ES6語言特性的總結(2)

scq000發表於2017-03-09

陣列

ES6中對於資料做了進一步的增強,以便能夠更加方便地建立陣列以及運算元組。

建立陣列

Array.of

該方法用於將一組值轉換為陣列。

Array.of(1); [1]
Array.of(3, 21, 22); [3,21,22]複製程式碼

這個方法的出現主要是為了彌補之前陣列建構函式的一些缺陷:

Arry(); // []
Array(3); // [undefined, undefined, undefined]複製程式碼

你會發現在使用單個數值引數的時候,那個引數被構造器作為陣列長度而進行初始化。而兩個引數以上的時候,則返回由引數構成的陣列。而 Array.of() 方法總會建立一個包含所有傳入引數的陣列,而不管引數的數量與型別。

Array.from

該方法通常用於將類似陣列的物件以及可遍歷物件轉換成陣列。你可以將NodeList,Set,Map等等解構進行陣列的轉換。

利用該方法的第二個引數,你可以指定一個回撥函式,用於對陣列進行對映操作。

//arguments為函式傳入的引數
let args = Array.from(arguments, value => value + 1);
//等同於
let args = Array.from(arguments).map(value => value + 1);複製程式碼

該方法的第三個引數是上下文,在對映函式中如果需要使用this,需要手動傳入該引數。

在ES6中, Class 語法允許我們為內建型別(比如 Array)和自定義類新建子類(比如叫 SubArray)。這些子類也會繼承父類的靜態方法,比如 SubArray.from(),呼叫該方法後會返回子類 SubArray 的一個例項,而不是 Array 的例項。

例項方法

fill

fill() 方法能使用特定值填充陣列中的一個或多個元素。

[1,2,3].fill(1); //用1填充陣列所有項 [1,1,1]
[1,2,3].fill(10, 2); //從索引2開始用10填充陣列 [1, 2, 10]
[1,2,3,4].fill(0, 2, 3);//從索引2到索引3之間開始用0填充陣列 [1,2,0,4]複製程式碼

find/findIndex

該方法的引數是一個回撥函式,用於查詢陣列中滿足回撥函式測試的第一個值或者第一個索引(index)。

let numbers = [1,342,342,22, 34, 35];
console.log(numbers.find(n => n > 35));         // 342
console.log(numbers.findIndex(n => n > 33)); // 1複製程式碼

copyWithin

該方法用來複制自身元素,然後填充進陣列裡。

補充

針對可迭代的物件,ES6提供了三個新的方法:entries,keys, values分別用於返回鍵值對、鍵名、鍵值的迭代器,可以使用for...of語法進行訪問。而陣列的鍵名其實就是它的索引值。

let set = new Set();
set.add(1);
set.add(2);
set.add(3);
for(let value of set.entries()) {
    console.log(value);
}

//輸出 [1,1] [2,2] [3,3]複製程式碼

字串

字串的操作層面,ES6提供了模板物件、多行字串的支援。

模板字面量

