欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JS中Symbol類型的介紹與基本用法

 更新時間:2024年04月10日 09:42:21   作者:想做后端的前端  
Symbol是一種特殊的、不可變的數(shù)據(jù)類型,可以作為對象屬性的標(biāo)識符使用,表示獨一無二的值,這篇文章主要給大家介紹了關(guān)于JS中Symbol類型的介紹與基本用法的相關(guān)資料,需要的朋友可以參考下

1、 引入Symbol類型的背景

ES5 的對象屬性名都是字符串,這容易造成屬性名沖突的問題

舉例: 使用別人的模塊/對象, 又想為之添加新的屬性,這就容易使得新屬性名與原有屬性名沖突

2、Symbol類型簡介

symbol是一種原始數(shù)據(jù)類型

  • 其余原始類型: 未定義(undefined) 、 空值(null)、布爾值(boolean)、字符串(string)、數(shù)值(number)、對象(object)
  • symbol表示獨一無二的值
  • symbol類型的"真實值"無法獲取,也就是說Symbol類型沒有對應(yīng)的字面量
  • symbol類型的意義在于區(qū)分彼此和不重復(fù),不在于真實值

Symbol()是一種原生函數(shù)

  • 常見的原生函數(shù)有String()、Number()、Boolean()、Array()、Object()、Function()、RegExp()、Date()、Error()、Symbol()

3、基本用法

符號需要使用Symbol()函數(shù)初始化。

let sym = Symbol();
// 因為符號本身是原始類型,所以typeof操作符對符號返回symbol
console.log(typeof sym); // symbol

調(diào)用Symbol()函數(shù)時,也可以傳入一個字符串參數(shù)作為對符號的描述,將來可以通過這個字符串來調(diào)試代碼。但是,這個字符串參數(shù)與符號定義或標(biāo)識完全無關(guān):

// Symbol的值是唯一的,不會出現(xiàn)相同值的常量
let genericSymbol = Symbol();
let otherGenericSymbol = Symbol();
console.log(genericSymbol == otherGenericSymbol); // false

// 可以傳入一個字符串參數(shù)作為對符號的描述
let fooSymbol = Symbol('foo');
let otherFooSymbol = Symbol('foo');
console.log(fooSymbol == otherFooSymbol); // false

符號沒有字面量語法。 按照規(guī)范,只要創(chuàng)建Symbol()實例并將其用作對象的新屬性,就可以保證它不會覆蓋已有的對象屬性,無論是符號屬性還是字符串屬性。

let genericSymbol = Symbol();
console.log(genericSymbol); // Symbol()

let fooSymbol = Symbol('foo');
console.log(fooSymbol); // Symbol(foo)

Symbol()函數(shù)不能與new關(guān)鍵字一起作為構(gòu)造函數(shù)使用。

這樣做是為了避免創(chuàng)建符號包裝對象,像使用Boolean、String或Number那樣,它們都支持構(gòu)造函數(shù)且可用于初始化包含原始值的包裝對象。

let myBoolean = new Boolean();
console.log(typeof myBoolean); // "object"

let myString = new String();
console.log(typeof myString); // "object"

let myNumber = new Number();
console.log(typeof myNumber); // "object"

let mySymbol = new Symbol(); // 報錯,TypeError
console.log(mySymbol);

如果想使用符號包裝對象,可以借用Object()函數(shù):

let mySymbol = Symbol();
let myWarppedSymbol = Object(mySymbol);
console.log(typeof myWarppedSymbol); // "object"

4、 使用全局符號注冊表

如果運行時的不同部分需要共享和重用符號實例,那么可以用一個字符串作為鍵,在全局符號注冊表中創(chuàng)建并重用符號。
Symbol.for()方法:

let fooGlobalSymbol = Symbol.for('foo');
console.log(typeof fooGlobalSymbol); // symbol

Symbol.for()對每個字符串鍵都執(zhí)行冪等操作。

第一次使用某個字符串調(diào)用時,它會檢查全局運行時注冊表,發(fā)現(xiàn)不存在對應(yīng)的符號,于是就會生成一個新符號實例并添加到注冊表中。
后續(xù)使用相同字符串的調(diào)用同樣會檢查注冊表,發(fā)現(xiàn)存在與該字符串對應(yīng)的符號,然后就會返回該符號實例。

