资讯专栏INFORMATION COLUMN

ES6系列---解构

baoxl / 1228人阅读

摘要:的解构特性,可以简化这项工作。必须传值的解构参数如果调用函数时不提供被解构的参数会导致程序抛出错误程序报错缺失的第三个参数,其值为。

在编码过程中,我们经常定义许多对象和数组,然后有组织地从中提取相关的信息片段。ES6的解构特性,可以简化这项工作。解构是一种打破数据结构,将其拆分为更小部分的过程。

未使用解构的做法
let options = {
    repeat: true,
    save: false
};

// 从对象中提取数据
let repeat = options.repeat;
    save = options.save;

这段代码从options对象提取了repeatsave的值并将其存储为同名局部变量。如果要提取的变量更多,甚至还包含嵌套结构,靠遍历会够呛。

解构

ES6解构的实现,实际上是利用了我们早已熟悉的对象和数字字面量的语法。

对象解构
let node = {
    type: "Identifier",
    name: "foo"
};

let { type, name } = node;

console.log(type);  // "Identifier"
console.log(name);  // "foo"

可见,只要在赋值操作的左边放置一个对象字面量就可以了。typename都是局部声明的变量,也是用来从options对象读取相应值的属性名称。

数组解构
let colors = [ "red", "green", "blue" ];
let [ firstColor, secondColor ] = colors;

console.log(firstColor);   // "red"
console.log(secondColor);  // "green"

使用的是数组字面量。我们从colors数组中解构出了"red"和"green"两个值,分别存储在变量firstColorsecondColor中。

数组解构模式中,也可以直接省略元素,只为感兴趣的元素提供变量:

let colors = [ "red", "green", "blue" ];
let [ , , thirdColor] = colors; // 不提供变量的,占位一下就可以

console.log(thirdColor);   // "blue"
解构赋值 对象解构赋值

我们也可以对已声明的变量使用解构赋值:

let node = {
    type: "Identifier",
    name: "foo"
},
type = "Literal",
name = 5;

// 使用解构语法为变量赋值,要用小括号扩住
({ type, name } = node);

console.log(type);  // "Identifier"
console.log(name);  // "foo"

JavaScript语法规定,代码块不允许出现在赋值语句左侧,因此添加小括号将块语句转化为一个表达式,从而实现解构赋值。

解构赋值常常用在给函数传参数值的时候:

let node = {
    type: "Identifier",
    name: "foo"
},
type = "Literal",
name = 5;

function outputInfo(value) {
    console.log(value === node);  // true
}

outputInfo({ type, name } = node);

console.log(type);  // "Identifier"
consolo.log(name);  // "foo"
数组解构赋值

数组解构也可以用于赋值上下文:

let colors = [ "red", "green", "blue"];
    firstColor = "black";
    secondColor = "purple";
    
[ firstColor, secondColor ] = colors;

console.log(firstColor);  // "red"
console.log(secondClor);  // "green"

数组解构赋值可以很方便地交换两个变量的值。
先看看ES5,我们交换两个变量的做法:

let a = 1,
    b = 2,
    tmp;
    
tmp = a;
a = b;
b = tmp;

console.log(a);  // 2
console.log(b);  // 1

使用数组解构赋值:

let a = 1,
    b = 2;

// 左侧是解构模式,右侧是为交换过程创建的临时数字字面量
[ a, b ] = [ b, a ];

console.log(a);  // 2
console.log(b);  // 1
解构赋默认值 对象解构赋默认值:
let node = {
    type: "Identifier",
    name: "foo"
};

let { type, name, value1, value2 = true } = node;

console.log(type);    // "Identifier"
console.log(name);    // "foo"
console.log(value1);  // undefined  在解构对象上没有对应的值
console.log(value2);  // true
数组解构赋默认值:
let colors = [ "red" ];

let [ firstColor, secondColor, thirdColor = "blue"] = colors;

console.log(firstColor);   // "red"
console.log(secondColor);  // undefined
console.log(thirdColor);   // "blue"
为非同名变量赋值
let node = {
    type: "Identifier",
    name: "foo"
};

let { type: localType, name: localName = "bar" } = node;

console.log(localType);    // "Identifier"
console.log(localName );    // "bar"

type: localType语法的含义是读取名为type的属性并将其值存储在变量localType中。

嵌套解构 对象嵌套解构:
let node = {
    type: "Identifier",
    name: "foo",
    loc: {
        start: {
            line: 1,
            colomn: 1
        },
        end: {
            line: 1,
            column: 4
        }
    }
};

