回憶es6新增api的那些年

Array

在JS中被各類用戶庫擴展得最多的特性之一就是數組類型。ES6在數組上增長許多靜態的和原型(實例)的幫助功能應當並不使人驚訝。javascript

Array.of(..) 靜態函數

Array(..)的構造器有一個盡人皆知的坑:若是僅有一個參數值被傳遞,並且這個參數值是一個數字的話,它並不會製造一個含有一個帶有該數值元素的數組,而是構建一個長度等於這個數字的空數組。這種操做形成了「空值槽」行爲,而這正是JS數組爲人詬病的地方。java

Array.of(..)做爲數組首選的函數型構造器取代了Array(..),由於Array.of(..)沒有那種單數字參數值的狀況。考慮以下代碼:正則表達式

var a = Array( 3 ); a.length; // 3 a[0]; // undefined var b = Array.of( 3 ); b.length; // 1 b[0]; // 3 var c = Array.of( 1, 2, 3 ); c.length; // 3 c; // [1,2,3]

在什麼樣的環境下,你纔會想要是使用Array.of(..)來建立一個數組,而不是使用像c = [1,2,3]這樣的字面語法呢?有兩種可能的狀況。算法

若是你有一個回調,傳遞給它的參數值本應當被包裝在一個數組中時,Array.of(..)就完美地符合條件。這可能不是那麼常見,可是它能夠爲你的癢處撓上一把。數組

另外一種場景是若是你擴展Array構成它的子類,並且但願可以在一個你的子類的實例中建立和初始化元素,好比:安全

class MyCoolArray extends Array { sum() { return this.reduce( function reducer(acc,curr){ return acc + curr; }, 0 ); } } var x = new MyCoolArray( 3 ); x.length; // 3 -- 噢! x.sum(); // 0 -- 噢! var y = [3]; // Array,不是 MyCoolArray y.length; // 1 y.sum(); // `sum` is not a function var z = MyCoolArray.of( 3 ); z.length; // 1 z.sum(); // 3

你不能(簡單地)只建立一個MyCoolArray的構造器,讓它覆蓋Array父構造器的行爲,由於這個父構造器對於實際建立一個規範的數組值(初始化this)是必要的。在MyCoolArray子類上「被繼承」的靜態of(..)方法提供了一個不錯的解決方案。數據結構

Array.from(..) 靜態函數

在JavaScript中一個「類數組對象」是一個擁有length屬性的對象,這個屬性明確地帶有0或更高的整數值。app

在JS中處理這些值出了名地讓人沮喪;將它們變形爲真正的數組曾經是十分常見的作法,這樣各類Array.property方法(map(..)indexOf(..)等等)才能與它一塊兒使用。這種處理一般看起來像:框架

// 類數組對象 var arrLike = { length: 3, 0: "foo", 1: "bar" }; var arr = Array.prototype.slice.call( arrLike );

另外一種slice(..)常常被使用的常見任務是,複製一個真正的數組:異步

var arr2 = arr.slice();

在這兩種狀況下,新的ES6Array.from(..)方法是一種更易懂並且更優雅的方式 —— 也不那麼冗長:

var arr = Array.from( arrLike ); var arrCopy = Array.from( arr );

Array.from(..)會查看第一個參數值是不是一個可迭代對象(參見第三章的「迭代器」),若是是,它就使用迭代器來產生值,並將這些值「拷貝」到將要被返回的數組中。由於真正的數組擁有一個能夠產生這些值的迭代器,因此這個迭代器會被自動地使用。

可是若是你傳遞一個類數組對象做爲Array.from(..)的第一個參數值,它的行爲基本上是和slice()(不帶參數值的!)或apply()相同的,它簡單地循環全部的值,訪問從0開始到length值的由數字命名的屬性。

考慮以下代碼:

var arrLike = {
    length: 4, 2: "foo" }; Array.from( arrLike ); // [ undefined, undefined, "foo", undefined ]

由於在arrLike上不存在位置01,和3,因此對這些值槽中的每個,結果都是undefined值。

你也能夠這樣產生相似的結果:

var emptySlotsArr = [];
emptySlotsArr.length = 4; emptySlotsArr[2] = "foo"; Array.from( emptySlotsArr ); // [ undefined, undefined, "foo", undefined ]

避免空值槽

前面的代碼段中,在emptySlotsArrArray.from(..)調用的結果有一個微妙但重要的不一樣。Array.from(..)從不產生空值槽。

在ES6以前,若是你想要製造一個被初始化爲在每一個值槽中使用實際undefined值(不是空值槽!)的特定長數組,你不得不作一些額外的工做:

var a = Array( 4 ); // 四個空值槽! var b = Array.apply( null, { length: 4 } ); // 四個 `undefined` 值

但如今Array.from(..)使這件事簡單了些:

var c = Array.from( { length: 4 } ); // 四個 `undefined` 值

