ECMAScript 6學(xué)習(xí)(五)

本人是android開發(fā)的,由于最近React Native的火熱,再加上自己完全不懂JS的語法,俗話說的好"落后就要挨打",雖然不知道誰說的,不過很有道理.

學(xué)習(xí)書籍《ECMAScript 6 入門 》

Symbol和Set、Map


Symbol

ES6引入了一種新的原始數(shù)據(jù)類型Symbol,表示獨(dú)一無二的值。它是JavaScript語言的第七種數(shù)據(jù)類型,前六種是:Undefined、Null、布爾值(Boolean)、字符串(String)、數(shù)值(Number)、對象(Object)。

Symbol值通過Symbol函數(shù)生成。這就是說,對象的屬性名現(xiàn)在可以有兩種類型,一種是原來就有的字符串,另一種就是新增的Symbol類型。凡是屬性名屬于Symbol類型,就都是獨(dú)一無二的,可以保證不會(huì)與其他屬性名產(chǎn)生沖突。

Symbol 作為屬性名,該屬性不會(huì)出現(xiàn)在for...infor...of循環(huán)中,也不會(huì)被Object.keys()、Object.getOwnPropertyNames()、JSON.stringify()返回。它通過Object.getOwnPropertySymbols方法返回一個(gè)數(shù)組,成員是當(dāng)前對象的所有用作屬性名的 Symbol 值。

var obj = {};

var a = Symbol('a');

var b = Symbol('b');

obj[a] = 'Hello';

obj[b] = 'World';

var objectSymbols = Object.getOwnPropertySymbols(obj);

objectSymbols

// [Symbol(a), Symbol(b)]

另一個(gè)新的API,Reflect.ownKeys方法可以返回所有類型的鍵名,包括常規(guī)鍵名和 Symbol 鍵名。

let obj = {

[Symbol('my_key')]: 1,

enum: 2,

nonEnum: 3

};

Reflect.ownKeys(obj)

//? ["enum", "nonEnum", Symbol(my_key)]


Symbol.for(),Symbol.keyFor()

有時(shí),我們希望重新使用同一個(gè)Symbol值,Symbol.for方法可以做到這一點(diǎn)。它接受一個(gè)字符串作為參數(shù),然后搜索有沒有以該參數(shù)作為名稱的Symbol值。如果有,就返回這個(gè)Symbol值,否則就新建并返回一個(gè)以該字符串為名稱的Symbol值。

var s1 = Symbol.for('foo');

var s2 = Symbol.for('foo');

s1 === s2 // true

Symbol.for()Symbol()這兩種寫法,都會(huì)生成新的Symbol。它們的區(qū)別是,前者會(huì)被登記在全局環(huán)境中供搜索,后者不會(huì)。Symbol.for()不會(huì)每次調(diào)用就返回一個(gè)新的 Symbol 類型的值,而是會(huì)先檢查給定的key是否已經(jīng)存在,如果不存在才會(huì)新建一個(gè)值。比如,如果你調(diào)用Symbol.for("cat")30次,每次都會(huì)返回同一個(gè) Symbol 值,但是調(diào)用Symbol("cat")30次,會(huì)返回30個(gè)不同的Symbol值。

Symbol.for("bar") === Symbol.for("bar")

// true

Symbol("bar") === Symbol("bar")

// false

Symbol.keyFor方法返回一個(gè)已登記的 Symbol 類型值的key,未登記的Symbol值,返回undefined.

var s1 = Symbol.for("foo");

Symbol.keyFor(s1) // "foo"

var s2 = Symbol("foo");

Symbol.keyFor(s2) // undefined

需要注意的是,Symbol.for為Symbol值登記的名字,是全局環(huán)境的,可以在不同的 iframe 或 service worker 中取到同一個(gè)值。


內(nèi)置的Symbol值

Symbol.hasInstance ?當(dāng)其他對象使用instanceof運(yùn)算符,判斷是否為該對象的實(shí)例時(shí),會(huì)調(diào)用這個(gè)方法。

class Even {

static [Symbol.hasInstance](obj) {

? ? ?return Number(obj) % 2 === 0;

? ? }

}

1 instanceof Even // false

2 instanceof Even // true

12345 instanceof Even // false


Symbol.isConcatSpreadable ?表示該對象使用Array.prototype.concat()時(shí),是否可以展開。

Symbol.isConcatSpreadable?屬性等于trueundefined,可以展開。

Symbol.isConcatSpreadable 屬性等于false,不可以展開。

let arr1 = ['c', 'd'];

['a', 'b'].concat(arr1, 'e') // ['a', 'b', 'c', 'd', 'e']

arr1 [Symbol.isConcatSpreadable] // undefined

let arr2 = ['c', 'd'];

arr2[Symbol.isConcatSpreadable] = false;

