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);
複製代碼