你不懂JS:ES6與未來 新增API
前言
現在一言不合就問技術棧。今日早讀文章由前端早讀課專欄作者@HetfieldJoe翻譯分享。
正文從這開始~
從值的轉換到數學計算,ES6給各種內建原生類型和對象增加了許多靜態屬性和方法來輔助這些常見任務。另外,一些原生類型的實例通過各種新的原型方法獲得了新的能力。
注意: 大多數這些特性都可以被忠實地填補。我們不會在這裡深入這樣的細節,但是關於兼容標準的shim/填補,你可以看一下「ES6 Shim」(https://github.com/paulmillr/es6-shim/)。
Array
在JS中被各種用戶庫擴展得最多的特性之一就是數組類型。ES6在數組上增加許多靜態的和原型(實例)的幫助功能應當並不令人驚訝。
Array.of(..) 靜態函數
Array(..)的構造器有一個盡人皆知的坑:如果僅有一個參數值被傳遞,而且這個參數值是一個數字的話,它並不會製造一個含有一個帶有該數值元素的數組,而是構建一個長度等於這個數字的空數組。這種操作造成了不幸的和怪異的「空值槽」行為,而這正是JS數組為人詬病的地方。
Array.of(..)作為數組首選的函數型構造器取代了Array(..),因為Array.of(..)沒有那種單數字參數值的情況。考慮如下代碼:
在什麼樣的環境下,你才會想要是使用Array.of(..)來創建一個數組,而不是使用像c = [1,2,3]這樣的字面語法呢?有兩種可能的情況。
如果你有一個回調,傳遞給它的參數值本應當被包裝在一個數組中時,Array.of(..)就完美地符合條件。這可能不是那麼常見,但是它可以為你的癢處撓上一把。
另一種場景是如果你擴展Array構成它的子類,而且希望能夠在一個你的子類的實例中創建和初始化元素,比如:
你不能(簡單地)只創建一個MyCoolArray的構造器,讓它覆蓋Array父構造器的行為,因為這個父構造器對於實際創建一個規範的數組值(初始化this)是必要的。在MyCoolArray子類上「被繼承」的靜態of(..)方法提供了一個不錯的解決方案。
Array.from(..) 靜態函數
在JavaScript中一個「類數組對象」是一個擁有length屬性的對象,這個屬性明確地帶有0或更高的整數值。
在JS中處理這些值出了名地讓人沮喪;將它們變形為真正的數組曾經是十分常見的做法,這樣各種Array.property方法(map(..),indexOf(..)等等)才能與它一起使用。這種處理通常看起來像:
另一種slice(..)經常被使用的常見任務是,複製一個真正的數組:
vararr2=arr.slice();
在這兩種情況下,新的ES6Array.from(..)方法是一種更易懂而且更優雅的方式 —— 也不那麼冗長:
vararr=Array.from(arrLike);
vararrCopy=Array.from(arr);
Array.from(..)會查看第一個參數值是否是一個可迭代對象(參見第三章的「迭代器」),如果是,它就使用迭代器來產生值,並將這些值「拷貝」到將要被返回的數組中。因為真正的數組擁有一個可以產生這些值的迭代器,所以這個迭代器會被自動地使用。
但是如果你傳遞一個類數組對象作為Array.from(..)的第一個參數值,它的行為基本上是和slice()(不帶參數值的!)或apply()相同的,它簡單地循環所有的值,訪問從0開始到length值的由數字命名的屬性。
考慮如下代碼:
vararrLike={
length:4,
2:"foo"
};
Array.from(arrLike);
// [ undefined, undefined, "foo", undefined ]
因為在arrLike上不存在位置0,1,和3,所以對這些值槽中的每一個,結果都是undefined值。
你也可以這樣產生類似的結果:
varemptySlotsArr=[];
emptySlotsArr.length=4;
emptySlotsArr[2]="foo";
Array.from(emptySlotsArr);
// [ undefined, undefined, "foo", undefined ]
避免空值槽
前面的代碼段中,在emptySlotsArr和Array.from(..)調用的結果有一個微妙但重要的不同。Array.from(..)從不產生空值槽。
在ES6之前,如果你想要製造一個被初始化為在每個值槽中使用實際undefined值(不是空值槽!)的特定長數組,你不得不做一些額外的工作:
vara=Array(4);// 四個空值槽!
varb=Array.apply(null,{length:4});// 四個 `undefined` 值
但現在Array.from(..)使這件事簡單了些:
varc=Array.from({length:4});// 四個 `undefined` 值
警告: 使用一個像前面代碼段中的a那樣的空值槽數組可以與一些數組函數工作,但是另一些函數會忽略空值槽(比如map(..)等)。你永遠不應該刻意地使用空值槽,因為它幾乎肯定會在你的程序中導致奇怪/不可預料的行為。
映射
Array.from(..)工具還有另外一個絕技。第二個參數值,如果被提供的話,是一個映射函數(和普通的Array#map(..)幾乎相同),它在將每個源值映射/變形為返回的目標值時調用。考慮如下代碼:
vararrLike={
length:4,
2:"foo"
};
Array.from(arrLike,functionmapper(val,idx){
if(typeofval=="string"){
returnval.toUpperCase();
}
else{
returnidx;
}
});
// [ 0, 1, "FOO", 3 ]
注意: 就像其他接收回調的數組方法一樣,Array.from(..)接收可選的第三個參數值,它將被指定為作為第二個參數傳遞的回調的this綁定。否則,this將是undefined。
一個使用Array.from(..)將一個8位值數組翻譯為16位值數組的例子,參見第五章的「類型化數組」。
創建 Arrays 和子類型
在前面幾節中,我們討論了Array.of(..)和Array.from(..),它們都用與構造器相似的方法創建一個新數組。但是在子類中它們會怎麼做?它們是創建基本Array的實例,還是創建衍生的子類的實例?
classMyCoolArrayextendsArray{
..
}
MyCoolArray.from([1,2])instanceofMyCoolArray;// true
Array.from(
MyCoolArray.from([1,2])
)instanceofMyCoolArray;// false
of(..)和from(..)都使用它們被訪問時的構造器來構建數組。所以如果你使用基本的Array.of(..)你將得到Array實例,但如果你使用MyCoolArray.of(..),你將得到一個MyCoolArray實例。
在第三章的「類」中,我們講解了在所有內建類(比如Array)中定義好的@@species設定,它被用於任何創建新實例的原型方法。slice(..)是一個很棒的例子:
varx=newMyCoolArray(1,2,3);
x.slice(1)instanceofMyCoolArray;// true
一般來說,這種默認行為將可能是你想要的,但是正如我們在第三章中討論過的,如果你想的話你 可以 覆蓋它:
classMyCoolArrayextendsArray{
// 強制 `species` 為父類構造器
staticget[Symbol.species](){returnArray;}
}
varx=newMyCoolArray(1,2,3);
x.slice(1)instanceofMyCoolArray;// false
x.slice(1)instanceofArray;// true
要注意的是,@@species設定僅適用於原型方法,比如slice(..)。of(..)和from(..)不使用它;它們倆都只使用this綁定(哪個構造器被用於發起引用)。考慮如下代碼:
classMyCoolArrayextendsArray{
// 強制 `species` 為父類構造器
staticget[Symbol.species](){returnArray;}
}
varx=newMyCoolArray(1,2,3);
MyCoolArray.from(x)instanceofMyCoolArray;// true
MyCoolArray.of([2,3])instanceofMyCoolArray;// true
copyWithin(..) 原型方法
Array#copyWithin(..)是一個對所有數組可用的新修改器方法(包括類型化數組;參加第五章)。copyWithin(..)將數組的一部分拷貝到同一個數組的其他位置,覆蓋之前存在在那裡的任何東西。
它的參數值是 目標(要被拷貝到的索引位置),開始(拷貝開始的索引位置(含)),和可選的 結束(拷貝結束的索引位置(不含))。如果這些參數值中存在任何負數,那麼它們就被認為是相對於數組的末尾。
考慮如下代碼:
[1,2,3,4,5].copyWithin(3,);// [1,2,3,1,2]
[1,2,3,4,5].copyWithin(3,,1);// [1,2,3,1,5]
[1,2,3,4,5].copyWithin(,-2);// [4,5,3,4,5]
[1,2,3,4,5].copyWithin(,-2,-1);// [4,2,3,4,5]
copyWithin(..)方法不會擴張數組的長度,就像前面代碼段中的第一個例子展示的。當到達數組的末尾時拷貝就會停止。
與你可能想像的不同,拷貝的順序並不總是從左到右的。如果起始位置與目標為重疊的話,它有可能造成已經被拷貝過的值被重複拷貝,這大概不是你期望的行為。
所以在這種情況下,演算法內部通過相反的拷貝順序來避免這個坑。考慮如下代碼:
[1,2,3,4,5].copyWithin(2,1);// ???
如果演算法是嚴格的從左到右,那麼2應當被拷貝來覆蓋3,然後這個被拷貝的2應當被拷貝來覆蓋4,然後這個被拷貝的2應當被拷貝來覆蓋5,而你最終會得到[1,2,2,2,2]。
與此不同的是,拷貝演算法把方向反轉過來,拷貝4來覆蓋5,然後拷貝3來覆蓋4,然後拷貝2來覆蓋3,而最後的結果是[1,2,2,3,4]。就期待的結果而言這可能更「正確」,但是如果你僅以單純的從左到右的方式考慮拷貝演算法的話,它就可能讓人糊塗。
fill(..) 原型方法
ES6中的Array#fill(..)方法原生地支持使用一個指定的值來完全地(或部分地)填充一個既存的數組:
vara=Array(4).fill(undefined);
a;
// [undefined,undefined,undefined,undefined]
fill(..)可選地接收 開始 與 結束 參數,它們指示要被填充的數組的一部分,比如:
vara=[null,null,null,null].fill(42,1,3);
a;// [null,42,42,null]
find(..) 原型方法
一般來說,在一個數組中搜索一個值的最常見方法曾經是indexOf(..)方法,如果值被找到的話它返回值的位置索引,沒有找到的話返回 -1:
vara=[1,2,3,4,5];
(a.indexOf(3)!=-1);// true
(a.indexOf(7)!=-1);// false
(a.indexOf("2")!=-1);// false
indexOf(..)比較要求一個嚴格===匹配,所以搜索"2"找不到值2,反之亦然。沒有辦法覆蓋indexOf(..)的匹配演算法。不得不手動與值-1進行比較也很不幸/不優雅。
提示: 一個使用~操作符來繞過難看的-1的有趣(而且爭議性地令人糊塗)技術,參見本系列的 類型與文法。
從ES5開始,控制匹配邏輯的最常見的迂迴方法是some(..)。它的工作方式是為每一個元素調用一個回調函數,直到這些調用中的一個返回true/truthy值,然後它就會停止。因為是由你來定義這個回調函數,所以你就擁有了如何做出匹配的完全控制權:
vara=[1,2,3,4,5];
a.some(functionmatcher(v){
returnv=="2";
});// true
a.some(functionmatcher(v){
returnv==7;
});// false
但這種方式的缺陷是你只能使用true/false來指示是否找到了合適的匹配值,而不是實際被匹配的值。
ES6的find(..)解決了這個問題。它的工作方式基本上與some(..)相同,除了一旦回調返回一個true/truthy值,實際的數組值就會被返回:
vara=[1,2,3,4,5];
a.find(functionmatcher(v){
returnv=="2";
});// 2
a.find(functionmatcher(v){
returnv==7;// undefined
});
使用一個自定義的matcher(..)函數還允許你與對象這樣的複雜值進行匹配:
varpoints=[
{x:10,y:20},
{x:20,y:30},
{x:30,y:40},
{x:40,y:50},
{x:50,y:60}
];
points.find(functionmatcher(point){
return(
point.x%3==&&
point.y%4==
);
});// { x: 30, y: 40 }
注意: 和其他接收回調的數組方法一樣,find(..)接收一個可選的第二參數。如果它被設置了的話,就將被指定為作為第一個參數傳遞的回調的this綁定。否則,this將是undefined。
findIndex(..) 原型方法
雖然前一節展示了some(..)如何在一個數組檢索給出一個Boolean結果,和find(..)如何從數組檢索中給出匹配的值,但是還有一種需求是尋找匹配的值的位置索引。
indexOf(..)可以完成這個任務,但是沒有辦法控制它的匹配邏輯;它總是使用===嚴格等價。所以ES6的findIndex(..)才是答案:
varpoints=[
{x:10,y:20},
{x:20,y:30},
{x:30,y:40},
{x:40,y:50},
{x:50,y:60}
];
points.findIndex(functionmatcher(point){
return(
point.x%3==&&
point.y%4==
);
});// 2
points.findIndex(functionmatcher(point){
return(
point.x%6==&&
point.y%7==
);
});// -1
不要使用findIndex(..) != -1(在indexOf(..)中經常這麼干)來從檢索中取得一個boolean,因為some(..)已經給出了你想要的true/false了。而且也不要用a[ a.findIndex(..) ]來取得一個匹配的值,因為這是find(..)完成的任務。最後,如果你需要嚴格匹配的索引,就使用indexOf(..),如果你需要一個更加定製化的匹配,就使用findIndex(..)。
注意: 和其他接收回調的數組方法一樣,find(..)接收一個可選的第二參數。如果它被設置了的話,就將被指定為作為第一個參數傳遞的回調的this綁定。否則,this將是undefined。
entries(), values(), keys() 原型方法
在第三章中,我們展示了數據結構如何通過一個迭代器來提供一種模擬逐個值的迭代。然後我們在第五章探索新的ES6集合(Map,Set,等)如何為了產生不同種類的迭代器而提供幾種方法時闡述了這種方式。
因為Array並不是ES6的新東西,所以它可能不被認為是一個傳統意義上的「集合」,但是在它提供了相同的迭代器方法:entries(),values(),和keys()的意義上,它是的。考慮如下代碼:
vara=[1,2,3];
[...a.values()];// [1,2,3]
[...a.keys()];// [0,1,2]
[...a.entries()];// [ [0,1], [1,2], [2,3] ]
[...a[Symbol.iterator]()];// [1,2,3]
就像Set一樣,默認的Array迭代器與values()放回的東西相同。
在本章早先的「避免空值槽」一節中,我們展示了Array.from(..)如何將一個數組中的空值槽看作帶有undefined的存在值槽。其實際的原因是,在底層數組迭代器就是以這種方式動作的:
vara=[];
a.length=3;
a[1]=2;
[...a.values()];// [undefined,2,undefined]
[...a.keys()];// [0,1,2]
[...a.entries()];// [ [0,undefined], [1,2], [2,undefined] ]
Object
幾個額外的靜態幫助方法已經被加入Object。從傳統意義上講,這種種類的函數是關注於對象值的行為/能力的。
但是,從ES6開始,Object靜態函數還用於任意種類的通用全局API —— 那些還沒有更自然地存在於其他的某些位置的API(例如,Array.from(..))。
Object.is(..) 靜態函數
Object.is(..)靜態函數進行值的比較,它的風格甚至要比===比較還要嚴格。
Object(..)調用底層的SameValue演算法(ES6語言規範,第7.2.9節)。SameValue演算法基本上與===嚴格等價比較演算法相同(ES6語言規範,第7.2.13節),但是帶有兩個重要的例外。
考慮如下代碼:
varx=NaN,y=,z=-;
x===x;// false
y===z;// true
Object.is(x,x);// true
Object.is(y,z);// false
你應當為嚴格等價性比較繼續使用===;Object.is(..)不應當被認為是這個操作符的替代品。但是,在你想要嚴格地識別NaN或-0值的情況下,Object.is(..)是現在的首選方式。
注意: ES6還增加了一個Number.isNaN(..)工具(在本章稍後討論),它可能是一個稍稍方便一些的測試;比起Object.is(x, NaN)你可能更偏好Number.isNaN(x)。你 可以 使用笨拙的x == 0 && 1 / x === -Infinity來準確地測試-0,但在這種情況下Object.is(x,-0)要好得多。
Object.getOwnPropertySymbols(..) 靜態函數
第二章中的「Symbol」一節討論了ES6中的新Symbol基本值類型。
Symbol可能將是在對象上最經常被使用的特殊(元)屬性。所以引入了Object.getOwnPropertySymbols(..),它僅取回直接存在於對象上的symbol 屬性:
varo={
foo:42,
[Symbol("bar")]:"hello world",
baz:true
};
Object.getOwnPropertySymbols(o);// [ Symbol(bar) ]
Object.setPrototypeOf(..) 靜態函數
還是在第二章中,我們提到了Object.setPrototypeOf(..)工具,它為了 行為委託 的目的(意料之中地)設置一個對象的[[Prototype]](參見本系列的 this與對象原型)。考慮如下代碼:
varo1={
foo(){console.log("foo");}
};
varo2={
// .. o2 的定義 ..
};
Object.setPrototypeOf(o2,o1);
// 委託至 `o1.foo()`
o2.foo();// foo
另一種方式:
varo1={
foo(){console.log("foo");}
};
varo2=Object.setPrototypeOf({
// .. o2 的定義 ..
},o1);
// 委託至 `o1.foo()`
o2.foo();// foo
在前面兩個代碼段中,o2和o1之間的關係都出現在o2定義的末尾。更常見的是,o2和o1之間的關係在o2定義的上面被指定,就像在類中,而且在對象字面量的__proto__中也是這樣(參見第二章的「設置[[Prototype]]」)。
警告: 正如展示的那樣,在對象創建之後立即設置[[Prototype]]是合理的。但是在很久之後才改變它一般不是一個好主意,而且經常會導致困惑而非清晰。
Object.assign(..) 靜態函數
許多JavaScript庫/框架都提供將一個對象的屬性拷貝/混合到另一個對象中的工具(例如,jQuery的extend(..))。在這些不同的工具中存在著各種微妙的區別,比如一個擁有undefined值的屬性是否被忽略。
ES6增加了Object.assign(..),它是這些演算法的一個簡化版本。第一個參數是 目標對象 而所有其他的參數是 源對象,它們會按照羅列的順序被處理。對每一個源對象,它自己的(也就是,不是「繼承的」)可枚舉鍵,包括symbol,將會好像通過普通=賦值那樣拷貝。Object.assign(..)返回目標對象。
考慮這種對象構成:
vartarget={},
o1={a:1},o2={b:2},
o3={c:3},o4={d:4};
// 設置只讀屬性
Object.defineProperty(o3,"e",{
value:5,
enumerable:true,
writable:false,
configurable:false
});
// 設置不可枚舉屬性
Object.defineProperty(o3,"f",{
value:6,
enumerable:false
});
o3[Symbol("g")]=7;
// 設置不可枚舉 symbol
Object.defineProperty(o3,Symbol("h"),{
value:8,
enumerable:false
});
Object.setPrototypeOf(o3,o4);
僅有屬性a,b,c,e,和Symbol("g")將被拷貝到target:
Object.assign(target,o1,o2,o3);
target.a;// 1
target.b;// 2
target.c;// 3
Object.getOwnPropertyDescriptor(target,"e");
// { value: 5, writable: true, enumerable: true,
// configurable: true }
Object.getOwnPropertySymbols(target);
// [Symbol("g")]
屬性d,f,和Symbol("h")在拷貝中被忽略了;非枚舉屬性和非自身屬性將會被排除在賦值之外。另外,e作為一個普通屬性賦值被拷貝,而不是作為一個只讀屬性被複制。
在早先一節中,我們展示了使用setPrototypeOf(..)來在對象o2和o1之間建立一個[[Prototype]]關係。這是利用Object.assign(..)的另外一種形式:
varo1={
foo(){console.log("foo");}
};
varo2=Object.assign(
Object.create(o1),
{
// .. o2 的定義 ..
}
);
// 委託至 `o1.foo()`
o2.foo();// foo
注意: Object.create(..)是一個ES5標準工具,它創建一個[[Prototype]]鏈接好的空對象。更多信息參見本系列的 this與對象原型。
Math
ES6增加了幾種新的數學工具,它們協助或填補了常見操作的空白。所有這些操作都可以被手動計算,但是它們中的大多數現在都被原生地定義,這樣JS引擎就可以優化計算的性能,或者進行與手動計算比起來小數精度更高的計算。
與直接的開發者相比,asm.js/轉譯的JS代碼(參見本系列的 非同步與性能)更可能是這些工具的使用者。
三角函數:
cosh(..) - 雙曲餘弦
acosh(..) - 雙曲反餘弦
sinh(..) - 雙曲正弦
asinh(..) - 雙曲反正弦
tanh(..) - 雙曲正切
atanh(..) - 雙曲反正切
hypot(..) - 平方和的平方根(也就是,廣義勾股定理)
算數函數:
cbrt(..) - 立方根
clz32(..) - 計數32位二進位表達中前綴的零
expm1(..) - 與exp(x) - 1相同
log2(..) - 二進位對數(以2為底的對數)
log10(..) - 以10為底的對數
log1p(..) - 與log(x + 1)相同
imul(..) - 兩個數字的32為整數乘法
元函數:
sign(..) - 返回數字的符號
trunc(..) - 僅返回一個數字的整數部分
fround(..) - 舍入到最接近的32位(單精度)浮點數值
Number
重要的是,為了你的程序能夠正常工作,它必須準確地處理數字。ES6增加了一些額外的屬性和函數來輔助常見的數字操作。
兩個在Number上新增的功能只是既存全局函數的引用:Number.parseInt(..)和Number.parseFloat(..)。
靜態屬性
ES6以靜態屬性的形式增加了一些有用的數字常數:
Number.EPSILON - 在任意兩個數字之間的最小值:2^-52(關於為了應對浮點算數運算不精確的問題而將這個值用做容差的講解,參見本系列的 類型與文法 的第二章)
Number.MAX_SAFE_INTEGER - 可以用一個JS數字值明確且「安全地」表示的最大整數:2^53 - 1
Number.MIN_SAFE_INTEGER - 可以用一個JS數字值明確且「安全地」表示的最小整數:-(2^53 - 1)或(-2)^53 + 1.
注意: 關於「安全」整數的更多信息,參見本系列的 類型與文法 的第二章。
Number.isNaN(..) 靜態函數
標準的全局isNaN(..)工具從一開始就壞掉了,因為不僅對實際的NaN值返回true,而且對不是數字的東西也返回true。其原因是它會將參數值強制轉換為數字類型(這可能失敗而導致一個NaN)。ES6增加了一個修復過的工具Number.isNaN(..),它可以正確工作:
vara=NaN,b="NaN",c=42;
isNaN(a);// true
isNaN(b);// true —— 噢!
isNaN(c);// false
Number.isNaN(a);// true
Number.isNaN(b);// false —— 修好了!
Number.isNaN(c);// false
Number.isFinite(..) 靜態函數
看到像isFinite(..)這樣的函數名會誘使人們認為它單純地意味著「不是無限」。但這不十分正確。這個新的ES6工具有更多的微妙之處。考慮如下代碼:
vara=NaN,b=Infinity,c=42;
Number.isFinite(a);// false
Number.isFinite(b);// false
Number.isFinite(c);// true
標準的全局isFinite(..)會強制轉換它收到的參數值,但是Number.isFinite(..)會省略強制轉換的行為:
vara="42";
isFinite(a);// true
Number.isFinite(a);// false
你可能依然偏好強制轉換,這時使用全局isFinite(..)是一個合法的選擇。或者,並且可能是更明智的選擇,你可以使用Number.isFinite(+x),它在將x傳遞前明確地將它強制轉換為數字(參見本系列的 類型與文法 的第四章)。
整數相關的靜態函數
JavaScript數字值總是浮點數(IEEE-754)。所以判定一個數字是否是「整數」的概念與檢查它的類型無關,因為JS沒有這樣的區分。
取而代之的是,你需要檢查這個值是否擁有非零的小數部分。這樣做的最簡單的方法通常是:
x===Math.floor(x);
ES6增加了一個Number.isInteger(..)幫助工具,它可以潛在地判定這種性質,而且效率稍微高一些:
Number.isInteger(4);// true
Number.isInteger(4.2);// false
注意: 在JavaScript中,4,4.,4.0,或4.0000之間沒有區別。它們都將被認為是一個「整數」,因此都會從Number.isInteger(..)中給出true。
另外,Number.isInteger(..)過濾了一些明顯的非整數值,它們在x === Math.floor(x)中可能會被混淆:
Number.isInteger(NaN);// false
Number.isInteger(Infinity);// false
有時候處理「整數」是信息的重點,它可以簡化特定的演算法。由於為了僅留下整數而進行過濾,JS代碼本身不會運行得更快,但是當僅有整數被使用時引擎可以採取幾種優化技術(例如,asm.js)。
因為Number.isInteger(..)對Nan和Infinity值的處理,定義一個isFloat(..)工具並不像!Number.isInteger(..)一樣簡單。你需要這麼做:
functionisFloat(x){
returnNumber.isFinite(x)&&!Number.isInteger(x);
}
isFloat(4.2);// true
isFloat(4);// false
isFloat(NaN);// false
isFloat(Infinity);// false
注意: 這看起來可能很奇怪,但是無窮即不應當被認為是整數也不應當被認為是浮點數。
ES6還定義了一個Number.isSafeInteger(..)工具,它檢查一個值以確保它是一個整數並且在Number.MIN_SAFE_INTEGER-Number.MAX_SAFE_INTEGER的範圍內(包含兩端)。
varx=Math.pow(2,53),
y=Math.pow(-2,53);
Number.isSafeInteger(x-1);// true
Number.isSafeInteger(y+1);// true
Number.isSafeInteger(x);// false
Number.isSafeInteger(y);// false
String
在ES6之前字元串就已經擁有好幾種幫助函數了,但是有更多的內容被加入了進來。
Unicode 函數
在第二章的「Unicode敏感的字元串操作」中詳細討論了String.fromCodePoint(..),String#codePointAt(..),String#normalize(..)。它們被用來改進JS字元串值對Unicode 的支持。
String.fromCodePoint(0x1d49e);// ""
"abd".codePointAt(2).toString(16);// "1d49e"
normalize(..)字元串原型方法用來進行Unicode規範化,它將字元與相鄰的「組合標誌」進行組合,或者將組合好的字元拆開。
一般來說,規範化不會對字元串的內容產生視覺上的影響,但是會改變字元串的內容,這可能會影響length屬性報告的結果,以及用位置訪問字元的行為:
normalize(..)接受一個可選參數值,它用於指定使用的規範化形式。這個參數值必須是下面四個值中的一個:"NFC"(默認),"NFD","NFKC",或者"NFKD"。
注意: 規範化形式和它們在字元串上的效果超出了我們要在這裡討論的範圍。更多細節參見「Unicode規範化形式」(http://www.unicode.org/reports/tr15/)。
String.raw(..) 靜態函數
String.raw(..)工具被作為一個內建的標籤函數來與字元串字面模板(參見第二章)一起使用,取得不帶有任何轉譯序列處理的未加工的字元串值。
這個函數幾乎永遠不會被手動調用,但是將與被標記的模板字面量一起使用:
varstr="bc";
String.raw` a${str}dxE9`;
// " abcdxE9", not " abcdé"
在結果字元串中,`和t是分離的未被加工過的字元,而不是一個轉譯字元序列 `。這對Unicode轉譯序列也是一樣。
repeat(..) 原型函數
在Python和Ruby那樣的語言中,你可以這樣重複一個字元串:
"foo"*3;// "foofoofoo"
在JS中這不能工作,因為*乘法是僅對數字定義的,因此"foo"會被強制轉換為NaN數字。
但是,ES6定義了一個字元串原型方法repeat(..)來完成這個任務:
"foo".repeat(3);// "foofoofoo"
字元串檢驗函數
作為對ES6以前的String#indexOf(..)和String#lastIndexOf(..)的補充,增加了三個新的搜索/檢驗函數:startsWith(..),endsWidth(..),和includes(..)。
varpalindrome="step on no pets";
palindrome.startsWith("step on");// true
palindrome.startsWith("on",5);// true
palindrome.endsWith("no pets");// true
palindrome.endsWith("no",10);// true
palindrome.includes("on");// true
palindrome.includes("on",6);// false
對於所有這些字元串搜索/檢驗方法,如果你查詢一個空字元串"",那麼它將要麼在字元串的開頭被找到,要麼就在字元串的末尾被找到。
警告: 這些方法默認不接受正則表達式作為檢索字元串。關於關閉實施在第一個參數值上的isRegExp檢查的信息,參見第七章的「正則表達式Symbol」。
複習
ES6在各種內建原生對象上增加了許多額外的API幫助函數:
Array增加了of(..)和from(..)之類的靜態函數,以及copyWithin(..)和fill(..)之類的原型函數。
Object增加了is(..)和assign(..)之類的靜態函數。
Math增加了acosh(..)和clz32(..)之類的靜態函數。
Number增加了Number.EPSILON之類的靜態屬性,以及Number.isFinite(..)之類的靜態函數。
String增加了String.fromCodePoint(..)和String.raw(..)之類的靜態函數,以及repeat(..)和includes(..)之類的原型函數。
這些新增函數中的絕大多數都可以被填補(參見ES6 Shim),它們都是受常見的JS庫/框架中的工具啟發的。
關於本文
譯者:@HetfieldJoe
譯文:http://www.jianshu.com/p/e19a4764e9dd
※代碼審查應該關注什麼:性能
※域名劫持資源重載入方案
※《前端架構設計》讀後感
※代碼審查應該關注什麼之一
TAG:前端早讀課 |
※新ANSI、ESDA、JEDEC JS-002 CDM測試標準概覽
※SGU合格速報:明治大學SGJS項目OFFER!
※SGU合格速報:摘3枚明治大學SGJS項目OFFER!
※PHP程序的JSON
※Spring MVC請求及返回JSON數據
※SpriteJS:重新定義Canvas API
※JSON、XML、TOML、CSON、YAML 大比拼
※在Python中使用JSON
※為Python選擇一個更快的JSON庫
※Dota2:北美賽區三預選資格存疑 OpTic、VGJS還有EG真的欽定TI么
※HTML5+CSS3從入門到精通 CSS3及JS媒體查詢詳解
※CSS-in-JS,向Web組件化再邁一大步
※Discuz API JSON 適用於IOS及Android移動端開發
※OHFLYER成為JSSI授權的飛機維修供應商
※ReactJS:我就是想把代碼和HTML混在一起!
※AngularJS中的MVC模式
※幾張圖為你分析HTML、JS與PHP之間的數據傳輸
※#新勢力發售# Air Jordan 5 LANEY JSP | Xsneaker
※Springboot 2.0整合JSP與JSP的熱部署
※JS001工藝變更前後在晚期NSCLC患者中的PK相似性研究