前言
该章为个人ES6解构赋值知识点笔记,内容上参考了阮大的ES6入门,主要讲述了ES6新增的解构赋值功能,记录了解构在不同数据类型中的使用和其一般的使用场景
数组的解构赋值
基本用法
//ES5中的代码
const arr = [1,2,3];
const a = arr[0];
const b = arr[1];
const c = arr[2];
//ES6解构赋值
let [A,B,C] = [1,2,3];
console.log(A);//1
console.log(B);//2
console.log(C);//3
上述代码,可以从数组中直接按照对应位置进行提取值,然后对变量进行赋值
本质上,这种写法属于"模式匹配",等号两边模式相同,左边变量就会被赋予右边对应的值
数组解构实例
//完全解构
let [a,[[b],[c]]] = [1,[[2],3]];
a//1
b//2
c//3
//存在空值解构
let [ , ,c] = [1,2,3];
c//3
let [x, ,y] = [1,2,3];
x//1
y//3
//拓展运算解构
let [i,...j] = [1,2,3,4];
i//1
j//[2,3,4]
//不完全解构
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 [x,y,...z] = ["a"];
x//"a"
y//undefined 如果一但解构不成功那么就会直接赋值undefined
z//[]
哪些数据不能被解构
等号右边不是可遍历的解构,解构时就会报错,通常来讲就是等号右边的值转换为对象后不具备Iterator接口或者本身就不具备Iterator接口
//转化为对象不具备Iterator
let [a] = 1; //number类型
let [a] = false; //boolean类型
let [a] = NaN; //非数
let [a] = undefined; //undefined类型
let [a] = null; //类型
//本身不具备Iterator接口
let [a] = {}
默认值
解构赋值允许使用默认值,但是需要有几点注意的地方,接下来举例说明
- ES6内部使用严格相等运算===,只有在对应解构的值严格等于undefined时才会使用默认值
let [a==true] = [];
a//true
let [a,b=2] = [1];
a//1
b//2
let [a,b=2] = [1,undefined];
a//1
b//2
let [a,b=2] = [1,null];
a//1
b//null b对应解构的值必须严格等于 undefined
- 如果默认值是一个表达式,那么这个表达式是惰性求值的,即只有用到时才会求值
function fn(){
console.log("此时我被使用了");
}
let [x=fn()] = [1];
上述函数fn不会被执行,因为x取到值了,实际上上述代码可以理解为
let x = [1][0] === undefined ? f() : [1][0];
- 默认值可以引用解构赋值的其他变量,但是该变量必须已经声明
let [x=1,y=x] = []
x//1
y//1
let [x=y,y=1] = []
//报错此时y还没有被声明
对象的解构赋值
对象的解构赋值和数组不同的地方是,数字组是按次序排列结构的,但是对象是必须和属性同名才可以取到正确的值,以下举几处实例,展示对象解构的注意点
- 按属性名称不按顺序解构
let {bar,foo} = {foo:"a",bar:"b"};
bar//b
foo//a
- 当没有属性名对应时解构失败 为undefined
let {foo} = {bar:"baz"};
foo//undefined
- 对象解构复制可以很方便将现有的对象方法,赋值到某个变量
const {log} = console;
log("hello")//hello
- 解构赋值的简写和重命名
//之前的对象解构方法是一种简写方式,实际上的解构赋值完整写法
let {foo:foo} = {foo:1};
foo//1
//重命名
let {foo:a} = {foo:1};
a//1
以上要注意 foo 是被寻找的同名属性 a 才是真正被赋值的,也就是说对象解构时 : 左边的是匹配模式右边才是赋值变量
5. 对象解构嵌套
let obj = {};
let arr = [];
({foo:obj.prop,bar:arr[0]} = {foo:123,bar:true});
obj//{prop:123}
arr//[true]
- 解构报错
let {foo:{bar}} = {baz:"baz"};
//报错 foo解构到时undefined undefined.bar 就会报错
- 可解构继承属性
const obj1 = {};
const obj2 = {foo:"bar"};
Object.setPrototypeOf(obj1,obj2);
const {foo} = obj1;
foo//"bar"
默认值
对象解构的默认值规则和数组一样,但是有几点需要注意,以下举例说明
- 如果将已经声明的变量用于解构赋值,需要用括号包裹
let x;
{x} = {x:1}
//直接书写时 JS引擎会将{x}解释为代码块,从而发生语法错误
//需要改为以下表达式的写法
({x} = {x:1})//改为表达式就不会报错
- 解构赋值允许等号左边的模式中不放任何变量名,因此可以写出以下无意义但是不报错的表达式
({} = {age:1})
- JS中数据也是特殊对象,因此可以对数组进行对象属性的解构
let {0:frist,[arr.length - 1] : last} = [1,2,3] ;
first//1
last//3
字符串的解构赋值
字符串解构相对简单,有两种不同的方式,举例说明
- 字符串被转换为类似数组的对象,按对应位置进行赋值
const [a,b,c] = "hello";
a//"h"
b//"e"
c//"l"
- length属性解构
let {length:len} = "hello"
len//5
数值和布尔值的解构赋值
如果是 数值和布尔值的解构,会先转为对象
let {toString:s} = 123;
s === Number.prototype.toString//true
值得注意的是,只要等号右边的值不是对象或者数组,将其先转为对象然后解构,但是有两个特殊情况,undefined和null无法转化为对象,因此解构时会报错
函数参数的解构赋值
函数的参数也可以进行解构
function add([x,y]){
return x+y ;
}
上述代码中,函数的实参是一个数组,但是形参会解构实参的数组,对于函数内部来说参数就是x,y,但是需要注意一但使用函数参数解构,就要注意参数传入,一但类型不对,极容易报错,需要谨慎使用
function add([x,y]){
return x+y ;
}
add(1)//报错 TypeError: undefined is not a function
参数解构的默认值
function move({x = 0,y = 0} = {}){
return [x,y];
}
move({x:3,y:8});//[3,8]
move({x:3});//[3,0]
圆括号问题
emmmm,出现可能性较小,直接举例简单说明,一下情况注意不能使用圆括号
- 变量声明语句
let [(a)] = [1];
let {x:(c)} = {};
- 函数参数
function fn([(z)]){
return z
}
- 赋值语句的模式
({p:a}) = {p:1};
可以使用圆括号的情况:
只有一种: 赋值语句非模式部分
[(b)] = [3]; //正确
用法
解构赋值的用途很多,使用得当将极大的方便前端开发,以下举例使用解构赋值的几种场景
变量交换
let a = 1;
let b = 2;
[b,a] = [a,b];
从函数内解构返回多个值
函数只能返回一个值,如果要返回多个值,那么只能返回一个对象或者数组,如果使用解构就非常方便
function fn (){
return {
foo:1,
bar:2
}
}
let {foo,bar} = fn()
函数参数的定义
我们知道JS函数参数在传入的时候,不会按照名称传入,而是按照顺序传入,使用解构就能很好的实现对应参数的传入
function fn({x,y,z}){...}
fn({z:3,x:1,y:2});
JSON提取数据
let jsonData = {
id:1,
status:"OK",
data:[11,22]
};
let {id,status,data:numbers} = jsonData;
id//1
numbers//[11,22]
函数参数默认值
$.ajax = function(url,{
async:true,
beforeSend:function(){},
//...more config
}={}){
//...
}
通过解构和默认值的方式,避免了在函数体内部如果配置参数不全再写兼容语句,如 var foo = config.foo||"default foo"
遍历map结构
任何部署了Iterator接口的对象,都可以用for...of循环遍历,因此for...of配合解构,对map进行遍历能很好的获取键值
const map = new Map();
map.set("frist","hello");
map.set("second","world");
for(let[key,value] of map){
//内部获取键值
console.log(`${key} is ${value}`)
}
模块引入
当我们在引入模块时,想要指定引入某些特定方法时,使用解构会非常清晰
//假设我们有一个模块fns,我们想引入其中的fn1方法和fn2方法
const {fn1 , fn2} = require("fns");
结语
不积跬步,无至千里,相信每日细小的积累,终会在日后有所爆发,学无止境与君共勉.