// 創(chuàng)建新符號
let fooGlobalSymbol = Symbol.for('foo');
// 重用已有符號
let otherFooGlobalSymbol = Symbol.for('foo');

console.log(fooGlobalSymbol === otherFooGlobalSymbol); // true

采用相同符號,在全局注冊表中定義的符號跟使用Symbol()定義的符號也不等同:

// 使用Symbol()定義
let localSymbol = Symbol('foo');
// 使用全局注冊表定義
let globalSymbol = Symbol.for('foo');

console.log(localSymbol === globalSymbol); // false

全局注冊表中的符號必須使用字符串鍵來創(chuàng)建,因此作為參數(shù)傳給Symbol.for()的任何值都會被轉(zhuǎn)換為字符串。

注冊表中使用的鍵同時也會被用作符號描述。

let emptyGlobalSymbol = Symbol.for();
console.log(emptyGlobalSymbol); // Symbol(undefined)

使用Symbol.keyFor()來查詢?nèi)肿员?,這個方法接收符號,返回該全局符號對應(yīng)的字符串鍵。如果查詢的不是全局符號,則返回undefined。

// 創(chuàng)建全局符號
let s = Symbol.for('foo');
console.log(Symbol.keyFor(s)); // foo

// 創(chuàng)建普通符號
let s2 = Symbol('bar');
console.log(Symbol.keyFor(s2)); // undefined

如果傳給Symbol.keyFor()的不是符號,則該方法拋出TypeError。

Symbol.keyFor(123); // TypeError: 123 is not a symbol

5、 使用符號作為屬性

凡是可以使用字符串或數(shù)值作為屬性的地方,都可以使用符號。

包括對象字面量屬性和 Object.defineProperty(obj, prop, descriptor) / Object.defineProperties() 定義的屬性。

對象字面量只能在計算屬性語法中使用符號作為屬性。

let s1 = Symbol('foo'),
    s2 = Symbol('bar'),
    s3 = Symbol('baz'),
    s4 = Symbol('qux');

let o = {
    // [屬性],會對屬性進(jìn)行讀取,并且轉(zhuǎn)換成字符串。[s1]是讀取了Symbol的字符串鍵'foo'
    [s1]: 'foo val'
};
// 或 o[s1] = 'foo val';
console.log(o); // { [Symbol(foo)]: 'foo val' }

Object.defineProperty(o, s2, { value: 'bar val' });
console.log(o); // {Symbol(foo): foo val, Symbol(bar): bar val}

Object.defineProperties(o, {
    [s3]: { value: 'baz val' },
    [s4]: { value: 'qux val' }
});
console.log(o); // {Symbol(foo): foo val, Symbol(bar): baz val,
                //  Symbol(foo): foo val, Symbol(bar): qux val}

let s1 = Symbol('foo'),
    s2 = Symbol('bar');

let o = {
    [s1]: 'foo val',
    [s2]: 'bar val',
    baz: 'baz val',
    qux: 'qux val'
};

// Object.getOwnPropertySymbols()返回對象實例的符號屬性數(shù)組
console.log(Object.getOwnPropertySymbols(o)); // [ Symbol(foo), Symbol(bar) ]

// Object.getOwnPropertyNames()返回對象實例的常規(guī)屬性數(shù)組
console.log(Object.getOwnPropertyNames(o)); // [ 'baz', 'qux' ]

// Object.getOwnPropertyDescriptors()會返回同時包含常規(guī)和符號屬性描述符的對象
console.log(Object.getOwnPropertyDescriptors(o));
// {
//     baz: {
//       value: 'baz val',
//       writable: true,
//       enumerable: true,
//       configurable: true
//     },
//     qux: {
//       value: 'qux val',
//       writable: true,
//       enumerable: true,
//       configurable: true
//     },
//     [Symbol(foo)]: {
//       value: 'foo val',
//       writable: true,
//       enumerable: true,
//       configurable: true
//     },
//     [Symbol(bar)]: {
//       value: 'bar val',
//       writable: true,
//       enumerable: true,
//       configurable: true
//     }
//   }

// Reflect.ownKeys()會返回兩種類型的鍵
console.log(Reflect.ownKeys(o)); // [ 'baz', 'qux', Symbol(foo), Symbol(bar) ]

