1 解构:
从数组或对象中提取值,给变量赋值这被称为解构
解构赋值的变量都会重新声明
解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。由于 undefined 和 null 无法转为对象,所以对它们进行解构赋值,都会报错
关键词 模式匹配
、 解构不成功
、 不完全解构
、解构赋值允许指定默认值
- ES6 允许模式匹配
给变量值、set 结构用于数组结构赋值
、数组结构赋值
、对象结构赋值
、函数参数结构赋值
、圆括号的使用情况
、字符串结构赋值
-
-
模式匹配
: 等号两边模式相同,左边的变量就会被赋予对应的值。如果解构不成功
,变量就会被赋值 undefined(如下例子),不完全解构
依然是解构成功的情况(如下例)
不完全解构
:指等号左边的模式只能匹配一部分等号右边的数组
-
1.1 数组解构赋值
let [a, b, c] = [1, 2, 3]
a//1
b//2
c//3
let [foo, [[bar], baz]] = [1, [[2], 3]];
foo //1
bar // 2
baz // 3
let [ , , third] ["foo", "bar", "baz"]
third // 'bar'
let [x, , y] = [1, 2, 3];
x // 1
y // 3
let [head, ...tail] = [1, 2, 3, 4];
head // 1
tail // [2, 3, 4]
//===========解构不成功的例子/解构不成功的例子/解构不成功的例子/解构不成功的例子===================
let [x, y, ...z] = ['a'];
x // "a"
y // undefined
z // []
let [foo] = []
foo// undefined
let [bar, foo] = [1];
bar//1
foo // undefined
//==========================不完全解构的例子=====================================
let [x,y]=[1,2,3]
x//1
y//2
let [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 接口(最后一个表达式)
//
//但是 let {foo:3}={} 不会报错,因为使用了默认值
-
- 对于 Set 结构,也可以使用数组的解构赋值
let [x,y,z]=new set(['a','b','c'])
x//'a'
y//'b'
z//'c'
1.1.2默认值
解构函数允许指定默认值
ES6 使用严格模式(===
) 判读是否有值,需要严格等于 undefined ,如果一个数组中的数值不严格等于 undefined 默认值时不会生效的。
如果默认值是一个表达式,该表达式时惰性求值的,需要用到的时候才会求值
默认值可以引用解构赋值的其他变量,但前提时该被引用的变量必须提前声明
例如
let [foo=true]=[]
foo // true
let[x,y='b']=['a']
x // 'a'
y //'b'
let [foo='oo']=[undefined]
foo // ‘oo'
let [frr='oo']=[null]
foo// null 因为 null 不严格等于undefined
function f() {
console.log('aaa');
}
let [x = f()] = [1];
x // 1 这里的发f() 永远不会被调用,因为当默认值时表达式时时惰性求值,只用被需要的时候才会求值,
//而这里数值中的数值时1 因此默认值不起作用,f()永远不被需要
let [x = 1, y = x] = []; // x=1; y=1 y引用x 时,x 已经被提前声明 且x符合默认赋值
let [x = 1, y = x] = [2]; // x=2; y=2 y引用x 时,x 已经被提前声明 x 解构赋值 2,y 又引用的x
let [x = 1, y = x] = [1, 2]; // x=1; y=2
let [x = y, y = 1] = []; // ref 报错 x引用y y没有被提前声明,故报错
1.2 对象的解构赋值
- 数组解构赋值与对象解构赋值,不同。数组的元素是按照次序排列的,变量的取值由它的位置决定;而对象的属性没有顺序,变量的取值必须与属性同名,才能取到正确的值
注意点 -
- 什么是
匹配模式
,什么是真正的变量
对象解构赋值的内部机制
,先找到同名属性,在赋值给对应变量,真正赋值的是变量而不是匹配模式
- 什么是
-
- ,变量的声明和赋值是一体的。对于
let
和const
来说,变量不能重新声明,所以一旦赋值的变量以前声
明过,就会报错 不过,因为var
命令允许重新声明
- ,变量的声明和赋值是一体的。对于
let { bar, foo } = { foo: "aaa", bar: "bbb"}
foo // "aaa"
bar // "bbb"
// 上面那个例子相当于
let { foo: foo, bar: bar } = { foo: "aaa", bar: "bbb" };
let { baz } = { foo: "aaa", bar: "bbb" };
baz // undefined
//变量名与属性名不一样式要写成这样
var { foo: baz } = { foo: 'aaa', bar: 'bbb' };
baz // "aaa"
let obj = { first: 'hello', last: 'world' };
let { first: f, last: l } = obj;
f // 'hello'
l // 'world
let {foo} = {foo: 1}; // SyntaxError: Duplicate declaration "foo"
let baz;
let {bar: baz} = {bar: 1}; // SyntaxError: Duplicate declaration "baz"
//下面这样写才行,这里的 ()不能省略 因为解析器会将起首的大括号,理解成一个代码块,而不是
赋值语句
let foo;
({foo} = {foo: 1}); // 成功
let baz;
({bar: baz} = {bar: 1}); // 成功
-
- 和数组一样,解构也可以用于嵌套结构的对象
let obj = {
p: [
'Hello',
{ y: 'World' }
]
};
let { p: [x, { y }] } = obj;
x // "Hello"
y // "World"
//这时 p 是模式,不是变量,因此不会被赋值
loc: {
start: {
line: 1,
column: 5
}
}
};
var { loc: { start: { line }} } = node;
line // 1
loc // error: loc is undefined
start // error: start is undefined
//,只有 line 是变量, loc 和 start 都是模式,不会被赋值
let obj={ };
let arr=[ ];
({foo:obj.prop, bar:arr[0]})={foo:123,bar:true}
obj // {prop:123}
arr //[true]
-
- 对象的解构也可以指定默认值 :默认值生效的条件是,对象的属性值严格等于 undefined
var {x = 3} = {};
x // 3
var {x, y = 5} = {x: 1};
x // 1
y // 5
var {x:y = 3} = {};
y // 3
var {x:y = 3} = {x: 5};
y // 5
var { message: msg = 'Something went wrong' } = {};
msg // "Something went wrong
var {x = 3} = {x: undefined};
x // 3
var {x = 3} = {x: null};
x // null
-
- 如果解构模式式嵌套的对象,而子对象所在的父对象属性不存在,那么将会报错
// 报错
let {foo: {bar}} = {baz: 'baz'};
-
- 如果将一个已经声明的变量用于解构赋值时,必须非常小心 ,必须* 用 () 将器括起来*
let x;
{x} = {x: 1};// 会报错,因为将首起为{ 的解析成代码块
// 正确的写法
({x} = {x: 1});
-
-
- 解构赋值允许,等号左边的模式之中,不放置任何变量名。因此,可以写出非常古怪的赋值表达式
-
({}={foo:true,bar:'ooo'})
({} = [true, false]);
({} = 'abc');
({} = []);
-
- 对象的解构赋值,可以很方便的将现有对象的方法赋值给莫变量
let{sin,cos,log}=Math
-
- 数组时特殊的对象,因此可以将数组进行对象属性的解构
let arr = [1, 2, 3];
let {0 : first, [arr.length - 1] : last} = arr;
first // 1
last // 3
1.3. 字符串的解构赋值
-
- 类似数组的对象都有一个 length 属性,因此还可以对这个属性解构赋值
let {length : len} = 'hello';
len // 5
1.4函数参数的解构赋值
function add([x, y]){
return x + y;
}add([1, 2]); // 3
[[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];
}
// 解构赋值的默认值通常是放在等号左边的,这个实际上是没有默认值的,而是解构赋值,其实际上这个函数参数是解构赋值的,可以看做 function move({x: 0, y: 0 }) {
return [x, y];
}
move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, undefined] // 这里y 就没有定义
1.5 圆括号的使用情况
- 不能再下面三种情况下使用
-
- 1 赋值语句中,不能将整个模式或嵌套模式中的一层放在圆括号中
-
- 2 变量声明语句中不能带有圆括号
-
- 3 函数参数中,模式不能带有圆括号
如下例都不对
- 3 函数参数中,模式不能带有圆括号
//一下全部报错
({ p: a }) = { p: 42 }; // 报错,原因在赋值语句中共将整个模式放在圆括号中
([a]) = [5]; // 报错,原因在赋值语句中共将整个模式放在圆括号中
[({ p: a }), { x: c }] = [{}, {}]; //赋值语句中,不能将嵌套模式中的一层放在圆括号中
function f([(z)]) { return z; } // 报错原因 函数参数也属于变量声明,变量声明语句中不能带有圆括号
let [(a)] = [1]; // 变量声明语句中不能带有圆括号
let {x: (c)} = {};// 变量声明语句中不能带有圆括号
let ({x: c}) = {};// 变量声明语句中不能带有圆括号
let {(x: c)} = {};// 变量声明语句中不能带有圆括号
let {(x): c} = {};// 变量声明语句中不能带有圆括号
let { o: ({ p: p }) } = { o: { p: 2 } }; // 变量声明语句中不能带有圆括号
- 只有一种情况可以使用圆括号
赋值语句的非模式部分可以使用圆括号
注意下面例子之所以对,是因为同时没有没有变量声明
[(b)] = [3]; // 正确
({ p: (d) } = {}); // 正确, 注意这里必须用,这里如果不用圆括号,js 会将首期的{}解析成代码块
[(parseInt.prop)] = [3]; // 正确
1.6 结构赋值的用途
- 变量交换
- 函数返回多个值,取值的时候比较方便
- 函数参数定义时,可以方便的把一组参数与变量名对应起来
// 参数是一组有次序的值
function f([x, y, z]) { ... }
f([1, 2, 3]);
// 参数是一组无次序的值
function f({x, y, z}) { ... }
f({z: 3, y: 2, x: 1});
- 提取JSON数据
- 函数参数的默认值================zanshibu能体会
- 遍历Map结构
- 输入模块的指定方法
2 set 解构 、Map结构
例如:
new set(['a','b','c'])
var map = new Map();
map结构
原生支持 iterator 接口 配合变量的结构赋值,获取 键名、键值 非常方便
var map=new Map()
map.set('first','hello')
map.set('seconed','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) {
// ...
}
3 Iterator 接口
定义:为各种数据结构
提供统一的访问机制,任何数据只要部署了iterator接口,就可以完成遍历操作
任何部署了 iterator 接口的对象,都可以用 for...of 循环遍历