警告: 使用一個像前面代碼段中的a那樣的空值槽數組能夠與一些數組函數工做,可是另外一些函數會忽略空值槽(好比map(..)等)。你永遠不該該刻意地使用空值槽,由於它幾乎確定會在你的程序中致使奇怪/不可預料的行爲。

映射

Array.from(..)工具還有另一個絕技。第二個參數值,若是被提供的話,是一個映射函數(和普通的Array#map(..)幾乎相同),它在將每一個源值映射/變形爲返回的目標值時調用。考慮以下代碼:

var arrLike = { length: 4, 2: "foo" }; Array.from( arrLike, function mapper(val,idx){ if (typeof val == "string") { return val.toUpperCase(); } else { return idx; } } ); // [ 0, 1, "FOO", 3 ]

注意: 就像其餘接收回調的數組方法同樣,Array.from(..)接收可選的第三個參數值,它將被指定爲做爲第二個參數傳遞的回調的this綁定。不然,this將是undefined

一個使用Array.from(..)將一個8位值數組翻譯爲16位值數組的例子,參見第五章的「類型化數組」。

copyWithin(..) 原型方法

Array#copyWithin(..)是一個對全部數組可用的新修改器方法(包括類型化數組;參加第五章)。copyWithin(..)將數組的一部分拷貝到同一個數組的其餘位置,覆蓋以前存在在那裏的任何東西。

它的參數值是 目標(要被拷貝到的索引位置),開始(拷貝開始的索引位置(含)),和可選的 結束(拷貝結束的索引位置(不含))。若是這些參數值中存在任何負數,那麼它們就被認爲是相對於數組的末尾。

考慮以下代碼:

[1,2,3,4,5].copyWithin( 3, 0 ); // [1,2,3,1,2] [1,2,3,4,5].copyWithin( 3, 0, 1 ); // [1,2,3,1,5] [1,2,3,4,5].copyWithin( 0, -2 ); // [4,5,3,4,5] [1,2,3,4,5].copyWithin( 0, -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(..)方法原生地支持使用一個指定的值來徹底地(或部分地)填充一個既存的數組:

var a = Array( 4 ).fill( undefined ); a; // [undefined,undefined,undefined,undefined]

fill(..)可選地接收 開始 與 結束 參數,它們指示要被填充的數組的一部分,好比:

var a = [ null, null, null, null ].fill( 42, 1, 3 ); a; // [null,42,42,null]

find(..) 原型方法

通常來講,在一個數組中搜索一個值的最多見方法曾經是indexOf(..)方法,若是值被找到的話它返回值的位置索引,沒有找到的話返回-1

var a = [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值,而後它就會中止。由於是由你來定義這個回調函數,因此你就擁有了如何作出匹配的徹底控制權:

var a = [1,2,3,4,5]; a.some( function matcher(v){ return v == "2"; } ); // true a.some( function matcher(v){ return v == 7; } ); // false

但這種方式的缺陷是你只能使用true/false來指示是否找到了合適的匹配值,而不是實際被匹配的值。

ES6的find(..)解決了這個問題。它的工做方式基本上與some(..)相同,除了一旦回調返回一個true/truthy值,實際的數組值就會被返回:

var a = [1,2,3,4,5]; a.find( function matcher(v){ return v == "2"; } ); // 2 a.find( function matcher(v){ return v == 7; // undefined });

使用一個自定義的matcher(..)函數還容許你與對象這樣的複雜值進行匹配:

var points = [
    { x: 10, y: 20 }, { x: 20, y: 30 }, { x: 30, y: 40 }, { x: 40, y: 50 }, { x: 50, y: 60 } ]; points.find( function matcher(point) { return ( point.x % 3 == 0 && point.y % 4 == 0 ); } ); // { x: 30, y: 40 }

注意: 和其餘接收回調的數組方法同樣,find(..)接收一個可選的第二參數。若是它被設置了的話,就將被指定爲做爲第一個參數傳遞的回調的this綁定。不然,this將是undefined

findIndex(..) 原型方法

雖然前一節展現了some(..)如何在一個數組檢索給出一個Boolean結果,和find(..)如何從數組檢索中給出匹配的值,可是還有一種需求是尋找匹配的值的位置索引。

indexOf(..)能夠完成這個任務,可是沒有辦法控制它的匹配邏輯;它老是使用===嚴格等價。因此ES6的findIndex(..)纔是答案:

var points = [ { x: 10, y: 20 }, { x: 20, y: 30 }, { x: 30, y: 40 }, { x: 40, y: 50 }, { x: 50, y: 60 } ]; points.findIndex( function matcher(point) { return ( point.x % 3 == 0 && point.y % 4 == 0 ); } ); // 2 points.findIndex( function matcher(point) { return ( point.x % 6 == 0 && point.y % 7 == 0 ); } ); // -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()的意義上,它是的。考慮以下代碼:

var a = [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的存在值槽。其實際的緣由是,在底層數組迭代器就是以這種方式動做的:

var a = []; 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節),可是帶有兩個重要的例外。

考慮以下代碼:

var x = NaN, y = 0, z = -0; 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屬性:

var o = { foo: 42, [ Symbol( "bar" ) ]: "hello world", baz: true }; Object.getOwnPropertySymbols( o ); // [ Symbol(bar) ]

Object.setPrototypeOf(..) 靜態函數

仍是在第二章中,咱們提到了Object.setPrototypeOf(..)工具,它爲了 行爲委託 的目的(意料之中地)設置一個對象的[[Prototype]](參見本系列的 this與對象原型)。考慮以下代碼:

var o1 = { foo() { console.log( "foo" ); } }; var o2 = { // .. o2 的定義 .. }; Object.setPrototypeOf( o2, o1 ); // 委託至 `o1.foo()` o2.foo(); // foo

另外一種方式:

var o1 = { foo() { console.log( "foo" ); } }; var o2 = Object.setPrototypeOf( { // .. o2 的定義 .. }, o1 ); // 委託至 `o1.foo()` o2.foo(); // foo

在前面兩個代碼段中,o2o1之間的關係都出如今o2定義的末尾。更常見的是,o2o1之間的關係在o2定義的上面被指定,就像在類中,並且在對象字面量的__proto__中也是這樣(參見第二章的「設置[[Prototype]]」)。

警告: 正如展現的那樣,在對象建立以後當即設置[[Prototype]]是合理的。可是在好久以後才改變它通常不是一個好主意,並且常常會致使困惑而非清晰。

Object.assign(..) 靜態函數

許多JavaScript庫/框架都提供將一個對象的屬性拷貝/混合到另外一個對象中的工具(例如,jQuery的extend(..))。在這些不一樣的工具中存在着各類微妙的區別,好比一個擁有undefined值的屬性是否被忽略。

ES6增長了Object.assign(..),它是這些算法的一個簡化版本。第一個參數是 目標對象 而全部其餘的參數是 源對象,它們會按照羅列的順序被處理。對每個源對象,它本身的(也就是,不是「繼承的」)可枚舉鍵,包括symbol,將會好像經過普通=賦值那樣拷貝。Object.assign(..)返回目標對象。

考慮這種對象構成:

var target = {}, 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 );

僅有屬性abce,和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")]

屬性df,和Symbol("h")在拷貝中被忽略了;非枚舉屬性和非自身屬性將會被排除在賦值以外。另外,e做爲一個普通屬性賦值被拷貝,而不是做爲一個只讀屬性被複制。

在早先一節中,咱們展現了使用setPrototypeOf(..)來在對象o2o1之間創建一個[[Prototype]]關係。這是利用Object.assign(..)的另一種形式:

var o1 = { foo() { console.log( "foo" ); } }; var o2 = 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(..),它能夠正確工做:

var a = 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工具備更多的微妙之處。考慮以下代碼:

var a = NaN, b = Infinity, c = 42; Number.isFinite( a ); // false Number.isFinite( b ); // false Number.isFinite( c ); // true

標準的全局isFinite(..)會強制轉換它收到的參數值,可是Number.isFinite(..)會省略強制轉換的行爲:

var a = "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中,44.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(..)NanInfinity值的處理,定義一個isFloat(..)工具並不像!Number.isInteger(..)同樣簡單。你須要這麼作:

function isFloat(x) { return Number.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的範圍內(包含兩端)。

var x = 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 ); // "𝒞" "ab𝒞d".codePointAt( 2 ).toString( 16 ); // "1d49e"

normalize(..)字符串原型方法用來進行Unicode規範化,它將字符與相鄰的「組合標誌」進行組合,或者將組合好的字符拆開。

通常來講,規範化不會對字符串的內容產生視覺上的影響,可是會改變字符串的內容,這可能會影響length屬性報告的結果,以及用位置訪問字符的行爲:

var s1 = "e\u0301"; s1.length; // 2 var s2 = s1.normalize(); s2.length; // 1 s2 === "\xE9"; // true

normalize(..)接受一個可選參數值,它用於指定使用的規範化形式。這個參數值必須是下面四個值中的一個:"NFC"(默認),"NFD""NFKC",或者"NFKD"

注意: 規範化形式和它們在字符串上的效果超出了咱們要在這裏討論的範圍。更多細節參見「Unicode規範化形式」(http://www.unicode.org/reports/tr15/)。

String.raw(..) 靜態函數

String.raw(..)工具被做爲一個內建的標籤函數來與字符串字面模板(參見第二章)一塊兒使用,取得不帶有任何轉譯序列處理的未加工的字符串值。

這個函數幾乎永遠不會被手動調用,可是將與被標記的模板字面量一塊兒使用:

var str = "bc"; String.raw`\ta${str}d\xE9`; // "\tabcd\xE9", not " abcdé"

在結果字符串中,`和t是分離的未被加工過的字符,而不是一個轉譯字符序列\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(..)

var palindrome = "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庫/框架中的工具啓發的。

相關文章
相關標籤/搜索