相關文章:【阿里面試】有關symbol的一些知識(1)-基礎知識
【阿里面試】有關symbol的一些知識(2)-實例
【阿里面試】有關symbol的一些知識(3)-內置方法
內置的 Symbol 值
除了定義自己使用的 Symbol 值以外勿侯,ES6 還提供了 11 個內置的 Symbol
值,指向語言內部使用的方法。
1. Symbol.hasInstance
對象的 Symbol.hasInstance
屬性蛔趴,指向一個內部方法。當其他對象使用 instanceof
運算符幅狮,判斷是否為該對象的實例時贡歧,會調用這個方法整胃。比如,foo instanceof Foo
在語言內部拷获,實際調用的是 Foo[Symbol.hasInstance](foo)
。
class MyClass {
[Symbol.hasInstance](foo) {
return foo instanceof Array;
}
}
[1, 2, 3] instanceof new MyClass(); // true
MyClass
是一個類减细,new MyClass()
會返回一個實例匆瓜。該實例的 Symbol.hasInstance
方法,會在進行 instanceof
運算時自動調用未蝌,判斷左側的運算子是否為 Array
的實例
class Even {
static [Symbol.hasInstance](obj) {
return Number(obj) % 2 === 0;
}
}
// 等同于
const Even = {
[Symbol.hasInstance](obj) {
return Number(obj) % 2 === 0;
},
};
1 instanceof Even; // false
2 instanceof Even; // true
12345 instanceof Even; // false
2. Symbol.isConcatSpreadable
對象的 Symbol.isConcatSpreadable
屬性等于一個布爾值驮吱,表示該對象用于 Array.prototype.concat()
時,是否可以展開萧吠。
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']
上面代碼說明左冬,數(shù)組的默認行為是可以展開,Symbol.isConcatSpreadable
默認等于 undefined
纸型。該屬性等于 true 時拇砰,也有展開的效果。
類似數(shù)組的對象正好相反狰腌,默認不展開除破。它的 Symbol.isConcatSpreadable
屬性設為 true,才可以展開琼腔。
let obj = { length: 2, 0: "c", 1: "d" };
["a", "b"].concat(obj, "e"); // ['a', 'b', obj, 'e']
obj[Symbol.isConcatSpreadable] = true;
["a", "b"].concat(obj, "e"); // ['a', 'b', 'c', 'd', 'e']
Symbol.isConcatSpreadable
屬性也可以定義在類里面瑰枫。
class A1 extends Array {
constructor(args) {
super(args);
this[Symbol.isConcatSpreadable] = true;
}
}
class A2 extends Array {
constructor(args) {
super(args);
}
get [Symbol.isConcatSpreadable]() {
return false;
}
}
let a1 = new A1();
a1[0] = 3;
a1[1] = 4;
let a2 = new A2();
a2[0] = 5;
a2[1] = 6;
[1, 2].concat(a1).concat(a2);
// [1, 2, 3, 4, [5, 6]]
注意,Symbol.isConcatSpreadable
的位置差異丹莲,A1 是定義在實例上光坝,A2 是定義在類本身,效果相同甥材。
3. Symbol.species
對象的 Symbol.species
屬性盯另,指向一個構造函數(shù)。創(chuàng)建衍生對象時擂达,會使用該屬性土铺。
class MyArray extends Array {}
const a = new MyArray(1, 2, 3);
const b = a.map((x) => x);
const c = a.filter((x) => x > 1);
b instanceof MyArray; // true
c instanceof MyArray; // true
Symbol.species
屬性就是為了解決這個問題而提供的〗鹤蹋現(xiàn)在,我們可以為 MyArray 設置 Symbol.species
屬性悲敷。
class MyArray extends Array {
// 由于定義了Symbol.species屬性究恤,創(chuàng)建衍生對象時就會使用這個屬性返回的函數(shù),作為構造函數(shù)后德。
static get [Symbol.species]() {
return Array;
}
// 默認的Symbol.species屬性等同于下面的寫法
// static get [Symbol.species]() {
// return this;
// }
}
class MyArray extends Array {
static get [Symbol.species]() {
return Array;
}
}
const a = new MyArray();
const b = a.map((x) => x);
b instanceof MyArray; // false
b instanceof Array; // true
class T1 extends Promise {}
class T2 extends Promise {
static get [Symbol.species]() {
return Promise;
}
}
new T1((r) => r()).then((v) => v) instanceof T1; // true
new T2((r) => r()).then((v) => v) instanceof T2; // false
總之部宿,Symbol.species
的作用在于,實例對象在運行過程中瓢湃,需要再次調用自身的構造函數(shù)時理张,會調用該屬性指定的構造函數(shù)。
它主要的用途是绵患,有些類庫是在基類的基礎上修改的雾叭,那么子類使用繼承的方法時,作者可能希望返回基類的實例落蝙,而不是子類的實例织狐。
4. Symbol.match
對象的 Symbol.match
屬性,指向一個函數(shù)筏勒。當執(zhí)行 str.match(myObject)
時移迫,如果該屬性存在,會調用它管行,返回該方法的返回值厨埋。
String.prototype.match(regexp);
// 等同于
regexp[Symbol.match](this);
class MyMatcher {
[Symbol.match](string) {
return "hello world".indexOf(string);
}
}
"e".match(new MyMatcher()); // 1
5. Symbol.replace
對象的 Symbol.replace
屬性,指向一個方法捐顷,當該對象被 String.prototype.replace
方法調用時荡陷,會返回該方法的返回值。
String.prototype.replace(searchValue, replaceValue);
// 等同于
searchValue[Symbol.replace](this, replaceValue);
const x = {};
x[Symbol.replace] = (...s) => console.log(s);
"Hello".replace(x, "World"); // ["Hello", "World"]
Symbol.replace
方法會收到兩個參數(shù)套菜,第一個參數(shù)是 replace
方法正在作用的對象亲善,上面例子是 Hello,第二個參數(shù)是替換后的值逗柴,上面例子是 World蛹头。
6. Symbol.search
對象的 Symbol.search
屬性,指向一個方法戏溺,當該對象被 String.prototype.search
方法調用時渣蜗,會返回該方法的返回值。
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
7. Symbol.split
對象的 Symbol.split
屬性旷祸,指向一個方法耕拷,當該對象被 String.prototype.split
方法調用時,會返回該方法的返回值托享。
String.prototype.split(separator, limit);
// 等同于
separator[Symbol.split](this, limit);
// 使用Symbol.split方法骚烧,重新定義了字符串對象的split方法的行為浸赫,
class MySplitter {
constructor(value) {
this.value = value;
}
[Symbol.split](string) {
let 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'
8. Symbol.iterator
對象的 Symbol.iterator
屬性,指向該對象的默認遍歷器方法赃绊。
const myIterable = {};
myIterable[Symbol.iterator] = function* () {
yield 1;
yield 2;
yield 3;
};
[...myIterable]; // [1, 2, 3]
對象進行 for...of
循環(huán)時既峡,會調用 Symbol.iterator
方法,返回該對象的默認遍歷器
class Collection {
*[Symbol.iterator]() {
let i = 0;
while (this[i] !== undefined) {
yield this[i];
++i;
}
}
}
let myCollection = new Collection();
myCollection[0] = 1;
myCollection[1] = 2;
for (let value of myCollection) {
console.log(value);
}
// 1
// 2
9. Symbol.toPrimitive
對象的 Symbol.toPrimitive
屬性碧查,指向一個方法运敢。該對象被轉為原始類型的值時,會調用這個方法忠售,返回該對象對應的原始類型值传惠。
Symbol.toPrimitive
被調用時,會接受一個字符串參數(shù)稻扬,表示當前運算的模式卦方,一共有三種模式。
- Number:該場合需要轉成數(shù)值
- String:該場合需要轉成字符串
- Default:該場合可以轉成數(shù)值泰佳,也可以轉成字符串
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'
10. Symbol.toStringTag
對象的 Symbol.toStringTag
屬性愿汰,指向一個方法。在該對象上面調用 Object.prototype.toString
方法時乐纸,如果這個屬性存在,它的返回值會出現(xiàn)在 toString
方法返回的字符串之中摇予,表示對象的類型汽绢。也就是說,這個屬性可以用來定制[object Object]
或[object Array]
中 object
后面的那個字符串侧戴。
// 例一
({ [Symbol.toStringTag]: "Foo" }.toString());
// "[object Foo]"
// 例二
class Collection {
get [Symbol.toStringTag]() {
return "xxx";
}
}
let x = new Collection();
Object.prototype.toString.call(x); // "[object xxx]"
ES6 新增內置對象的 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'
11. Symbol.unscopables
對象的 Symbol.unscopables
屬性,指向一個對象酗宋。該對象指定了使用 with
關鍵字時积仗,哪些屬性會被 with
環(huán)境排除。
Array.prototype[Symbol.unscopables];
// {
// copyWithin: true,
// entries: true,
// fill: true,
// find: true,
// findIndex: true,
// includes: true,
// keys: true
// }
Object.keys(Array.prototype[Symbol.unscopables]);
// ['copyWithin', 'entries', 'fill', 'find', 'findIndex', 'includes', 'keys']
// 沒有 unscopables 時
class MyClass {
foo() {
return 1;
}
}
var foo = function () {
return 2;
};
with (MyClass.prototype) {
foo(); // 1
}
// 有 unscopables 時
class MyClass {
foo() {
return 1;
}
get [Symbol.unscopables]() {
return { foo: true };
}
}
var foo = function () {
return 2;
};
with (MyClass.prototype) {
foo(); // 2
}
上面代碼通過指定 Symbol.unscopables
屬性蜕猫,使得 with
語法塊不會在當前作用域尋找 foo
屬性寂曹,即 foo
將指向外層作用域的變量。
原文:# ECMAScript 6 入門