做软件代理去哪个网站,公司注册地址和经营地址不一致,微信小程序游戏制作平台,做网站的文章变量解构赋值 数组解构赋值1 基操2 默认值 对象的解构赋值默认值注意 字符串的解构赋值数值与布尔值的解构赋值函数参数的解构赋值圆括号不得使用 作用 数组解构赋值
1 基操
ES6允许按照一定的模式从数组和对象中提取值从而对变量进行赋值#xff0c;也即解构#xff08;De… 变量解构赋值 数组解构赋值1 基操2 默认值 对象的解构赋值默认值注意 字符串的解构赋值数值与布尔值的解构赋值函数参数的解构赋值圆括号不得使用 作用 数组解构赋值
1 基操
ES6允许按照一定的模式从数组和对象中提取值从而对变量进行赋值也即解构Destructuring 也即为变量赋值可以有下面的方法
let a 1;
let b 2;
let c 3;
// or
let [a, b, c] [1, 2, 3];按照对应位置从数组中提取值为变量赋值 此种写法的本质上是等号两边的模式匹配 下面是使用嵌套数组进行解构
let [foo, [[bar], baz]] [1, [[2], 3]];
foo // 1
bar // 2
baz // 3let [ , , third] [foo, bar, baz];
third // bazlet [x, , y] [1, 2, 3];
x // 1
y // 3let [head, ...tail] [1, 2, 3, 4];
head // 1
tail // [2, 3, 4]let [x, y, ...z] [a];
x // a
y // undefined
z // [] 解构不成功则变量的值等于undefined
let [foo] [];
let [bar, foo] [1];上面的两种情况属于结构失败 foo的值为undefined
还有就是不完全解构但是成功 等号左边的模式只匹配一部分的等号右边的数组
let [x, y] [1, 2, 3];
x // 1
y // 2let [a, [b], d] [1, [2, 3], 4];
a // 1
b // 2
d // 4如果等号的右边不是数组或者严格地说不是可遍历的结构则会报错
// 报错
let [foo] 1;
let [foo] false;
let [foo] NaN;
let [foo] undefined;
let [foo] null;
let [foo] {};上面的语句都会报错因为等号右边的值要么转为对象以后不具备 Iterator 接口前五个表达式要么本身就不具备 Iterator 接口最后一个表达式
对于 Set 结构也可以使用数组的解构赋值
let [x, y, z] new Set([a, b, c]);
x // a事实上只要某种数据结构具有 Iterator 接口都可以采用数组形式的解构赋值
function* fibs() {let a 0;let b 1;while (true) {yield a;[a, b] [b, a b];}
}let [first, second, third, fourth, fifth, sixth] fibs();
sixth // 5上面代码中fibs是一个 Generator 函数原生具有 Iterator 接口 解构赋值会依次从这个接口获取值
2 默认值
解构赋值允许指定默认值
let [foo true] [];
foo // truelet [x, y b] [a]; // xa, yb
let [x, y b] [a, undefined]; // xa, yb注意ES6 内部使用严格相等运算符判断一个位置是否有值 所以只有当一个数组成员严格等于undefined默认值才会生效
let [x 1] [undefined];
x // 1let [x 1] [null];
x // null上面代码中如果一个数组成员是null默认值就不会生效因为null不严格等于undefined 如果默认值是一个表达式那么这个表达式是惰性求值的即只有在用到的时候才会求值
function f() {console.log(aaa);
}let [x f()] [1];上面代码中因为x能取到值所以函数f根本不会执行 上面的代码其实等价于下面的代码
let x;
if ([1][0] undefined) {x f();
} else {x [1][0];
}默认值可以引用解构赋值的其他变量但该变量必须已经声明
let [x 1, y x] []; // x1; y1
let [x 1, y x] [2]; // x2; y2
let [x 1, y x] [1, 2]; // x1; y2
let [x y, y 1] []; // ReferenceError: y is not defined上面最后一个表达式之所以会报错是因为x用y做默认值时y还没有声明
对象的解构赋值
解构不仅可以用于数组还可以用于对象
let { foo, bar } { foo: aaa, bar: bbb };
foo // aaa
bar // bbb对象的解构与数组有一个重要的不同 数组的元素是按次序排列的变量的取值由它的位置决定 而对象的属性没有次序变量必须与属性同名才能取到正确的值
let { bar, foo } { foo: aaa, bar: bbb };
foo // aaa
bar // bbblet { baz } { foo: aaa, bar: bbb }
baz // undefined如果解构失败变量的值等于undefined
对象的解构赋值可以很方便地将现有对象的方法赋值到某个变量
// yi
let { log, sin, cos } Math;// er
const { log } console;
log(hello) // hello上面代码的例一将Math对象的对数、正弦、余弦三个方法赋值到对应的变量上使用起来就会方便很多 例二将console.log赋值到log变量
如果变量名与属性名不一致必须写成下面这样
let { foo: baz } { foo: aaa, bar: bbb };
baz // aaalet obj { first: hello, last: world };
let { first: f, last: l } obj;
f // hello
l // world这实际上说明对象的解构赋值是下面形式的简写
let { foo: foo, bar: bar } { foo: aaa, bar: bbb };也就是说对象的解构赋值的内部机制是先找到同名属性然后再赋给对应的变量 真正被赋值的是后者而不是前者
let { foo: baz } { foo: aaa, bar: bbb };
baz // aaa
foo // error: foo is not defined上面代码中foo是匹配的模式baz才是变量。真正被赋值的是变量baz而不是模式foo
与数组一样解构也可以用于嵌套结构的对象
let obj {p: [hello,{ y: World }]
};let { p: [x, { y }] } obj;
x // hello
y // World注意这时p是模式不是变量因此不会被赋值 如果p也要作为变量赋值可以写成下面这样
let obj {p: [Hello,{ y: World }]
};let { p, p: [x, { y }] } obj;
x // Hello
y // World
p // [Hello, {y: World}]const node {loc: {start: {line: 1,column: 5}}
};let { loc, loc: { start }, loc: { start: { line }} } node;
line // 1
loc // Object {start: Object}
start // Object {line: 1, column: 5}上面代码有三次解构赋值分别是对loc、start、line三个属性的解构赋值 注意最后一次对line属性的解构赋值之中只有line是变量loc和start都是模式不是变量
let obj {};
let arr [];({ foo: obj.prop, bar: arr[0] } { foo: 123, bar: true });obj // {prop:123}
arr // [true]注意对象的解构赋值可以取到继承的属性
const obj1 {};
const obj2 { foo: bar };
Object.setPrototypeOf(obj1, obj2);const { foo } obj1;
foo // bar上面代码中对象obj1的原型对象是obj2 foo属性不是obj1自身的属性而是继承自obj2的属性解构赋值可以取到这个属性
默认值
对象的解构也可以指定默认值
var {x 3} {};
x // 3var {x 3, y 5} {x: 1};
x // 1
y // 5var {x: y 4 } {};
y // 4var {x: y 3} {x: 5};
y // 5var { message: msg Something went wrong } {};
msg // Something went wrongvar {x 3} {x: undefined};
x // 3var {x 3} {x: null};
x // null默认值生效的条件是对象的属性值严格等于undefined 上面代码中属性x等于null因为null与undefined不严格相等所以是个有效的赋值导致默认值3不会生效
注意
1如果要将一个已经声明的变量用于解构赋值必须非常小心
// 错误的写法
let x;
{x} {x: 1};
// SyntaxError: syntax error// 正确的写法
let x;
({x} {x: 1});上面代码的写法会报错因为 JavaScript 引擎会将{x}理解成一个代码块从而发生语法错误 只有不将大括号写在行首避免 JavaScript 将其解释为代码块才能解决这个问题
2解构赋值允许等号左边的模式之中不放置任何变量名 因此可以写出非常古怪的赋值表达式
({} [true, false]);
({} abc);
({} []);上面的表达式虽然毫无意义但是语法是合法的可以执行
3由于数组本质是特殊的对象因此可以对数组进行对象属性的解构
let arr [1, 2, 3];
let {0 : first, [arr.length - 1] : last} arr;
first // 1
last // 3上面代码对数组进行对象解构 数组arr的0键对应的值是1[arr.length - 1]就是2键对应的值是3 方括号这种写法属于属性名表达式详见对象的扩展
字符串的解构赋值
字符串也可以解构赋值 类似数组的对象都有一个length属性因此还可以对这个属性解构赋值
const [a, b, c, d, e] hello;
a // h
b // e
c // l
d // l
e // olet {length : len} hello;
len // 5数值与布尔值的解构赋值
解构赋值时如果等号右边是数值和布尔值则会先转为对象
let {toString: s} 123;
s Number.prototype.toString // truelet {toString: s} true;
s Boolean.prototype.toString // truelet { prop: x } undefined; // TypeError
let { prop: y } null; // TypeError上面代码中数值和布尔值的包装对象都有toString属性因此变量s都能取到值 解构赋值的规则是只要等号右边的值不是对象或数组就先将其转为对象 由于undefined和null无法转为对象所以对它们进行解构赋值都会报错
函数参数的解构赋值
function add([x, y]){return x y;
}add([1, 2]); // 3上面代码中函数add的参数表面上是一个数组但在传入参数的那一刻数组参数就被解构成变量x和y 对于函数内部的代码来说它们能感受到的参数就是x和y
[[1, 2], [3, 4]].map(([a, b] a b);
// [3, 7]函数参数的解构也可以使用默认值
function move({x 0, y 0} {}) {return [x, y];
}move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, 0]
move({}); // [0, 0]
move(); // [0, 0]上面代码中函数move的参数是一个对象通过对这个对象进行解构得到变量x和y的值 如果解构失败x和y等于默认值
function move({x, y} { x: 0, y: 0 }) {return [x, y];
}move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, undefined]
move({}); // [undefined, undefined]
move(); // [0, 0]上面代码是为函数move的参数指定默认值而不是为变量x和y指定默认值所以会得到与前一种写法不同的结果
undefined就会触发函数参数的默认值
[1, undefined, 3].map((x yes) x);
// [ 1, yes, 3 ]圆括号
解构赋值虽然很方便但是解析起来并不容易 对于编译器来说一个式子到底是模式还是表达式没有办法从一开始就知道必须解析到或解析不到等号才能知道
由此带来的问题是如果模式中出现圆括号怎么处理 ES6 的规则是只要有可能导致解构的歧义就不得使用圆括号 因此建议只要有可能就不要在模式中放置圆括号
不得使用
变量声明语句
let [(a)] [1];let {x: (c)} {};
let {{x: c}) {};
let {(x: c)} {};
let {(x): c} {};let { o: ({ p: p }) } { o: { p: 2 } };上面 6 个语句都会报错因为它们都是变量声明语句模式不能使用圆括号
函数参数
function f([(z)]) { return z; }
function f([z, (x)]) { return x; }报错函数参数也属于变量声明因此不能带有圆括号
赋值语句模式
// 将整个模式放在圆括号之中导致报错
({ p: a }) { p: 42 };
([a]) [5];// 将一部分模式放在圆括号之中导致报错
[({ p: a }), { x: c }] [{}, {}];作用
变量的解构赋值作用很多
交换变量的值
let x 1;
let y 2;[x, y] [y, x];上面代码交换变量x和y的值这样的写法不仅简洁而且易读语义非常清晰
函数返回多个值
function example() {return [1, 2, 3];
}
let [a, b, c] example();function example() {return {foo: 1,bar: 2}
}
let {foo, bar} example();函数只能返回一个值如果要返回多个值只能将它们放在数组或对象里返回 有了解构赋值取出这些值就非常方便
函数参数的定义
// 参数是一组有次序的值
function f([x, y, z]) { ... }
f([1, 2, 3]);// 参数是一组无次序的值
function f({x, y, z}) { ... }
f({z: 3, y: 2, x: 1});解构赋值可以方便地将一组参数与变量名对应起来
提取JSON数据
let jsonData {id: 42,status: OK,data: [888, 9999]
};let { id, status, data: number } jsonData;console.log(id, status, number);
// 42 ‘OK’ [888, 9999]解构赋值对提取 JSON 对象中的数据尤其有用
函数参数的默认值
jQuery.ajax function (url, {async true,beforeSend function () {},cache true,complete - function () {},crossDomain false,global true,// ... more config
} {}) {// ... do stuff
};指定参数的默认值就避免了在函数体内部再写var foo config.foo || ‘default foo’;这样的语句
遍历Map结构 任何部署了 Iterator 接口的对象都可以用for…of循环遍历 Map 结构原生支持 Iterator 接口配合变量的解构赋值获取键名和键值就非常方便
const map new Map();
map.set(first, hello);
map.set(second, world);for (let [key, value] of map) {console.log(key is value);
}
// first is hello
// second is world// 如果只想获取键名或者只想获取键值可以写成下面这样
// 获取键名
for (let [key] of map) {// ...
}// 获取键值
for (let [,value] of map) {// ...
}输入模块的指定方 加载模块时往往需要指定输入哪些方法 解构赋值使得输入语句非常清晰
const { SourceMapConsumer, SourceNode } require(source-map);