['a', 'b'].concat(arr2, 'e') // ['a', 'b', ['c','d'], 'e']


Symbol.species 指向當(dāng)前對象的構(gòu)造函數(shù)。

class MyArray extends Array {

static get [Symbol.species]() { return Array; }

}

var a = new MyArray(1,2,3);

var mapped = a.map(x => x * x);

mapped instanceof MyArray // false

mapped instanceof Array // true

上面代碼中,由于構(gòu)造函數(shù)被替換成了Array。所以,mapped對象不是MyArray的實(shí)例,而是Array的實(shí)例。


Symbol.match 指向一個(gè)函數(shù)。當(dāng)執(zhí)行str.match(myObject)時(shí),如果該屬性存在,會(huì)調(diào)用它,返回該方法的返回值。

String.prototype.match(regexp)

// 等同于

regexp[Symbol.match](this)

class MyMatcher {

? ?[Symbol.match](string) {

? ? ? ?return 'hello world'.indexOf(string);

? ? }

}

'e'.match(new MyMatcher()) // 1


Symbol.replace?指向一個(gè)方法,當(dāng)該對象被String.prototype.replace方法調(diào)用時(shí),會(huì)返回該方法的返回值。

Symbol.replace方法會(huì)收到兩個(gè)參數(shù),第一個(gè)參數(shù)是replace方法正在作用的對象,下面例子是Hello,第二個(gè)參數(shù)是替換后的值,上面例子是World

const x = {};

x[Symbol.replace] = (...s) => console.log(s);

'Hello'.replace(x, 'World') // ["Hello", "World"]


Symbol.search 指向一個(gè)方法,當(dāng)該對象被String.prototype.search方法調(diào)用時(shí),會(huì)返回該方法的返回值。

String.prototype.search(regexp)

// 等同于

regexp[Symbol.search](this)

class MySearch {

? ? constructor(value) {

? ? ? ? ?this.value = value;

? ? }

? ? ?[Symbol.search](string) {

? ? ? ? ? return string.indexOf(this.value);

? ? ? }

}

'foobar'.search(new MySearch('foo')) // 0


Symbol.split 指向一個(gè)方法,當(dāng)該對象被String.prototype.split方法調(diào)用時(shí),會(huì)返回該方法的返回值。

class MySplitter {

? ? constructor(value) {

? ? ? ? this.value = value;

? ? }

[Symbol.split](string) {

? ?var index = string.indexOf(this.value);

? ?if (index === -1) {

? ? ? ? ?return string;

? ? }

? ?return [

? ? ?string.substr(0, index),

? ? ?string.substr(index + this.value.length)

? ?];

? }

}

'foobar'.split(new MySplitter('foo'))

// ['', 'bar']

'foobar'.split(new MySplitter('bar'))

// ['foo', '']

'foobar'.split(new MySplitter('baz'))

// 'foobar'


Symbol.iterator 指向該對象的默認(rèn)遍歷器方法。

var myIterable = {};

myIterable[Symbol.iterator] = function* () {

? ? ? yield 1;

? ? ? yield 2;

? ? ? yield 3;

};

[...myIterable] // [1, 2, 3]


Symbol.toPrimitive 指向一個(gè)方法。該對象被轉(zhuǎn)為原始類型的值時(shí),會(huì)調(diào)用這個(gè)方法,返回該對象對應(yīng)的原始類型值。

Symbol.toPrimitive被調(diào)用時(shí),會(huì)接受一個(gè)字符串參數(shù),表示當(dāng)前運(yùn)算的模式,一共有三種模式。

Number:該場合需要轉(zhuǎn)成數(shù)值

String:該場合需要轉(zhuǎn)成字符串

Default:該場合可以轉(zhuǎn)成數(shù)值,也可以轉(zhuǎn)成字符串

let obj = {

[Symbol.toPrimitive](hint) {

? ? ?switch (hint) {

? ? ? ? ? ? ? case 'number':

? ? ? ? ? ? ? ? ? ? ? ?return 123;

? ? ? ? ? ? ? case 'string':

? ? ? ? ? ? ? ? ? ? ? ?return 'str';

? ? ? ? ? ? ? case 'default':

? ? ? ? ? ? ? ? ? ? ? ? return 'default';

? ? ? ? ? ? ? ?default:

? ? ? ? ? ? ? ? ? ? ? ? throw new Error();

? ? ? ? ? ? }

? ? ? ?}

};

2 * obj // 246

3 + obj // '3default'

obj == 'default' // true

String(obj) // 'str'


Symbol.toStringTag 指向一個(gè)方法。在該對象上面調(diào)用Object.prototype.toString方法時(shí),如果這個(gè)屬性存在,它的返回值會(huì)出現(xiàn)在toString方法返回的字符串之中,表示對象的類型。也就是說,這個(gè)屬性可以用來定制[object Object][object Array]object后面的那個(gè)字符串。