let { loc: { start }} = node;

console.log(start.line);     // 1
console.log(start.column);   // 1

上面的解构示例中,冒号前的标识符代表在对象中的检索位置,其右侧为被赋值的变量名;如果冒号后面是花括号,则意味着要赋予的最终值嵌套在对象内部更深的层级中。

也可以使用与对象名不同的局部变量:

...

let { loc: { start: localStart }} = node;
console.log(localStart.line);     // 1
console.log(localStart.column);   // 1
数组嵌套解构
let colors = [ "red", [ "green", "lightgreen" ], "blue" ];

let [ firstColor, [ secondColor ] ] = colors;

console.log(firstColor);   // "red"
console.log(secondClor);   // "green"
不定元素

ES6的函数引入了不定参数,而在数组解构语法中有个相似的概念:不定元素。
在数组中,可以通过...语法将数组中剩余的元素赋值给一个指定的变量:

let colors = [ "red", "green", "blue" ];

let [ firstColor, ...restColors ] = colors;

console.log(firstColor);          // "red"
console.log(restColors.length);   // 2
console.log(restColors[0]);       // "green"
console.log(restColors[1]);       // "blue"

通过不定元素来实现数组克隆:

// 在ES5中克隆数组
var colors = [ "red", "green", "blue" ];
// concat()方法的设计初衷是连接两个数组,不传参数会返回当前数组的副本
var clonedColors = colors.concat();

console.log(clonedColors);   // "[red,green,blue]"


// ES6通过不定元素来实现相同功能
let colors = [ "red", "green", "blue" ];
let [ ...clonedColors ] = colors;

console.log(clonedColors);   // "[red,green,blue]"

不定元素必须为最后一个条目,在后面继续添加逗号会导致程序抛出语法错误。

对象和数组混合解构
let node = {
    type: "Identifier",
    name: "foo",
    loc: {
        start: {
            line: 1,
            colomn: 1
        },
        end: {
            line: 1,
            column: 4
        }
    },
    range: [ 0, 3 ]
};

let { 
    loc: { start },
    range: [ startIndex ]
} = node;

console.log(start.line);     // 1
console.log(start.column);   // 1
console.log(startIndex);     // 0

这种方法极为有效,尤其是当你从JSON配置中提取信息时,不再需要遍历整个结构了。
请记住,解构模式中loc:和range:仅代表它们在node对象中所处的位置(也就是该对象的属性)。

解构参数

当定义一个接受大量可选参数的JavaScript函数时,我们通常会创建一个可选对象:

// options的属性表示其他参数
function setCookie(name, value, options) {
    options = options || {};
    
    let secure = options.secure,
        path = options.path,
        domain = options.domain,
        expires = options.expires;
        
    // 设置cookie的代码
}

// 第三个参数映射到options中
setCookie("type", "js", {
    secure: true,
    expires: 60000
});

许多JavaScript库中都有类似的setCookie()函数,而在示例函数中,namevalue是必需参数,而securepathdomainexpires则不然,这些参数相对而言没有优先级顺序,将它们列为额外的命名参数也不合适,此时为options对象设置同名的命名属性是一个很好的选择。现在的问题是,仅查看函数的声明部分,无法辨别函数的预期参数,必须通过阅读函数体才可以确定所有参数的情况。

如果将options定义为解构参数,则可以更清晰地了解函数预期传入的参数:

function setCookie(name, value, { secure, path, domain, expires }) {
    // 设置cookie的代码
}

setCookie("type", "js", {
    secure: true,
    expires: 60000
});

对于调用setCookie()函数的使用者而言,解构参数变得更清晰了。

必须传值的解构参数

如果调用函数时不提供被解构的参数会导致程序抛出错误:

// 程序报错
setCookie("type", "js");

缺失的第三个参数,其值为undefined。而解构参数只是将解构声明应用在函数参数的一个简写方法,会导致程序抛出错误。当调用setCookie()函数时,JavaScript引擎实际上做了下面的事情:

function setCookie(name, value, options) {
    let { secure, path, domain, expires } = options;
    // 设置cookie的代码
}

如果解构赋值表达式右值为nullundefined,则程序会报错。因此若调用setCookie()函数时不传入第3个参数,程序会报错。

如果解构参数是必需的,大可忽略掉这个问题;但如果希望将解构参数定义为可选的,那就必须为其提供默认值来解决这个问题:

function setCookie(name, value, { secure, path, domain, expires } = {}) {
    // ...
}

示例中为解构参数添加一个新的对象作为默认值,securepathdomainexpires这些变量的值全部为undefined,这样即使在调用setCookie()时未传递第3个参数,程序也不会报错。

解构参数的默认值

当然,我们也可以直接为解构参数指定默认值,就像在解构赋值语句中做的那样:

function setCookie(name, value, 
    {
      secure = false,
      path = "/",
      domain = "example.com",
      expires = new Date(Date.now() + 360000000)
    }
) {
    // ...
}

这种方法也有缺点:首先,函数声明变得比以前复杂了其次,如果解构参数是可选的,那么仍然要给它添加一个空对象作为参数,否则像setCookie("type", "js")这样的调用会导致程序抛错。建议对于对象类型的解构参数,为其赋予相同解构的默认参数:

function setCookie(name, value, 
    {
        secure = false,
        path = "/",
        domain = "example.com",
        expires = new Date(Date.now() + 360000000)
    } = {
        secure = false,
        path = "/",
        domain = "example.com",
        expires = new Date(Date.now() + 360000000)
    }
) {
    // ...
}

现在函数变得完整了,第一个对象字面量是解构参数,第二个为默认值。但这会造成非常多的代码冗余,我们可以将默认值提取到一个独立对象中,从而消除这些冗余:

const setCookieDefaults = {
    secure = false,
    path = "/",
    domain = "example.com",
    expires = new Date(Date.now() + 360000000)
};

function setCookie(name, value, 
    {
        secure = setCookieDefaults.secure,
        path = setCookieDefaults.path,
        domain = setCookieDefaults.domain,
        expires = setCookieDefaults.expires
    } = setCookieDefaults 
) {
    // ...
}

使用解构参数后,不得不面对处理默认参数的复杂逻辑,但它也有好的一面,如果改变默认值,可以立即在setCookieDefaults中修改,改变的数据将自动同步到所有出现过的地方。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/84800.html

相关文章

  • ES6系列文章 Destructuring

    摘要:解构是很重要的一个部分。解构代码如下上面的代码表示声明两个变量然后。实际业务中长方形的是不能没有值的。都算正常值的范畴。解构进阶解构时同时使用重命名和设置默认值的语法。若有,若没有属性,那么将赋值为。 Destructuring解构是ES6很重要的一个部分。和箭头函数、let、const 同等地位,解构可能是你日常用到最多的语法之一了。解构是什么意思呢?它是js 表达式,允许我们从数组...

    JiaXinYi 评论0 收藏0
  • ES6入门之变量的解构赋值

    摘要:数组的解构赋值基本用法允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为结构。如下以上都会报错但是如果左边为数组,右边为字符串,将会取字符串的第一个下标的值对于结构,同样可以使用数组的解构赋值。 showImg(https://segmentfault.com/img/remote/1460000018826068); 数组的解构赋值 基本用法 ES6 允许按照一定模式...

    gityuan 评论0 收藏0
  • ES6学习(二)之解构赋值及其原理

    摘要:基本原理解构是提供的语法糖,其实内在是针对可迭代对象的接口,通过遍历器按顺序获取对应的值进行赋值。属性值返回一个对象的无参函数,被返回对象符合迭代器协议。迭代器协议定义了标准的方式来产生一个有限或无限序列值。 更多系列文章请看 1、基本语法 1.1、数组 // 基础类型解构 let [a, b, c] = [1, 2, 3] console.log(a, b, c) // 1, 2, ...

    chunquedong 评论0 收藏0
  • 学习ES6 变量的解构赋值

    摘要:变量的解构赋值数组的解构赋值允许写成下面这样本质上,这种写法属于模式匹配,只要等号两边的模式相同,左边的变量就会被赋予对应的值。对象的解构赋值对象的解构与数组有一个重要的不同。由于和无法转为对象,所以对他们进行解构赋值,都会报错。 变量的解构赋值 数组的解构赋值 let a = 1; let b = 2; let c = 3; ES6允许写成下面这样 let [a,b,c] = [1,...

    sugarmo 评论0 收藏0
  • es6学习笔记-变量析构_v1.0_byKL

    摘要:学习笔记变量析构允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构。有一个属性用属性来获取字符串长度数值和布尔值的解构赋值解构赋值时,如果等号右边是数值和布尔值,则会先转为对象。 es6学习笔记-变量析构_v1.0 ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。 如果解构失败,变量的值等于undefine...

    Aldous 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<