ES6之解构赋值

1. es6的对象字面量的增强写法

1.1 属性的简写 property shorthand
  • 对象的属性名和作为属性值引用的变量名相同,可省略属性名?
  • 例:
var username = 'ouo'
var age = 18
var obj = {
	username:username,
	age:age
}
// 等价于
var obj = {
	username,
	age
}
1.2 方法的简写 method shorthand
  • 注意和箭头函数无关
  • 例:
foo:function() {
}
// 等价于
foo() {
}
1.3 计算属性名 computed property name
// es5:
var username = 'ouo'
var obj = {
	username,
	foo() {},
}
obj[username + 123] = 'hahaha'
// es6:
var username = 'ouo'
var obj = {
	username,
	foo() {},
	// 直接在对象里可以用中括号
	[username + 123]:'hahaha'
}

2. 解构赋值

2.1 数组的解构
2.1.1 基本使用

数组是按顺序赋值

const arr = ['abc', 'bcd', 'aaa'];
// let item1 = arr[0];
// let item2 = arr[1];
// let item3 = arr[2];

// 等价于

let [item1, item2, item3] = arr;
2.1.2 忽略部分元素,解构后面的元素
const arr = ['abc', 'bcd', 'aaa'];

let [, itemb, itemc] = arr;
let [itemm, , itemcc] = arr;

console.log(itemb, itemc); // bcd aaa
console.log(itemm, itemcc, 'flag'); // abc aaa flag
2.1.3 嵌套数组进行解构

解构出一个元素,后面的元素放到一个新数组中

  • 此处…newArr是剩余属性,类似于函数的剩余参数…args,而不是扩展运算符
  • 注意:剩余属性必须是模式中的最后一个,并且不能有尾随逗号。
const arr = ['abc', 'bcd', 'aaa'];

let [itema, ...newArr] = arr;
console.log(itema, newArr); // abc [ 'bcd', 'aaa' ]

let [x, y, ...z] = ['a'];

console.log(x); // "a"
console.log(y); // undefined
console.log(z); // []
2.1.4 解构的默认值
  • 解构比源更多的元素,多出来的元素的值为undefined,注意区分2.2.6和不完全解构
  • 可以设置默认值,类似于给函数参数设置默认值,当属性不存在或值为 undefined (总结为严格等于undefined,因为不存在的变量的默认值也是undefined)时,将使用默认值;如果属性的值为 null,则不使用。
const arr = ['abc', 'bcd', 'aaa'];

let [item4, item5, item6, item7] = arr;
console.log(item4, item5, item6, item7); // abc bcd aaa undefined

let [item4, item5, item6, item7 = '123'] = arr;
console.log(item4, item5, item6, item7); 
// ['abc', 'bcd', 'aaa'] 或 ['abc', 'bcd', 'aaa' , undefined] 打印值都为 abc bcd aaa 123
// arr为['abc', 'bcd', 'aaa', null]时,打印为 abc bcd aaa null
  • 默认值为函数:
function f() {
  console.log('aaa');
}
let [x = f()] = [1];
let x;

// 等价于
// [1][0]是指数组[1]的下标为0的元素

if ([1][0] === undefined) {
  x = f();
} else {
  x = [1][0];
}
  • 默认值可以引用解构赋值的其他变量,但该变量必须已经声明。
let [x = 1, y = x] = [];     // x=1; y=1
let [x = 1, y = x] = [2];    // x=2; y=2
let [x = 1, y = x] = [1, 2]; // x=1; y=2
let [x = y, y = 1] = [];     // ReferenceError: y is not defined
2.1.5 数组解构error

如果等号的右边不是数组(或者严格地说,不是可遍历的结构,参见《Iterator》一章),那么将会报错。
待展开…

1.  `// 报错`
2.  `let [foo] = 1;`
3.  `let [foo] = false;`
4.  `let [foo] = NaN;`
5.  `let [foo] = undefined;`
6.  `let [foo] = null;`
7.  `let [foo] = {};`