class Collection {

? ? get [Symbol.toStringTag]() {

? ? ? ? ? ?return 'xxx';

? ? ?}

}

var x = new Collection();

Object.prototype.toString.call(x) // "[object xxx]"

ES6新增內(nèi)置對象的Symbol.toStringTag屬性值如下。

JSON[Symbol.toStringTag]:'JSON'

Math[Symbol.toStringTag]:'Math'

Module對象M[Symbol.toStringTag]:'Module'

ArrayBuffer.prototype[Symbol.toStringTag]:'ArrayBuffer'

DataView.prototype[Symbol.toStringTag]:'DataView'

Map.prototype[Symbol.toStringTag]:'Map'

Promise.prototype[Symbol.toStringTag]:'Promise'

Set.prototype[Symbol.toStringTag]:'Set'

%TypedArray%.prototype[Symbol.toStringTag]:'Uint8Array'等

WeakMap.prototype[Symbol.toStringTag]:'WeakMap'

WeakSet.prototype[Symbol.toStringTag]:'WeakSet'

%MapIteratorPrototype%[Symbol.toStringTag]:'Map Iterator'

%SetIteratorPrototype%[Symbol.toStringTag]:'Set Iterator'

%StringIteratorPrototype%[Symbol.toStringTag]:'String Iterator'

Symbol.prototype[Symbol.toStringTag]:'Symbol'

Generator.prototype[Symbol.toStringTag]:'Generator'

GeneratorFunction.prototype[Symbol.toStringTag]:'GeneratorFunction'


Symbol.unscopables 指向一個(gè)對象。該對象指定了使用with關(guān)鍵字時(shí),哪些屬性會(huì)被with環(huán)境排除。

// 沒有 unscopables 時(shí)

?class MyClass {

? ? ?foo() { return 1; }

}

var foo = function () { return 2; };

with (MyClass.prototype) {

? ? ?foo(); // 1

}


// 有 unscopables 時(shí)

class MyClass {

foo() { return 1; }

? ?get [Symbol.unscopables]() {

? ? ? return { foo: true };

? ? }

}

var foo = function () { return 2; };

with (MyClass.prototype) {

? ? foo(); // 2

}

上面代碼通過指定Symbol.unscopables屬性,使得with語法塊不會(huì)在當(dāng)前作用域?qū)ふ?b>foo屬性,即foo將指向外層作用域的變量。


Set和Map

這兩個(gè)數(shù)據(jù)結(jié)構(gòu)我就不多說和java差不多.

1.Set

Set 類似于數(shù)組,但是成員的值都是唯一的,沒有重復(fù)的值。Set 函數(shù)可以接受一個(gè)數(shù)組(或類似數(shù)組的對象)作為參數(shù),用來初始化。

Set 書寫格式如下:

const s = new Set(); ?//Set初始化;

var set = new Set([1,2,3,4,4]); // Set初始化并接受一個(gè)數(shù)組(或類似數(shù)組的對象);

[2,3,5,4,5,2,2].forEach (x => s.add(x)); // Set通過add添加數(shù)據(jù)

Set實(shí)例的屬性和方法

屬性:

?---- Set.prototype.constructor:構(gòu)造函數(shù),默認(rèn)就是Set函數(shù)。

?---- Set.prototype.size:返回Set實(shí)例的成員總數(shù)。

方法:

-- 操作方法(用于操作數(shù)據(jù))

?---- add(value):添加某個(gè)值,返回Set結(jié)構(gòu)本身。

?---- delete(value):刪除某個(gè)值,返回一個(gè)布爾值,表示刪除是否成功。

?---- has(value):返回一個(gè)布爾值,表示該值是否為Set的成員。

?---- clear():清除所有成員,沒有返回值。


-- 遍歷方法(用于遍歷成員)

?---- keys():返回鍵名的遍歷器

?---- values():返回鍵值的遍歷器

?---- entries():返回鍵值對的遍歷器

?---- forEach():使用回調(diào)函數(shù)遍歷每個(gè)成員


2.WeakSet

WeakSet結(jié)構(gòu)與Set類似,也是不重復(fù)的值的集合。但是,它與Set有兩個(gè)區(qū)別。

首先,WeakSet的成員只能是對象,而不能是其他類型的值。

其次,WeakSet中的對象都是弱引用,即垃圾回收機(jī)制不考慮WeakSet對該對象的引用,也就是說,如果其他對象都不再引用該對象,那么垃圾回收機(jī)制會(huì)自動(dòng)回收該對象所占用的內(nèi)存,不考慮該對象還存在于WeakSet之中。這個(gè)特點(diǎn)意味著,無法引用WeakSet的成員,因此WeakSet是不可遍歷的。

