本人是android開發(fā)的,由于最近React Native的火熱,再加上自己完全不懂JS的語(yǔ)法,俗話說的好"落后就要挨打",雖然不知道誰(shuí)說的,不過很有道理.
學(xué)習(xí)書籍《ECMAScript 6 入門 》
Symbol和Set罚随、Map
Symbol
ES6引入了一種新的原始數(shù)據(jù)類型Symbol屠升,表示獨(dú)一無(wú)二的值汇在。它是JavaScript語(yǔ)言的第七種數(shù)據(jù)類型糙麦,前六種是:Undefined焚廊、Null诽里、布爾值(Boolean)、字符串(String)、數(shù)值(Number)、對(duì)象(Object)苞氮。
Symbol值通過Symbol函數(shù)生成贷帮。這就是說锄禽,對(duì)象的屬性名現(xiàn)在可以有兩種類型垂攘,一種是原來(lái)就有的字符串,另一種就是新增的Symbol類型逸贾。凡是屬性名屬于Symbol類型陨仅,就都是獨(dú)一無(wú)二的津滞,可以保證不會(huì)與其他屬性名產(chǎn)生沖突。
Symbol 作為屬性名,該屬性不會(huì)出現(xiàn)在for...in灼伤、for...of循環(huán)中据沈,也不會(huì)被Object.keys()、Object.getOwnPropertyNames()饺蔑、JSON.stringify()返回。它通過Object.getOwnPropertySymbols方法返回一個(gè)數(shù)組嗜诀,成員是當(dāng)前對(duì)象的所有用作屬性名的 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)其他對(duì)象使用instanceof運(yùn)算符臭埋,判斷是否為該對(duì)象的實(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 ?表示該對(duì)象使用Array.prototype.concat()時(shí)瓢阴,是否可以展開。
Symbol.isConcatSpreadable?屬性等于true或undefined健无,可以展開荣恐。
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)前對(duì)象的構(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對(duì)象不是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)該對(duì)象被String.prototype.replace方法調(diào)用時(shí)医清,會(huì)返回該方法的返回值嘉汰。
Symbol.replace方法會(huì)收到兩個(gè)參數(shù),第一個(gè)參數(shù)是replace方法正在作用的對(duì)象状勤,下面例子是Hello鞋怀,第二個(gè)參數(shù)是替換后的值,上面例子是World持搜。
const x = {};
x[Symbol.replace] = (...s) => console.log(s);
'Hello'.replace(x, 'World') // ["Hello", "World"]
Symbol.search 指向一個(gè)方法密似,當(dāng)該對(duì)象被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)該對(duì)象被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 指向該對(duì)象的默認(rèn)遍歷器方法抛猫。
var myIterable = {};
myIterable[Symbol.iterator] = function* () {
? ? ? yield 1;
? ? ? yield 2;
? ? ? yield 3;
};
[...myIterable] // [1, 2, 3]
Symbol.toPrimitive 指向一個(gè)方法。該對(duì)象被轉(zhuǎn)為原始類型的值時(shí)孩灯,會(huì)調(diào)用這個(gè)方法闺金,返回該對(duì)象對(duì)應(yīng)的原始類型值。
Symbol.toPrimitive被調(diào)用時(shí)峰档,會(huì)接受一個(gè)字符串參數(shù)败匹,表示當(dāng)前運(yùn)算的模式寨昙,一共有三種模式。
Number:該場(chǎng)合需要轉(zhuǎn)成數(shù)值
String:該場(chǎng)合需要轉(zhuǎn)成字符串
Default:該場(chǎng)合可以轉(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è)方法舔哪。在該對(duì)象上面調(diào)用Object.prototype.toString方法時(shí),如果這個(gè)屬性存在槽棍,它的返回值會(huì)出現(xiàn)在toString方法返回的字符串之中捉蚤,表示對(duì)象的類型。也就是說炼七,這個(gè)屬性可以用來(lái)定制[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)置對(duì)象的Symbol.toStringTag屬性值如下。
JSON[Symbol.toStringTag]:'JSON'
Math[Symbol.toStringTag]:'Math'
Module對(duì)象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è)對(duì)象特石。該對(duì)象指定了使用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語(yǔ)法塊不會(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ù)組的對(duì)象)作為參數(shù)推捐,用來(lái)初始化。
Set 書寫格式如下:
const s = new Set(); ?//Set初始化;
var set = new Set([1,2,3,4,4]); // Set初始化并接受一個(gè)數(shù)組(或類似數(shù)組的對(duì)象);
[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():返回鍵值對(duì)的遍歷器
?---- forEach():使用回調(diào)函數(shù)遍歷每個(gè)成員
2.WeakSet
WeakSet結(jié)構(gòu)與Set類似叽奥,也是不重復(fù)的值的集合扔水。但是,它與Set有兩個(gè)區(qū)別朝氓。
首先铭污,WeakSet的成員只能是對(duì)象恋日,而不能是其他類型的值。
其次嘹狞,WeakSet中的對(duì)象都是弱引用岂膳,即垃圾回收機(jī)制不考慮WeakSet對(duì)該對(duì)象的引用,也就是說磅网,如果其他對(duì)象都不再引用該對(duì)象谈截,那么垃圾回收機(jī)制會(huì)自動(dòng)回收該對(duì)象所占用的內(nèi)存,不考慮該對(duì)象還存在于WeakSet之中涧偷。這個(gè)特點(diǎn)意味著簸喂,無(wú)法引用WeakSet的成員,因此WeakSet是不可遍歷的燎潮。
WeakSet可以接受一個(gè)數(shù)組或類似數(shù)組的對(duì)象作為參數(shù)喻鳄。
var ws = new WeakSet();
var a = [[1,2],[3,4]];?
var ws = new WeakSet(a);
注意,是a數(shù)組的成員成為WeakSet的成員确封,而不是a數(shù)組本身除呵。這意味著,數(shù)組的成員只能是對(duì)象爪喘。
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)。它類似于對(duì)象侦鹏,也是鍵值對(duì)的集合诡曙,但是“鍵”的范圍不限于字符串,各種類型的值(包括對(duì)象)都可以當(dāng)作鍵略水。也就是說岗仑,Object結(jié)構(gòu)提供了“字符串—值”的對(duì)應(yīng),Map結(jié)構(gòu)提供了“值—值”的對(duì)應(yīng)聚请,是一種更完善的Hash結(jié)構(gòu)實(shí)現(xiàn)荠雕。如果你需要“鍵值對(duì)”的數(shù)據(jù)結(jié)構(gòu),Map比Object更合適驶赏。
Map實(shí)例的屬性和方法
size屬性:返回Map結(jié)構(gòu)的成員總數(shù)炸卑。
set(key, value)
? ? ? ?set方法設(shè)置key所對(duì)應(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對(duì)應(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ū)別是它只接受對(duì)象作為鍵名(null除外)沉迹,不接受其他類型的值作為鍵名,而且鍵名所指向的對(duì)象害驹,不計(jì)入垃圾回收機(jī)制,不可遍歷鞭呕。
WeakMap與Map在API上的區(qū)別主要是兩個(gè),一是沒有遍歷操作(即沒有key()宛官、values()和entries()方法)葫松,也沒有size屬性;二是無(wú)法清空底洗,即不支持clear方法腋么。這與WeakMap的鍵不被計(jì)入引用、被垃圾回收機(jī)制忽略有關(guān)亥揖。因此珊擂,WeakMap只有四個(gè)方法可用:get()、set()费变、has()摧扇、delete()。