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
的原型对象是obj2
。foo
属性不是obj1
自身的属性,而是继承自obj2
的属性,解构赋值可以取到这个属性。
2.2.8 由于数组本质是特殊的对象,因此可以对数组进行对象属性的解构。
let arr = [1,2,4]
let { 0:first, [arr.length - 1]: last } = arr
// arr[0] arr[length - 1]
3. 字符串的解构赋值
字符串也可以解构赋值。这是因为此时,字符串被转换成了一个类似数组的对象。
const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"
类似数组的对象都有一个length
属性,因此还可以对这个属性解构赋值,这点和4.一个意思,都是转为对象身上带的属性、方法。
let {length : len} = 'hello';
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. 函数参数的解构也可以使用默认值
-
js
-
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
指定默认值,所以会得到与前一种写法不同的结果。
// 应用
// 函数传参是对象时
// 如: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主模块引入
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 数据