因为等号右边的值,要么转为对象以后不具备 Iterator 接口(前五个表达式),要么本身就不具备 Iterator 接口(最后一个表达式)。

2.2 对象的解构赋值

对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。

2.2.1 基本使用
var obj = {
	name:'why',
	age:18,
	height:1.88
}

var { name,age,height } = obj
2.2.2 省略部分key 不需要“,”,直接写某个需要的属性名即可

省略部分key 不需要“,”直接写某个需要的属性名即可

var obj = {
  username: 'why',
  age: 18,
  height: 1.88,
};

// 省略部分key 不需要“,”直接写某个需要的属性名即可
var { age, username } = obj;
console.log(username, age); // why 118
2.2.3 对象解构的默认值
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 {x = 3} = {x: null};`
-   `x // null`
2.2.4 取别名
var obj = {
  username: 'why',
  age: 18,
  height: 1.88,
};
// 取别名,前面的是匹配的模式,后面的才是真正被赋值的变量;
// 也就是说,对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。**真正被赋值的是后者**,而不是前者。
var { username: otherName } = obj;
console.log(otherName, 'flag', username); // ReferenceError: username is not defined

// 其实对象的解构赋值是简写
var { username: username } = obj;
2.2.5 解构嵌套结构的对象(数组)
const obj = {
	a:[
		3,
		{
			b:'why'
		}
	]
}
// {} [] x,{} b
let { a: [x ,{ b }] } = obj // a是模式,并没有被赋值
console.log(x,y) // 3 why

let { a, a: [x ,{ b }]} = obj // a这样才会被赋值 
console.log(a) // [3,{b:'why'}]
2.2.6 报错
  • 情况1
// 报错
let {foo: {bar}} = {baz: 'baz'};

上面代码中,等号左边对象的foo属性,对应一个子对象,foo是模式,右边的{bar}是真正被赋值的变量。
原因很简单,因为foo这时没有匹配上,{bar}等于undefined,再取子属性就会报错。

  • 情况2
    将一个已经声明的变量用于解构赋值
1.  `// 错误的写法`
2.  `let x;`
3.  `{x} = {x: 1};`
4.  `// SyntaxError: syntax error`
// 对于编译器来说,一个式子到底是模式,还是表达式,没有办法从一开始就知道,必须解析到(或解析不到)等号才能知道。
// 上面代码的写法会报错,因为 JavaScript 引擎会将`{x}`理解成一个代码块,从而发生语法错误。只有不将大括号写在行首,避免 JavaScript 将其解释为代码块,才能解决这个问题,类似于立即执行函数,{}内的会被解析为代码块,整个执行。

1.  `// 正确的写法`
2.  `let x;`
3.  `({x} = {x: 1});` // 赋值部分使用圆括号

圆括号

2.2.7 对象的解构赋值可以取到继承的属性

Object.setPrototypeOf() 方法设置一个指定的对象的原型(即,内部 [[Prototype]] 属性)到另一个对象或 null,相当于继承。

const obj1 = {};
const obj2 = { foo: 'bar' };
Object.setPrototypeOf(obj1, obj2);

const { foo } = obj1;
foo // "bar"

上面代码中,对象obj1的原型对象是obj2foo属性不是obj1自身的属性,而是继承自obj2的属性,解构赋值可以取到这个属性。

2.2.8 由于数组本质是特殊的对象,因此可以对数组进行对象属性的解构。
let arr = [1,2,4]
let { 0:first, [arr.length - 1]: last } = arr

// arr[0] arr[length - 1]
3. 字符串的解构赋值

字符串也可以解构赋值。这是因为此时,字符串被转换成了一个类似数组的对象。

  1. const [a, b, c, d, e] = 'hello';
  2. a // "h"
  3. b // "e"
  4. c // "l"
  5. d // "l"
  6. e // "o"

