includes()
、startsWith()
、endsWith()
。传统JavaScript只有indexOf()
方法用来肯定一个字符串是否包含在另外一个字符串中,ES6又提供了三个新方法。includes()
:返回布尔值,表示是否找到了参数字符串。startsWith()
:返回布尔值,表示参数字符串是否在原字符串的头部。endsWith()
:返回布尔值,表示参数字符串是否在原字符串的尾部。let s = 'Hello world!';
s.startsWith('Hello') // true
s.endsWith('!') // true
s.includes('o') // true
复制代码
这三个方法都支持第二个参数,表示开始搜索的位置。可是使用第二个参数n
时,endsWith
的行为与其余两个方法有所不一样。它针对前n
个字符,而其余两个方法针对从第n
个位置直到字符串结束。node
let s = 'Hello world!';
s.startsWith('world', 6) // true
s.endsWith('Hello', 5) // true
s.includes('Hello', 6) // false
复制代码
repeat
。repeat
方法返回一个新字符串,表示将原字符串重复n次。'x'.repeat(3) // "xxx"
'hello'.repeat(2) // "hellohello"
'na'.repeat(0) // ""
复制代码
repeat
的参数是负数或者Infinity
,会报错。-0
,repeat
视同为 0。NaN
等同于 0。repeat
的参数是字符串,则会先转换成数字。padStart()
、padEnd()
。ES2017 引入了字符串补全长度的功能。若是某个字符串不够指定长度,会在头部或尾部补全。padStart()
用于头部补全,padEnd()
用于尾部补全。'x'.padStart(5, 'ab') // 'ababx'
'x'.padStart(4, 'ab') // 'abax'
'x'.padEnd(5, 'ab') // 'xabab'
'x'.padEnd(4, 'ab') // 'xaba'
复制代码
${}
之中。toString
方法。var name = "追逐",trait = "帅气";
//es
var str = "我叫"+name+",人很是"+trait+",说话又好听";
//es6
var str2 = `我叫 ${name} ,人很是 ${trait} ,说话又好听`;
复制代码
alert`123`
// 等同于
alert(123)
复制代码
标签模板其实不是模板,而是函数调用的一种特殊形式。“标签”指的就是函数,紧跟在后面的模板字符串就是它的参数。若是模板字符里面有变量,就不是简单的调用了,而是会将模板字符串先处理成多个参数,再调用函数。es6
let a = 5;
let b = 10;
tag`Hello ${ a + b } world ${ a * b }`;
// 等同于
tag(['Hello ', ' world ', ''], 15, 50);
复制代码
Number.isFinite()
、Number.isNaN()
。ES6 在Number
对象上,新提供了Number.isFinite()
和Number.isNaN()
两个方法。Number.isFinite()
用来检查一个数值是否为有限的(finite)。Number.isFinite(15); // true
Number.isFinite(0.8); // true
Number.isFinite(NaN); // false
Number.isFinite(Infinity); // false
Number.isFinite(-Infinity); // false
Number.isFinite('foo'); // false
Number.isFinite('15'); // false
Number.isFinite(true); // false
复制代码
Number.isNaN()
用来检查一个值是否为NaN
。和全局函数 isNaN()
相比,该方法不会强制将参数转换成数字,只有在参数是真正的数字类型,且值为 NaN
的时候才会返回 true
。Number.isNaN(NaN); // true
Number.isNaN(Number.NaN); // true
Number.isNaN(0 / 0) // true
// 下面这几个若是使用全局的 isNaN() 时,会返回 true。
Number.isNaN("NaN"); // false,字符串 "NaN" 不会被隐式转换成数字 NaN。
Number.isNaN(undefined); // false
Number.isNaN({}); // false
Number.isNaN("blabla"); // false
// 下面的都返回 false
Number.isNaN(true);
Number.isNaN(null);
Number.isNaN(37);
Number.isNaN("37");
Number.isNaN("37.37");
Number.isNaN("");
Number.isNaN(" ");
复制代码
Number.parseInt()
、Number.parseFloat()
。ES6 将全局方法parseInt()
和parseFloat()
,移植到Number
对象上面,行为彻底保持不变。这样作的目的,是逐步减小全局性方法,使得语言逐步模块化。// ES5的写法
parseInt('12.34') // 12
parseFloat('123.45#') // 123.45
// ES6的写法
Number.parseInt('12.34') // 12
Number.parseFloat('123.45#') // 123.45
Number.parseInt === parseInt // true
Number.parseFloat === parseFloat // true
复制代码
Number.isInteger()
。Number.isInteger()
用来判断一个值是否为整数。须要注意的是,在 JavaScript 内部,整数和浮点数是一样的储存方法,因此 3 和 3.0 被视为同一个值。Number.isInteger(25) // true
Number.isInteger(25.0) // true
Number.isInteger(25.1) // false
Number.isInteger("15") // false
Number.isInteger(true) // false
复制代码
Math.trunc
方法用于去除一个数的小数部分,返回整数部分。对于非数值,Math.trunc
内部使用Number
方法将其先转为数值。对于空值和没法截取整数的值,返回NaN
。Math.trunc(4.1) // 4
Math.trunc(4.9) // 4
Math.trunc(-4.1) // -4
Math.trunc(-4.9) // -4
Math.trunc(-0.1234) // -0
复制代码
Math.sign
方法用来判断一个数究竟是正数、负数、仍是零。对于非数值,会先将其转换为数值。它返回五种值,参数为正数,返回+1
;参数为负数,返回-1
;参数为 0,返回0
;参数为-0,返回-0
;其余值,返回NaN
。Math.sign(-5) // -1
Math.sign(5) // +1
Math.sign(0) // +0
Math.sign(-0) // -0
Math.sign(NaN) // NaN
Math.sign('') // 0
Math.sign(true) // +1
Math.sign(false) // 0
Math.sign(null) // 0
Math.sign('9') // +1
Math.sign('foo') // NaN
Math.sign() // NaN
Math.sign(undefined) // NaN
复制代码
Math.cbrt
方法用于计算一个数的立方根。对于非数值,Math.cbrt
方法内部也是先使用Number
方法将其转为数值。Math.cbrt(-1) // -1
Math.cbrt(0) // 0
Math.cbrt(1) // 1
Math.cbrt(2) // 1.2599210498948734
复制代码
Math.hypot
方法返回全部参数的平方和的平方根。Math.hypot(3, 4); // 5
Math.hypot(3, 4, 5); // 7.0710678118654755
Math.hypot(); // 0
Math.hypot(NaN); // NaN
Math.hypot(3, 4, 'foo'); // NaN
Math.hypot(3, 4, '5'); // 7.0710678118654755
Math.hypot(-3); // 3
复制代码
**
)。指数运算符能够与等号结合,造成一个新的赋值运算符(**=
)。2 ** 2 // 4
2 ** 3 // 8
let a = 1.5;
a **= 2;
// 等同于 a = a * a;
let b = 4;
b **= 3;
// 等同于 b = b * b * b;
复制代码
function log(x, y = 'World') {
console.log(x, y);
}
log('Hello') // Hello World
log('Hello', 'China') // Hello China
log('Hello', '') // Hello
复制代码
function foo({x, y = 5}) {
console.log(x, y);
}
foo({}) // undefined 5
foo({x: 1}) // 1 5
foo({x: 1, y: 2}) // 1 2
foo() // TypeError: Cannot read property 'x' of undefined
复制代码
// 例一
function f(x = 1, y) {
return [x, y];
}
f() // [1, undefined]
f(2) // [2, undefined])
f(, 1) // 报错
f(undefined, 1) // [1, 1]
// 例二
function f(x, y = 5, z) {
return [x, y, z];
}
f() // [undefined, 5, undefined]
f(1) // [1, 5, undefined]
f(1, ,2) // 报错
f(1, undefined, 2) // [1, 5, 2]
复制代码
length
属性。指定了默认值之后,函数的length
属性,将返回没有指定默认值的参数个数。也就是说,指定了默认值后,length
属性将失真。fn.length 返回形参个数,arguments.length 返回实参个数。(function (a) {}).length // 1
(function (a = 5) {}).length // 0
(function (a, b, c = 5) {}).length // 2
复制代码
var x = 1;
function f(x, y = x) {
console.log(y);
}
f(2) // 2
复制代码
上面代码中,参数y
的默认值等于变量x
。调用函数f
时,参数造成一个单独的做用域。在这个做用域里面,默认值变量x
指向第一个参数x
,而不是全局变量x
,因此输出是2
。算法
let x = 1;
function f(y = x) {
let x = 2;
console.log(y);
}
f() // 1
复制代码
上面代码中,函数f
调用时,参数y = x
造成一个单独的做用域。这个做用域里面,变量x
自己没有定义,因此指向外层的全局变量x
。函数调用时,函数体内部的局部变量x
影响不到默认值变量x
。数组
var x = 1;
function foo(x = x) {
// ...
}
foo() // ReferenceError: x is not defined
复制代码
上面代码中,参数x = x
造成一个单独做用域。实际执行的是let x = x
,因为暂时性死区的缘由,这行代码会报错”x 未定义“。数据结构
var x = 1;
function foo(x, y = function() { x = 2; }) {
var x = 3;
y();
console.log(x);
}
foo()//3
console.log(x); //1
复制代码
若是将var x = 3
的var
去除,函数foo
的内部变量x
就指向第一个参数x
,与匿名函数内部的x
是一致的,因此最后输出的就是2
,而外层的全局变量x
依然不受影响。app
var x = 1;
function foo(x, y = function() { x = 2; }) {
x = 3;
y();
console.log(x);
}
foo() // 2
x // 1
复制代码
...变量名
),用于获取函数的多余参数,这样就不须要使用arguments
对象了。rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中。function add(...values) {
let sum = 0;
for (var val of values) {
sum += val;
}
return sum;
}
add(2, 5, 3) // 10
复制代码
arguments
对象不是数组,而是一个相似数组的对象。因此为了使用数组的方法,必须使用Array.prototype.slice.call
先将其转为数组。rest 参数就不存在这个问题,它就是一个真正的数组,数组特有的方法均可以使用。下面是一个利用 rest 参数改写数组push
方法的例子。模块化
function push(array, ...items) {
items.forEach(function(item) {
array.push(item);
console.log(item);
});
}
var a = [];
push(a, 1, 2, 3)
复制代码
注意,rest 参数以后不能再有其余参数(即只能是最后一个参数),不然会报错。函数
// 报错
function f(a, ...b, c) {
// ...
}
复制代码
函数的length
属性,不包括 rest 参数。ui
(function(a) {}).length // 1
(function(...a) {}).length // 0
(function(a, ...b) {}).length // 1
复制代码
function foo() {}
foo.name // "foo"
var f = function () {};
f.name // "f"
var fn1 = function fn2(){};
fn1.name // "fn2"
复制代码
=>
)定义函数。var f = v => v;
//上面的箭头函数等同于
var f = function(v) {
return v;
};
复制代码
若是箭头函数不须要参数或须要多个参数,就使用一个圆括号表明参数部分。this
var f = () => 5;
// 等同于
var f = function () { return 5 };
var sum = (num1, num2) => num1 + num2;
// 等同于
var sum = function(num1, num2) {
return num1 + num2;
};
复制代码
若是箭头函数的代码块部分多于一条语句,就要使用大括号将它们括起来,而且使用return
语句返回。
var sum = (num1, num2) => { return num1 + num2; }
复制代码
因为大括号被解释为代码块,因此若是箭头函数直接返回一个对象,必须在对象外面加上括号,不然会报错。
// 报错
let getTempItem = id => { id: id, name: "Temp" };
// 不报错
let getTempItem = id => ({ id: id, name: "Temp" });
复制代码
this
对象,就是定义时所在的对象,而不是使用时所在的对象。new
命令,不然会抛出一个错误。arguments
对象,该对象在函数体内不存在。若是要用,能够用 rest 参数代替。yield
命令,所以箭头函数不能用做 Generator 函数。this
指向的固定化,并非由于箭头函数内部有绑定this
的机制,实际缘由是箭头函数根本没有本身的this
,致使内部的this
就是外层代码块的this
。正是由于它没有this
,因此也就不能用做构造函数。this
,因此固然也就不能用call()
、apply()
、bind()
这些方法去改变this
的指向。// ES6
function foo() {
setTimeout(() => {
console.log('id:', this.id);
}, 100);
}
// ES5
function foo() {
var _this = this;
setTimeout(function () {
console.log('id:', _this.id);
}, 100);
}
//转换后的 ES5 版本清楚地说明了,箭头函数里面根本没有本身的this,而是引用外层的this。
复制代码
function clownsEverywhere( param1, param2, ) { /* ... */ }
clownsEverywhere(
'foo',
'bar',
);
复制代码
console.log(...[1, 2, 3])
// 1 2 3
console.log(1, ...[2, 3, 4], 5)
// 1 2 3 4 5
[...document.querySelectorAll('div')]
// [<div>, <div>, <div>]
复制代码
扩展运算符后面还能够放置表达式。
const arr = [
...(x > 0 ? ['a'] : []),
'b',
];
复制代码
若是扩展运算符后面是一个空数组,则不产生任何效果。
[...[], 1]
// [1]
复制代码
因为扩展运算符能够展开数组,因此再也不须要apply
方法,将数组转为函数的参数了。
// ES5 的写法
function f(x, y, z) {
// ...
}
var args = [0, 1, 2];
f.apply(null, args);
// ES6的写法
function f(x, y, z) {
// ...
}
let args = [0, 1, 2];
f(...args);
复制代码
取一个数组中的最大值。
//es5
Math.max.apply(null,[1,5,2,8]) // 8
//es6
Math.max(...[1,5,2,8])//8
//上面两种方法等同于
Math.max(1,5,2,8)
复制代码
扩展运算符能够用于复制数组。
//es5
const a1 = [1, 2];
const a2 = a1.concat();
a2[0] = 2;
a1 // [1, 2]
a2 // [2, 2]
//es6
const a1 = [1, 2];
// 写法一
const a2 = [...a1];
// 写法二
const [...a2] = a1;
复制代码
扩展运算符用于合并数组。
// ES5
[1, 2].concat(more)
// ES6
[1, 2, ...more]
var arr1 = ['a', 'b'];
var arr2 = ['c'];
var arr3 = ['d', 'e'];
// ES5的合并数组
arr1.concat(arr2, arr3);
// [ 'a', 'b', 'c', 'd', 'e' ]
// ES6的合并数组
[...arr1, ...arr2, ...arr3]
// [ 'a', 'b', 'c', 'd', 'e' ]
复制代码
扩展运算符能够与解构赋值结合起来,用于生成数组。
// ES5
a = list[0], rest = list.slice(1)
// ES6
[a, ...rest] = list
复制代码
const [first, ...rest] = [1, 2, 3, 4, 5];
first // 1
rest // [2, 3, 4, 5]
const [first, ...rest] = [];
first // undefined
rest // []
const [first, ...rest] = ["foo"];
first // "foo"
rest // []
复制代码
const [...butLast, last] = [1, 2, 3, 4, 5];
// 报错
const [first, ...middle, last] = [1, 2, 3, 4, 5];
// 报错
复制代码
扩展运算符还能够将字符串转为真正的数组。
[...'hello']
// [ "h", "e", "l", "l", "o" ]
复制代码
扩展运算符实现了 Iterator 接口的对象
let nodeList = document.querySelectorAll('div');
let array = [...nodeList];
复制代码
Array.from()
方法用于将两类对象转为真正的数组。map
方法,用来对每一个元素进行处理,将处理后的值放入返回的数组。map
函数里面用到了this
关键字,还能够传入Array.from
的第三个参数,用来绑定this
。// NodeList对象
let ps = document.querySelectorAll('p');
Array.from(ps).forEach(function (p) {
console.log(p);
});
// arguments对象
function foo() {
var args = Array.from(arguments);
// ...
}
复制代码
Array.of()
方法用于将一组值,转换为数组。这个方法的主要目的,是弥补数组构造函数Array()
的不足。由于参数个数的不一样,会致使Array()
的行为有差别。//Array
Array() // []
Array(3) // [, , ,]
Array(3, 11, 8) // [3, 11, 8]
Array.of(3, 11, 8) // [3,11,8]
Array.of(3) // [3]
Array.of(3).length // 1
复制代码
copyWithin
方法,在当前数组内部,将指定位置的成员复制到其余位置(会覆盖原有成员),而后返回当前数组。也就是说,使用这个方法,会修改当前数组。 它接受三个参数。[1, 2, 3, 4, 5].copyWithin(0, 3)
// [4, 5, 3, 4, 5]
复制代码
find()
和findIndex()
。这两个方法均可以接受第二个参数,用来绑定回调函数的this
对象。find
方法,用于找出第一个符合条件的数组成员。它的参数是一个回调函数,全部数组成员依次执行该回调函数,直到找出第一个返回值为true
的成员,而后返回该成员。若是没有符合条件的成员,则返回undefined
。[1, 4, -5, 10].find((n) => n < 0)
// -5
[1, 5, 10, 15].find(function(value, index, arr) {
return value > 9;
}) // 10
//find方法的回调函数能够接受三个参数,依次为当前的值、当前的位置和原数组。
复制代码
findIndex
方法的用法与find
方法很是相似,返回第一个符合条件的数组成员的位置,若是全部成员都不符合条件,则返回-1
。[1, 5, 10, 15].findIndex(function(value, index, arr) {
return value > 9;
}) // 2
复制代码
fill()
,fill
方法使用给定值,填充一个数组。fill
方法用于空数组的初始化很是方便。数组中已有的元素,会被所有抹去。fill
方法还能够接受第二个和第三个参数,用于指定填充的起始位置和结束位置。['a', 'b', 'c'].fill(7)
// [7, 7, 7]
new Array(3).fill(7)
// [7, 7, 7]
复制代码
for...of
是es6引入的做为遍历全部数据结构的统一的方法。一个数据结构只要部署了Symbol.iterator
属性,就被视为具备 iterator 接口,就能够用for...of
循环遍历它的成员。也就是说,for...of
循环内部调用的是数据结构的Symbol.iterator
方法。entries()
,keys()
和 values()
用于遍历数组,它们都返回一个遍历器对象,能够用for...of
循环进行遍历,惟一的区别是keys()
是对键名的遍历、values()
是对键值的遍历,entries()
是对键值对的遍历。for (let index of ['a', 'b'].keys()) {
console.log(index);
}
// 0
// 1
for (let elem of ['a', 'b'].values()) {
console.log(elem);
}
// 'a'
// 'b'
for (let [index, elem] of ['a', 'b'].entries()) {
console.log(index, elem);
}
// 0 "a"
// 1 "b"
复制代码
includes()
方法返回一个布尔值,表示某个数组是否包含给定的值,与字符串的includes
方法相似。[1, 2, 3].includes(2) // true
[1, 2, 3].includes(4) // false
[1, 2, NaN].includes(NaN) // true
复制代码
该方法的第二个参数表示搜索的起始位置,默认为0
。若是第二个参数为负数,则表示倒数的位置,若是这时它大于数组长度(好比第二个参数为-4
,但数组长度为3
),则会重置为从0
开始。 没有该方法以前,咱们一般使用数组的indexOf
方法,检查是否包含某个值。indexOf
方法有两个缺点,一是不够语义化,它的含义是找到参数值的第一个出现位置,因此要去比较是否不等于-1
,表达起来不够直观。二是,它内部使用严格相等运算符(===
)进行判断,这会致使对NaN
的误判。 10. 数组的空位指,数组的某一个位置没有任何值。 空位不是undefined
,一个位置的值等于undefined
,依然是有值的。空位是没有任何值,in
运算符能够说明这一点。
0 in [undefined, undefined, undefined] // true
0 in [, , ,] // false
复制代码
es5对空位的处理很不一致,大多数状况下会忽略空位。
forEach()
, filter()
, reduce()
, every()
和some()
都会跳过空位。map()
会跳过空位,但会保留这个值join()
和toString()
会将空位视为undefined
,而undefined
和null
会被处理成空字符串。 es6明确将空位转为undefined
。Array.from
方法会将数组的空位,转为undefined
,也就是说,这个方法不会忽略空位。Array.from(['a',,'b'])
// [ "a", undefined, "b" ]
复制代码
...
)也会将空位转为undefined
。[...['a',,'b']]
// [ "a", undefined, "b" ]
复制代码
copyWithin()
会连空位一块儿拷贝。[,'a','b',,].copyWithin(2,0) // [,"a",,"a"]
复制代码
fill()
会将空位视为正常的数组位置。new Array(3).fill('a') // ["a","a","a"]
复制代码
for...of
循环也会遍历空位。let arr = [, ,];
for (let i of arr) {
console.log(1);
}
// 1
// 1
复制代码
上面代码中,数组arr
有两个空位,for...of
并无忽略它们。若是改为map
方法遍历,空位是会跳过的。 entries()
、keys()
、values()
、find()
和findIndex()
会将空位处理成undefined
。
// entries()
[...[,'a'].entries()] // [[0,undefined], [1,"a"]]
// keys()
[...[,'a'].keys()] // [0,1]
// values()
[...[,'a'].values()] // [undefined,"a"]
// find()
[,'a'].find(x => true) // undefined
// findIndex()
[,'a'].findIndex(x => true) // 0
复制代码
因为空位的处理规则很是不统一,因此建议避免出现空位。
//es6写法
const foo = 'bar';
const baz = {foo};
baz // {foo: "bar"}
// 等同于es5写法
const baz = {foo: foo};
//es6写法
const o = {
method() {
return "Hello!";
}
};
// 等同于es5写法
const o = {
method: function() {
return "Hello!";
}
};
复制代码
// 方法一
obj.foo = true;
// 方法二
obj['a' + 'bc'] = 123;
复制代码
可是,若是使用字面量方式定义对象(使用大括号),在 ES5 中只能使用方法一(标识符)定义属性。
var obj = {
foo: true,
abc: 123
};
复制代码
ES6 容许字面量定义对象时,用方法二(表达式)做为对象的属性名,即把表达式放在方括号内。
let propKey = 'foo';
let obj = {
[propKey]: true,
['a' + 'bc']: 123
};
复制代码
表达式还能够用于定义方法名。
let obj = {
['h' + 'ello']() {
return 'hi';
}
};
obj.hello() // hi
复制代码
注意,属性名表达式与简洁表示法,不能同时使用,会报错。
// 报错
const foo = 'bar';
const bar = 'abc';
const baz = { [foo] };
// 正确
const foo = 'bar';
const baz = { [foo]: 'abc'};
复制代码
Object.is()
。ES5 比较两个值是否相等,只有两个运算符:相等运算符(==
)和严格相等运算符(===
)。它们都有缺点,前者会自动转换数据类型,后者的NaN
不等于自身,以及+0
等于-0
。JavaScript 缺少一种运算,在全部环境中,只要两个值是同样的,它们就应该相等。 ES6 提出同值相等算法,用来解决这个问题。Object.is
就是部署这个算法的新方法。它用来比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致。Object.is('foo', 'foo')
// true
Object.is({}, {})
// false
复制代码
不一样之处只有两个:一是+0
不等于-0
,二是NaN
等于自身。
+0 === -0 //true
NaN === NaN // false
Object.is(+0, -0) // false
Object.is(NaN, NaN) // true
复制代码
Object.assign()
。Object.assign
方法用于对象的合并,将源对象(source)的全部可枚举属性,复制到目标对象(target)。const target = { a: 1 };
const source1 = { b: 2 };
const source2 = { c: 3 };
Object.assign(target, source1, source2);
console.log(target); // {a:1, b:2, c:3}
复制代码
若是只有一个参数,Object.assign
会直接返回该参数。
const obj = {a: 1};
Object.assign(obj) === obj // true
复制代码
因为undefined
和null
没法转成对象,因此若是它们做为参数,就会报错。
Object.assign(undefined) // 报错
Object.assign(null) // 报错
复制代码
注意:Object.assign
能够用来处理数组,可是会把数组视为对象。
Object.assign([1, 2, 3], [4, 5])
// [4, 5, 3]
//把数组视为属性名为 0、一、2 的对象,所以源数组的 0 号属性4覆盖了目标数组的 0 号属性1。
复制代码
Object.keys()
。ES5 引入了Object.keys
方法,返回一个数组,成员是参数对象自身的(不含继承的)全部可遍历(enumerable)属性的键名。var obj = { foo: 'bar', baz: 42 };
Object.keys(obj)
// ["foo", "baz"]
复制代码
ES2017 引入了跟Object.keys
配套的Object.values
和Object.entries
,做为遍历一个对象的补充手段,供for...of
循环使用。
let {keys, values, entries} = Object;
let obj = { a: 1, b: 2, c: 3 };
for (let key of keys(obj)) {
console.log(key); // 'a', 'b', 'c'
}
for (let value of values(obj)) {
console.log(value); // 1, 2, 3
}
for (let [key, value] of entries(obj)) {
console.log([key, value]); // ['a', 1], ['b', 2], ['c', 3]
}
复制代码
Object.values()
。Object.values
方法返回一个数组,成员是参数对象自身的(不含继承的)全部可遍历(enumerable)属性的键值。const obj = { foo: 'bar', baz: 42 };
Object.values(obj)
// ["bar", 42]
复制代码
返回数组的成员顺序,下面的代码中,属性名为数值的属性,是按照数值大小,从小到大遍历的,所以返回的顺序是b
、c
、a
。
const obj = { 100: 'a', 2: 'b', 7: 'c' };
Object.values(obj)
// ["b", "c", "a"]
复制代码
Object.entries()
。Object.entries
方法返回一个数组,成员是参数对象自身的(不含继承的)全部可遍历(enumerable)属性的键值对数组。const obj = { foo: 'bar', baz: 42 };
Object.entries(obj)
// [ ["foo", "bar"], ["baz", 42] ]
复制代码
let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
x // 1
y // 2
z // { a: 3, b: 4 }
复制代码
因为解构赋值要求等号右边是一个对象,因此若是等号右边是undefined
或null
,就会报错,由于它们没法转为对象。
let { x, y, ...z } = null; // 运行时错误
let { x, y, ...z } = undefined; // 运行时错误
复制代码
解构赋值必须是最后一个参数,不然会报错。
let { ...x, y, z } = obj; // 句法错误
let { x, ...y, ...z } = obj; // 句法错误
复制代码
注意,解构赋值的拷贝是浅拷贝,即若是一个键的值是复合类型的值(数组、对象、函数)、那么解构赋值拷贝的是这个值的引用,而不是这个值的副本。
let obj = { a: { b: 1 } };
let { ...x } = obj;
obj.a.b = 2;
console.log(x.a.b); // 2
复制代码
...
)用于取出参数对象的全部可遍历属性,拷贝到当前对象之中。let z = { a: 3, b: 4 };
let n = { ...z };
n // { a: 3, b: 4 }
复制代码
这等同于使用Object.assign
方法。
let aClone = { ...a };
// 等同于
let aClone = Object.assign({}, a);
复制代码