注意:Object.getOwnPropertyNames()和Object.getOwnProperty-Symbols()兩個方法的返回值彼此互斥。

因為符號屬性是對內(nèi)存中符號的一個引用,所以直接創(chuàng)建并用作屬性的符號不會丟失。

但是,如果沒有顯式地保存對這些屬性的引用,那么必須遍歷對象的所有符號屬性才能找到相應(yīng)的屬性鍵。

let o = {
    [Symbol('foo')]: 'foo val',
    [Symbol('bar')]: 'bar val'
};
console.log(o); // { [Symbol(foo)]: 'foo val', [Symbol(bar)]: 'bar val' }

let barSymbol = Object.getOwnPropertySymbols(o).find((Symbol) => 
				Symbol.toString().match(/bar/));
console.log(barSymbol); // Symbol(bar)

6、 所有屬性

屬性含義
Symbol.asyncIterator符號指定了一個對象的默認(rèn)異步迭代器。如果一個對象設(shè)置了這個屬性,它就是異步可迭代對象,可用于for await…of循環(huán)。
Symbol.prototype.descriptiondescription 是一個只讀屬性,它會返回 Symbol 對象的可選描述的字符串。
Symbol.hasInstance用于判斷某對象是否為某構(gòu)造器的實例。因此你可以用它自定義 instanceof 操作符在某個類上的行為。
Symbol.isConcatSpreadable用于配置某對象作為Array.prototype.concat()方法的參數(shù)時是否展開其數(shù)組元素。
Symbol.iterator為每一個對象定義了默認(rèn)的迭代器。該迭代器可以被 for…of 循環(huán)使用。
Symbol.match指定了匹配的是正則表達(dá)式而不是字符串。String.prototype.match() 方法會調(diào)用此函數(shù)
Symbol.matchAll內(nèi)置通用(well-known)符號指定方法返回一個迭代器,該迭代器根據(jù)字符串生成正則表達(dá)式的匹配項。此函數(shù)可以被 String.prototype.matchAll() 方法調(diào)用。
Symbol.replace這個屬性指定了當(dāng)一個字符串替換所匹配字符串時所調(diào)用的方法。
Symbol.search指定了一個搜索方法,這個方法接受用戶輸入的正則表達(dá)式,返回該正則表達(dá)式在字符串中匹配到的下標(biāo),這個方法由以下的方法來調(diào)用 String.prototype.search()。
Symbol.species知名的 Symbol.species 是個函數(shù)值屬性,其被構(gòu)造函數(shù)用以創(chuàng)建派生對象。
Symbol.split指向 一個正則表達(dá)式的索引處分割字符串的方法。這個方法通過 String.prototype.split() 調(diào)用。
Symbol.toPrimitive是內(nèi)置的 symbol 屬性,其指定了一種接受首選類型并返回對象原始值的表示的方法。它被所有的強類型轉(zhuǎn)換制算法優(yōu)先調(diào)用。
Symbol.toStringTag內(nèi)置通用(well-known)symbol 是一個字符串值屬性,用于創(chuàng)建對象的默認(rèn)字符串描述。它由 Object.prototype.toString() 方法內(nèi)部訪問。
Symbol.unscopables指用于指定對象值,其對象自身和繼承的從關(guān)聯(lián)對象的 with 環(huán)境綁定中排除的屬性名稱。

附:Symbol的使用場景

1、作為對象屬性 當(dāng)一個復(fù)雜對象中含有多個屬性的時候,很容易將某個屬性名覆蓋掉,利用 Symbol 值作為屬性名可以很好的避免這一現(xiàn)象

const name = Symbol('name');
const obj = {
    [name]: 'ClickPaas',
}

2、ES6 中的類是沒有 private 關(guān)鍵字來聲明類的私有方法和私有變量的,但是我們可以利用 Symbol 的唯一性來模擬

const speak = Symbol();
class Person {
    [speak]() {
        console.log(123)
    }
}
let person = new Person()
console.log(person[speak]())

因為使用者無法在外部創(chuàng)建出一個相同的 speak,所以就無法調(diào)用該方法

總結(jié) 

到此這篇關(guān)于JS中Symbol類型的介紹與基本用法的文章就介紹到這了,更多相關(guān)JS Symbol類型用法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論