WeakSet可以接受一個(gè)數(shù)組或類似數(shù)組的對象作為參數(shù)。

var ws = new WeakSet();

var a = [[1,2],[3,4]];?

var ws = new WeakSet(a);

注意,是a數(shù)組的成員成為WeakSet的成員,而不是a數(shù)組本身。這意味著,數(shù)組的成員只能是對象。

WeakSet 結(jié)構(gòu)有以下三個(gè)方法。

?---- WeakSet.prototype.add(value):向WeakSet實(shí)例添加一個(gè)新成員。

?---- WeakSet.prototype.delete(value):清除WeakSet實(shí)例的指定成員。

?---- WeakSet.prototype.has(value):返回一個(gè)布爾值,表示某個(gè)值是否在.


3.Map

Map數(shù)據(jù)結(jié)構(gòu)。它類似于對象,也是鍵值對的集合,但是“鍵”的范圍不限于字符串,各種類型的值(包括對象)都可以當(dāng)作鍵。也就是說,Object結(jié)構(gòu)提供了“字符串—值”的對應(yīng),Map結(jié)構(gòu)提供了“值—值”的對應(yīng),是一種更完善的Hash結(jié)構(gòu)實(shí)現(xiàn)。如果你需要“鍵值對”的數(shù)據(jù)結(jié)構(gòu),Map比Object更合適。

Map實(shí)例的屬性和方法

size屬性:返回Map結(jié)構(gòu)的成員總數(shù)。


set(key, value)

? ? ? ?set方法設(shè)置key所對應(yīng)的鍵值,然后返回整個(gè)Map結(jié)構(gòu)。如果key已經(jīng)有值,則鍵值會(huì)被更新,否則就新生成該鍵。

? ? ? ?set方法返回的是Map本身,因此可以采用鏈?zhǔn)綄懛ā?br>

let map = new Map()

.set(1, 'a')

.set(2, 'b')

.set(3, 'c');


get(key)

? ? ? ? get方法讀取key對應(yīng)的鍵值,如果找不到key,返回undefined

var m = new Map();

var hello = function() {console.log("hello");}

m.set(hello, "Hello ES6!") // 鍵是函數(shù)

m.get(hello)? // Hello ES6!


has(key)

? ? ? ? has方法返回一個(gè)布爾值,表示某個(gè)鍵是否在Map數(shù)據(jù)結(jié)構(gòu)中。

var m= new Map();

m.set("edition",6);

m.has("edition") // true

m.has("years") ?// false


delete(key)

? ? ? ? delete方法刪除某個(gè)鍵,返回true。如果刪除失敗,返回false。

var m = new Map();

m.set(undefined, "nah");

m.has(undefined)? ? // true

m.delete(undefined)

m.has(undefined)? ? ? // false


clear()

? ? ? ? clear方法清除所有成員,沒有返回值。


Map遍歷方法

?---- keys():返回鍵名的遍歷器。

?---- values():返回鍵值的遍歷器。

?---- entries():返回所有成員的遍歷器。

?---- forEach():遍歷Map的所有成員。


4.WeakMap

WeakMap結(jié)構(gòu)與Map結(jié)構(gòu)基本類似,唯一的區(qū)別是它只接受對象作為鍵名(null除外),不接受其他類型的值作為鍵名,而且鍵名所指向的對象,不計(jì)入垃圾回收機(jī)制,不可遍歷。

WeakMapMap在API上的區(qū)別主要是兩個(gè),一是沒有遍歷操作(即沒有key()、values()entries()方法),也沒有size屬性;二是無法清空,即不支持clear方法。這與WeakMap的鍵不被計(jì)入引用、被垃圾回收機(jī)制忽略有關(guān)。因此,WeakMap只有四個(gè)方法可用:get()set()、has()delete()。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一、let 和 constlet:變量聲明, const:只讀常量聲明(聲明的時(shí)候賦值)。 let 與 var 的...
    dadage456閱讀 837評論 0 0
  • //Clojure入門教程: Clojure – Functional Programming for the J...
    葡萄喃喃囈語閱讀 4,069評論 0 7
  • 1.概述 ES5的對象屬性名都是字符串,這容易造成屬性名的沖突。比如,你使用了一個(gè)他人提供的對象,但又想為這個(gè)對象...
    趙然228閱讀 883評論 2 10
  • [TOC] 參考阮一峰的ECMAScript 6 入門參考深入淺出ES6 let和const let和const都...
    郭子web閱讀 1,915評論 0 1
  • 強(qiáng)大的for-of循環(huán) ES6不會(huì)破壞你已經(jīng)寫好的JS代碼。目前看來,成千上萬的Web網(wǎng)站依賴for-in循環(huán),其...
    Awe閱讀 7,588評論 2 7

友情鏈接更多精彩內(nèi)容