在ES6中,我們可以使用反引號(` )來包裹普通字串。
在ES5,我們如果要生成一個多行的字串,通常要使用+連字元,而現在只要使用反引號就可以了。

var str = `Courses are provided in MOOC format with course material available online, mostly as videos complemented with exercise and example files.
All throughout the course, a technical expert will be available online to provide help and answer your questions.
Each course takes approximately 6 to 7 hours to complete, depending on your proficiency, and must be completed within one week.`;複製程式碼

另外,我們可以在字串模板中製造替換位,從而使用一些變數來填充我們的模板。

var name = 'scq000';
var str = `Hello, ${name}`; // Hello,scq000複製程式碼

###標籤化模板

模板標籤(template tag)能對模板字面量進行轉換並返回最終的字串值,標籤在模板的起始處被指定。標籤實際上就是一個函式,它被呼叫時接收需要處理的模板字面量資料,然後進行處理後返回一個字串。這個函式的第一個引數是一個陣列,包含被JS解釋過的字面量字串,隨後的引數是每個替換位的解釋值。

function tag(literals, ...substitutions) {
  let result = '';
  console.log(literals);
  console.log(substitutions);
  return result;
}
var name = 'scq000';
var age = 12;

let msg = tag`My name is ${name}, and my age is ${age}.`;複製程式碼

在上面這個例子中,literials被賦值為['My name is ', [, and my age is ], [.]],而substutions則是['scq000', 12],即用來替換的值。你可以在這個函式中,利用這兩個資訊對字串做進一步的加工。

另外,有個內建的String.raw標籤,可以直接獲取模板字面量的原始值,即轉義之前的值。

let msg = String.raw`hello$1\nworld`console.log(msg); //hello$1\nworld複製程式碼

字串例項方法

對於字串的例項方法上,新增了一些比較常用的方法。

  1. includes: 在給定文字存在於字串中的任意位置時會返回 true ,否則返回 false 。
  2. startsWith: 在給定文字出現在字串起始處時返回 true ,否則返回 false 。
  3. endsWith: 在給定文字出現在字串結尾處時返回 true ,否則返回 false 。

需要注意的是,與之前indexOf等方法不同,以上這些例項方法的引數不能傳入正規表示式,否則會丟擲錯誤。

  1. repeat: 接受一個引數作為字串的重複次數,返回一個將初始字串重複指定次數的新字串。

符號

從ES6開始,引入了第6個基本資料型別:符號(Symbol)。 它是一種特殊的、不可變的資料型別,可以作為物件屬性的識別符號使用。

建立符號值

const name = Symbol(); //注意這裡不能用new,因為Symbol是基本資料型別
const aname = Symbol('aname'); //提供的這個引數主要用來除錯
typeof name //"Symbol"複製程式碼

使用符號值

可以在任何能使用“計算屬性名”的場合使用符號。

let firstName = Symbol('first name');
let lastName = Symbol('last name');

let person = {
  [firstName]: 'scq'
};
Object.defineProperty(person, firstName, { writable: false });

Object.defineProperties(person, {
  [lastName]: {
    value: '000',
    writable: false
  }
});複製程式碼

上面的例子,為person物件定義了兩個符號型別屬性,並將它們設為只讀的。利用這種方式,特別適合建立物件私有成員。

暴露內部方法

利用Symbol的一些屬性,可以針對物件的一些內部行為進行操作。

  1. Symbol.iterator: 一個返回物件預設迭代器的方法,使用for...of
  2. Symbol.match: 一個用於對字串進行匹配的方法,也用於確定一個物件是否可以作為正規表示式使用。使用String.prototype.match
  3. Symbol.replace:一個替換匹配字串的子串的方法.使用String.prototype.replace
  4. Symbol.search
  5. Symbol.split
  6. Symbol.hasInstance: 一個確定一個構造器物件識別的物件是否為它的例項的方法。使用 instanceof.
  7. Symbol.isConcatSpreadable: 一個布林值,表明一個物件是否應該flattened為它的陣列元素。使用Array.prototype.concat().
  8. Symbol.unscopables: 擁有和繼承屬性名的一個物件的值被排除在與環境繫結的相關物件外。
  9. Symbol.species: 一個用於建立派生物件的構造器函式。.
  10. Symbol.toPrimitive: 一個將物件轉化為基本資料型別的方法。
  11. Symbol.toStringTag: 用於物件的預設描述的字串值。使用Object.prototype.toString().

功能比較多,就不一一說明了。下面就以iterator來說明一下使用方法:

var iterator = {
  [Symbol.iterator]() {
    return {
      start: 0,
      next() {
        if(this.start < 10) {
          return {value: this.start ++, done: false}
        }else {
          return {value: undefined, done: true}
        }
      }
    }
  }
};

for(var value of iterator) {
  console.log(vlaue);
}複製程式碼

上面的例子利用了Symbol.iterator這個屬性,使得物件iterator獲得了迭代器的能力。因此,可以對這個物件使用for...of的語法進行迭代操作。

Set與Map

ES6中增加了兩個新的資料結構,Set和Map,補充了原本陣列的一些不足之處。Set 是不包含重複值的列表,而Map 則是鍵與相對應的值的集合。

Set

Set是一種無重複值的有序列表。
建立一個Set很簡單,只要使用new關鍵字就可以了。Set的構造器實際上可以接受任何可迭代物件作為引數。在構造器內部,會使用迭代器來提取引數中的值。

let set1 = new Set(); //建立一個空的集合 Set {}
let set2 = new Set([1,2,3]); //建立一個包含三個元素的集合, Set {1, 2, 3}
let set3 = new Set([1,2,3,4,4]); //建立一個去重後的集合, Set {1, 2, 3}複製程式碼

針對Set,主要提供了以下幾個方法:

  1. add: 能向 Set 中新增專案
  2. has: 測試某個值是否存在於 Set 中
  3. delete: 來移除單個值
  4. clear: 來將所有值從 Set 中移除
    還提供了一個size屬性用於判斷集合長度
let set = new Set([1,2,3,4,5,6]);
set.add(3); //由於3已經在集合裡了,並不會新增新項
set.add('nihao'); // Set {1,2,3,4,5,6,'nihao'}
set.has(3); //true
set.delete(3); // Set {1,2,4,5,6,'nihao'}
set.clear(); // Set {}複製程式碼

注意的是,當一個屬性被新增到 set 物件時,它的值也被設為true。而在 Set 內部的比較使用了Object.is()方法,來判斷兩個值是否相等。

Set的遍歷

同陣列一樣,作為可迭代的資料結構,ES6提供了forEach的方法對其進行遍歷。你也可以使用,for...of的語法進行。

let set = new Set(['a','b','c']);
set.forEach((value, key) => console.log('Value: ' + value + ' Key: ' + key));
//Value: a Key: a
//Value: b Key: b
//Value: c Key: c複製程式碼

由於Set的每一項同時被認為鍵和值,因此,key和value其實是一致的。如果想在回撥函式中使用 this ,你可以給 forEach() 傳入一個 this 值作為第三個引數。你也可以使用箭頭函式來達到同等的效果。

轉換成陣列

要將Set轉換成陣列,可以像下面這樣:

let set = new Set([1,2,3,4,5]);
Array.from(set); //[1,2,3,4,5]
[...set]; //[1,2,3,4,5]複製程式碼

使用擴充套件運算子可以更簡單地將 Set 轉換回陣列。

Map

Map與Set相似,資料結構中儲存著鍵值對。例項方法與Set相同的部分是has,delete,clear。你可以呼叫 set() 方法並給它傳遞一個鍵與一個關聯的值,來給 Map 新增項;此後使用鍵名來呼叫 get() 方法便能提取對應的值。

let map = new Map();
map.set('key1', 'value1'); //Map {"key1" => "value1"}
map.set('key2', 'value2'); //Map {"key1" => "value1", "key2" => "value2"}
map.get('key1'); //value1
map.has('key2'); //true
map.delete('key1'); //刪除成功會返回true
map.has('key1'); //false
map.clear(); //清空所有複製程式碼

而對於map的遍歷可以使用forEach語法,其中的回撥函式同樣是接收三個引數:value,key,context。當然context是可選的。

let map = new Map();
map.set('key1', 'value1'); 
map.set('key2', 'value2'); 
map.forEach((value,key) => console.log(value));
//value1, value2複製程式碼

WeakSet和WeakMap

WeakMap和WeakSet一樣,儲存了是物件的弱引用方式。而Set和Weak的例項中,則是採用了強引用的方式,只要SetMap的例項存在,其中所儲存的物件就無法被垃圾回收機制回收,從而無法釋放記憶體。利用WeakSet和WeakMap的弱引用方式,則可以在記憶體管理上有著更加容易優化的空間。

系列三請點這裡


本文對你有幫助?歡迎掃碼加入前端學習小組微信群:

ES6語言特性的總結(2)

相關文章