类似数组的对象都有一个length属性,因此还可以对这个属性解构赋值,这点和4.一个意思,都是转为对象身上带的属性、方法。

  1. let {length : len} = 'hello';
  2. len // 5
4. 数值和布尔值的解构赋值

解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象,如果转换不了则会解报错。
何为包装对象:字符串、数字、布尔值这三种原始类型的值在一定情况下会自动转为对象(分别对应String、Number、Boolean)。

// true这个布尔值首先被转为对象,toString是属性,s是被赋值的变量

let { toString: s } = true;
// Boolean.prototype.toString
console.log(s); // true被包装成对象,而对象沿着原型链总能查询到哦、toString方法

let { toString: s } = 123;
// Number.prototype.toString
console.log(s); // true被包装成对象,而对象沿着原型链总能查询到哦、toString方法

// 由于undefined和null无法转为对象,所以对它们进行解构赋值,都会报错
// TypeError
5. 函数参数的解构也可以使用默认值
  1. js

  2. function move({x = 0, y = 0} = {}) {`

  3. return [x, y];

  4. }

  5. move({x: 3, y: 8}); // [3, 8]

  6. move({x: 3}); // [3, 0]

  7. move({}); // [0, 0]

  8. move(); // [0, 0]

上面代码中,函数move的参数是一个对象,通过对这个对象进行解构,得到变量xy的值。如果解构失败,xy等于默认值。

注意,下面的写法会得到不一样的结果。

  1. function move({x, y} = { x: 0, y: 0 }) {
  2. return [x, y];
  3. }
  4. move({x: 3, y: 8}); // [3, 8]
  5. move({x: 3}); // [3, undefined]
  6. move({}); // [undefined, undefined]
  7. move(); // [0, 0]

上面代码是**为函数move的参数指定默认值,而不是为变量xy指定默认值,所以会得到与前一种写法不同的结果。

// 应用
// 函数传参是对象时
// 如:vuex中的 { commit }

应用
  • 用解构赋值交换变量(不再需要临时变量)
let a = 1;
let b = 2;
[a, b] = [b, a];
console.log(a, b); // 2 1
  • 函数的参数/默认值结合
[[1, 2], [3, 4]].map(([a, b]) => a + b);
// [ 3, 7 ]
  • 从函数返回多个值
// 返回一个数组
function example() {
  return [1, 2, 3];
}
let [a, b, c] = example();

// 返回一个对象

function example() {
  return {
    foo: 1,
    bar: 2
  };
}
let { foo, bar } = example();
  • 解构赋值对象身上的部分属性给一个新对象
let param = {};
let userInfo = {
  obj: {
    unitId: 18,
    id: 20,
    userId: 9,
    nickName: 'why',
  },
};

// 因为只要对象身上的部分属性,先解构赋值对象,记得写默认值
let { unitId, userId, id } = userInfo.obj || {};

// 对象字面量的省略写法,省略属性名
param = { unitId, userId, id };
console.log(param, unitId, userId, id);
  • 模块化传送门
    // CommonJS主模块引入
  1. const { SourceMapConsumer, SourceNode } = require("source-map");
    // es6针对统一暴露和分别暴露,默认暴露不是必须使用解构传送门
// 统一
function fun1() {
    console.log('fun1() module2')
}
function fun2() {
    console.log('fun2() module2')
}
// 统一暴露: 暴露的是一个对象,引入时也必须是个对象
export {foo,bar} 


// ================

// 分别暴露:也叫多行暴露
export function foo() {
    console.log('foo() moudle1');
}
export function bar() {
    console.log('bar() moudle1')
}

// 主模块

import {foo,bar} from '.js/src/module1.js'
import {fun1,fun2} from './js/src/module2.js'
  • vuex的commit
    Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象
    context对象身上的commit方法
actions: {
   // 接收对象为参数,对象身上有commit方法
   increment ({ commit }) {
   	commit('increment')
   }
}
  • 遍历Map
    Map in MDN
    任何部署了 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) {
  // ...
}

待展开…

  • 提取 JSON 数据
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值