国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Symbol 的作用

xingqiba / 1188人閱讀

摘要:然而這樣使用有一個(gè)很大的限制在誕生之前,對(duì)象的鍵只能是字符串。如果只是簡(jiǎn)單的使用字符串作為,這將會(huì)有很大的風(fēng)險(xiǎn),因?yàn)樗鼈兊耐耆锌赡芟嗤V辉试S字符串作為,并沒有試圖讓輸出。

Symbols 的出現(xiàn)是為了什么呢?

翻譯自 medium

Symbols 是 JavaScript 最新推出的一種基本類型,它被當(dāng)做對(duì)象屬性時(shí)特別有用,但是有什么是它能做而 String 不能做的呢?

在我們開始探索 Symbols 功能之前,我們先來(lái)看一下被很多開發(fā)者忽略 JavaScript 的特性。

背景:

JavaScript 有兩種值類型,一種是 基本類型 (primitives),一種是 對(duì)象類型 (objects,包含 function 類型),基本類型包括數(shù)字 number (包含 integer,float,Infinity,NaN),布爾值 boolean,字符串 string,undefined,null,盡管 typeof null === "object",null 仍然是一個(gè)基本類型。

基本類型的值是不可變的,當(dāng)然了,存放基本類型值得變量是可以被重新分配的,例如當(dāng)你寫 let x = 1; x++,變量 x 就被重新分配值了,但是你并沒有改變?cè)瓉?lái)的1.

一些語(yǔ)言,例如 c 語(yǔ)言有引用傳遞和值傳遞的概念,JavaScript 也有類似的概念,盡管它傳遞的數(shù)據(jù)類型需要推斷。當(dāng)你給一個(gè) function 傳值的時(shí)候,重新分配值并不會(huì)修改該方法調(diào)用時(shí)的參數(shù)值。然而,假如你修改一個(gè)非基本類型的值,修改值也會(huì)影響原來(lái)的值。

考慮下下面的例子:

function primitiveMutator(val) {
  val = val + 1;
}
let x = 1;
primitiveMutator(x);
console.log(x); // 1
function objectMutator(val) {
  val.prop = val.prop + 1;
}
let obj = { prop: 1 };
objectMutator(obj);
console.log(obj.prop); // 2

基本類型一樣的值永遠(yuǎn)相等(除了奇怪的 NaN ),看看這里:

const first = "abc" + "def";
const second = "ab" + "cd" + "ef";
console.log(first === second); // true

然而,非基本類型的值即使內(nèi)容一樣,但也不相等,看看這里:

const obj1 = { name: "Intrinsic" };
const obj2 = { name: "Intrinsic" };
console.log(obj1 === obj2); // false
// Though, their .name properties ARE primitives:
console.log(obj1.name === obj2.name); // true

對(duì)象扮演了一個(gè) JavaScript 語(yǔ)言的基本角色,它們被到處使用,它們常被用在鍵值對(duì)的存儲(chǔ)。然而這樣使用有一個(gè)很大的限制:在 symbols 誕生之前,對(duì)象的鍵只能是字符串。假如我們?cè)囍褂靡粋€(gè)非字符串當(dāng)做對(duì)象的鍵,就會(huì)被轉(zhuǎn)換為字符串,如下所示:

const obj = {};
obj.foo = "foo";
obj["bar"] = "bar";
obj[2] = 2;
obj[{}] = "someobj";
console.log(obj);
// { "2": 2, foo: "foo", bar: "bar",
     "[object Object]": "someobj" }
注意:稍微離一下題,Map 數(shù)據(jù)結(jié)構(gòu)被創(chuàng)建的目的就是為了應(yīng)對(duì)存儲(chǔ)鍵值對(duì)中,鍵不是字符串的情況。
symbols 是什么?

現(xiàn)在我們知道了什么是基本類型,終于準(zhǔn)備好如何定義什么是 symbols 了。symbols 是一種無(wú)法被重建的基本類型。這時(shí) symbols 有點(diǎn)類似與對(duì)象創(chuàng)建的實(shí)例互相不相等的情況,但同時(shí) symbols 又是一種無(wú)法被改變的基本類型數(shù)據(jù)。這里有一個(gè)例子:

const s1 = Symbol();
const s2 = Symbol();
console.log(s1 === s2); // false

當(dāng)你初始化一個(gè)帶有一個(gè)接收可選字符串參數(shù)的 symbols 時(shí),我們可以來(lái) debug 看下,除此之外看看它會(huì)否影響自身。

const s1 = Symbol("debug");
const str = "debug";
const s2 = Symbol("xxyy");
console.log(s1 === str); // false
console.log(s1 === s2); // false
console.log(s1); // Symbol(debug)
symbols 作為對(duì)象的屬性

symbols 有另一個(gè)很重要的用途,就是用作對(duì)象的 key。這兒有一個(gè) symbols 作為對(duì)象 key 使用的例子:

const obj = {};
const sym = Symbol();
obj[sym] = "foo";
obj.bar = "bar";
console.log(obj); // { bar: "bar" }
console.log(sym in obj); // true
console.log(obj[sym]); // foo
console.log(Object.keys(obj)); // ["bar"]

我們注意到使用 Object.keys() 并沒有返回 symbols,這是為了向后兼容性的考慮。老代碼不兼容 symbols,因此古老的 Object.keys() 不應(yīng)該返回 symbols。

看第一眼,我們可能會(huì)覺得 symbols 這個(gè)特性很適合作為對(duì)象的私有屬性,許多其他語(yǔ)言都要類似的類的隱藏屬性,這一直被認(rèn)為是 JavaScript 的一大短板。不幸的是,還是有可能通過(guò) symbols 來(lái)取到對(duì)象的值,甚至都不用試著獲取對(duì)象屬性就可以得到對(duì)象 key,例如,通過(guò) Reflect.ownKeys() 方法就可以獲取所有的 key,包括 字符串和 symbols,如下所示:

function tryToAddPrivate(o) {
  o[Symbol("Pseudo Private")] = 42;
}
const obj = { prop: "hello" };
tryToAddPrivate(obj);
console.log(Reflect.ownKeys(obj));
        // [ "prop", Symbol(Pseudo Private) ]
console.log(obj[Reflect.ownKeys(obj)[1]]); // 42
注意:現(xiàn)在已經(jīng)有一個(gè)旨在解決 JavaScript 私有屬性的提案,叫做 Private Fields,盡管這并不會(huì)使所有的對(duì)象受益,它仍然對(duì)對(duì)象的實(shí)例有用,Private Fields 在 Chrome 74版本可用。
阻止對(duì)象屬性名沖突

symbols 可能對(duì)對(duì)象的私有屬性沒有直接好處,但是它有另外一個(gè)用途,它在不知道對(duì)象原有屬性名的情況下,擴(kuò)展對(duì)象屬性很有用。

考慮一下當(dāng)兩個(gè)不同的庫(kù)要讀取對(duì)象的一些原始屬性時(shí),或許它們都想要類似的標(biāo)識(shí)符。如果只是簡(jiǎn)單的使用字符串 id 作為 key,這將會(huì)有很大的風(fēng)險(xiǎn),因?yàn)樗鼈兊?key 完全有可能相同。

function lib1tag(obj) {
  obj.id = 42;
}
function lib2tag(obj) {
  obj.id = 369;
}

通過(guò)使用 symbols,不同的庫(kù)在初始化的時(shí)候生成其所需的 symbols,然后就可以在對(duì)象上任意賦值。

const library1property = Symbol("lib1");
function lib1tag(obj) {
  obj[library1property] = 42;
}
const library2property = Symbol("lib2");
function lib2tag(obj) {
  obj[library2property] = 369;
}

這方面 symbols 的確對(duì) JavaScript 有用。然后你或許會(huì)奇怪,不同的庫(kù)進(jìn)行初始化的時(shí)候?yàn)槭裁床皇褂秒S機(jī)字符串,或者使用命名空間呢?

const library1property = uuid(); // random approach
function lib1tag(obj) {
  obj[library1property] = 42;
}
const library2property = "LIB2-NAMESPACE-id"; // namespaced approach
function lib2tag(obj) {
  obj[library2property] = 369;
}

你是對(duì)的,這種方法確實(shí)類似于 symbols 的這一作用,除非兩個(gè)庫(kù)使用相同的屬性名,那就會(huì)有被覆寫的風(fēng)險(xiǎn)。

機(jī)敏的讀者已經(jīng)發(fā)現(xiàn)這兩種方案的效果并不完全相同。我們獨(dú)有的屬性名仍然有一個(gè)缺點(diǎn):它們的 key 很容易被找到,尤其是當(dāng)代碼進(jìn)行遞歸或者系列化對(duì)象,考慮如下的例子:

const library2property = "LIB2-NAMESPACE-id"; // namespaced
function lib2tag(obj) {
  obj[library2property] = 369;
}
const user = {
  name: "Thomas Hunter II",
  age: 32
};
lib2tag(user);
JSON.stringify(user);
// "{"name":"Thomas Hunter II","age":32,"LIB2-NAMESPACE-id":369}"

假如我們使用 symbols 作為屬性名,json 的輸出將不會(huì)包含 symbols,這是為什么呢?因?yàn)?JavaScript 支持 symbols,并不意味著 json 規(guī)范也會(huì)跟著修改。json 只允許字符串作為 key,JavaScript 并沒有試圖讓 json 輸出 symbols。

我們可以簡(jiǎn)單的通過(guò) Object.defineProperty() 來(lái)調(diào)整對(duì)象字符串輸出的 json。

const library2property = uuid(); // namespaced approach
function lib2tag(obj) {
  Object.defineProperty(obj, library2property, {
    enumerable: false,
    value: 369
  });
}
const user = {
  name: "Thomas Hunter II",
  age: 32
};
lib2tag(user);
// "{"name":"Thomas Hunter II",
   "age":32,"f468c902-26ed-4b2e-81d6-5775ae7eec5d":369}"
console.log(JSON.stringify(user));
console.log(user[library2property]); // 369

類似于 symbols,對(duì)象通過(guò)設(shè)置 enumerable 標(biāo)識(shí)符來(lái)隱藏字符串 key,它們都會(huì)被 Object.keys() 隱藏掉,而且都會(huì)被 Reflect.ownKeys() 展示出來(lái),如下所示:

const obj = {};
obj[Symbol()] = 1;
Object.defineProperty(obj, "foo", {
  enumberable: false,
  value: 2
});
console.log(Object.keys(obj)); // []
console.log(Reflect.ownKeys(obj)); // [ "foo", Symbol() ]
console.log(JSON.stringify(obj)); // {}

在這一點(diǎn)上,我們相當(dāng)于重建了 symbols,我們的隱藏字符串和 symbols 都被序列化器隱藏了,屬性也都可以通過(guò) Reflect.ownKeys() 來(lái)獲取,因此他們并不算私有屬性。假設(shè)我們使用命名空間、隨機(jī)字符串等字符串作為對(duì)象的屬性名,我們就可以避免多個(gè)庫(kù)重名的風(fēng)險(xiǎn)。

但是仍然有一點(diǎn)細(xì)微的不同,字符串是不可變的,而 symbols 可以保證永遠(yuǎn)唯一,因此仍然有可能會(huì)有人生成重名的字符串。從數(shù)學(xué)意義上 symbols 提供了一個(gè)字符串沒有的優(yōu)點(diǎn)。

在 Node.js 里面,當(dāng)檢測(cè)一個(gè)對(duì)象(例如使用 console.log()),假如對(duì)象上的一個(gè)方法叫做 inspect,當(dāng)記錄對(duì)象時(shí),該方法會(huì)被調(diào)用并輸出。你可以想象,這種行為并不是每個(gè)人都會(huì)這樣做,被用戶創(chuàng)建的 inspect 方法經(jīng)常會(huì)導(dǎo)致命名沖突,現(xiàn)在 require("util").inspect.custom 提供的 symbol 可以被用在函數(shù)上。inspect 方法在 Node.js v10 被放棄,在 v11 版直接被忽略。現(xiàn)在沒人可以忽然就改變 inspect 方法的行為了。

模擬私有屬性

這里有一個(gè)在對(duì)象上模擬私有屬性的有趣的嘗試。使用了另一個(gè) JavaScript 的新特性:proxy。proxy 會(huì)包住一個(gè)對(duì)象,然后我們就可以跟這個(gè)對(duì)象進(jìn)行各種各樣的交互。

proxy 提供了很多種攔截對(duì)象行為的方式。這里我們感興趣的是讀取對(duì)象屬性的行為。我并不會(huì)完整的解釋 proxy 是如何工作的,所以如果你想要了解的更多,可以查看我們的另一篇文章:JavaScript Object Property Descriptors, Proxies, and Preventing Extension

我們可以使用代理來(lái)展示對(duì)象上可用的屬性。這里我們先創(chuàng)建一個(gè) proxy 來(lái)隱藏兩個(gè)屬性,一個(gè)是字符串 _favColor,另一個(gè)是 symbol 叫 favBook。

let proxy;

{
  const favBook = Symbol("fav book");

  const obj = {
    name: "Thomas Hunter II",
    age: 32,
    _favColor: "blue",
    [favBook]: "Metro 2033",
    [Symbol("visible")]: "foo"
  };

  const handler = {
    ownKeys: (target) => {
      const reportedKeys = [];
      const actualKeys = Reflect.ownKeys(target);

      for (const key of actualKeys) {
        if (key === favBook || key === "_favColor") {
          continue;
        }
        reportedKeys.push(key);
      }

      return reportedKeys;
    }
  };

  proxy = new Proxy(obj, handler);
}

console.log(Object.keys(proxy)); // [ "name", "age" ]
console.log(Reflect.ownKeys(proxy)); // [ "name", "age", Symbol(visible) ]
console.log(Object.getOwnPropertyNames(proxy)); // [ "name", "age" ]
console.log(Object.getOwnPropertySymbols(proxy)); // [Symbol(visible)]
console.log(proxy._favColor); // "blue"

發(fā)現(xiàn) _favColor 屬性很簡(jiǎn)單,只需要閱讀源碼即可,另外,動(dòng)態(tài)的 key 可以通過(guò)暴力破解方式獲得(例如前面的 uuid 例子)。但是對(duì) symbol 屬性,如果你沒有直接的引用,是無(wú)法訪問(wèn)到 Metro 2033 這個(gè)值的。

Node.js 備注:有一個(gè)特性可以破解私有屬性,這個(gè)特性不是 JavaScript 的語(yǔ)言特性,也不存在與其他場(chǎng)景,例如 web 瀏覽器。當(dāng)使用 proxy 時(shí),你可以獲取到對(duì)象隱藏的屬性。這里有一個(gè)破解上面私有屬性的例子:

const [originalObject] = process
  .binding("util")
  .getProxyDetails(proxy);
const allKeys = Reflect.ownKeys(originalObject);
console.log(allKeys[3]); // Symbol(fav book)

我們現(xiàn)在要么修改全局的 Reflect 對(duì)象,要么修改 util 的方法綁定,來(lái)組織他們被某個(gè) Node.js 實(shí)例訪問(wèn)。但這是一個(gè)無(wú)底洞,如果你有興趣深挖,可以看這篇文章:Protecting your JavaScript APIs

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/103266.html

相關(guān)文章

  • ES6學(xué)習(xí)筆記1--let和const命令、解構(gòu)賦值和Symbol

    摘要:和命令命令在聲明所在的塊級(jí)作用域內(nèi)有效。解構(gòu)賦值從數(shù)組和對(duì)象中提取值,對(duì)變量進(jìn)行賦值,這被稱為解構(gòu)。數(shù)值和布爾值的解構(gòu)解構(gòu)賦值時(shí),如果等號(hào)右邊是數(shù)值和布爾值,則會(huì)先轉(zhuǎn)為對(duì)象。默認(rèn)值解構(gòu)賦值允許指定默認(rèn)值。 let和const命令 let命令 在聲明所在的塊級(jí)作用域內(nèi)有效。 只要塊級(jí)作用域內(nèi)存在let命令,它所聲明的變量就綁定(binding)這個(gè)區(qū)域,不再受外部的影響。 在同一個(gè)作用...

    liaosilzu2007 評(píng)論0 收藏0
  • ES6基本語(yǔ)法

    摘要:注意有些數(shù)據(jù)結(jié)構(gòu)是在現(xiàn)有數(shù)據(jù)結(jié)構(gòu)的基礎(chǔ)上計(jì)算生成的,比如的數(shù)組都部署了一下三個(gè)方法,調(diào)用后都返回遍歷器對(duì)象返回一個(gè)遍歷器對(duì)象,用于遍歷鍵名,鍵值組成的數(shù)組。 ES6是什么? JavaScript的第六版,在ES5的基礎(chǔ)上增加了許多特性:箭頭函數(shù)、字符串插值、代理、生成器、結(jié)構(gòu)賦值、塊級(jí)作用域等等。 一、let和const 1.作用:聲明變量 ES6中明確規(guī)定,如果區(qū)塊中存在let和co...

    Jeffrrey 評(píng)論0 收藏0
  • javascript---Symbol類型, 引用類型, 作用

    摘要:指針指針指針重要的時(shí)期說(shuō)三遍由于對(duì)象類型為指針引用在變量復(fù)制方面,基本類型和引用類型也有所不同。在瀏覽器中,全局執(zhí)行環(huán)境被認(rèn)為是對(duì)象。 javascript---Symbol類型, 引用類型, 作用域 javascript的引用類型, 即對(duì)象類型是我們最常用的的類型, 其中有許多讓我們需要注意的地方, 最新的 , ES6 的推出, 使得對(duì)象類型的屬性名不僅僅可以是字符串類型,還可是Si...

    leejan97 評(píng)論0 收藏0
  • ECMAScript6

    摘要:返回布爾值標(biāo)簽?zāi)0蹇梢跃o跟一個(gè)函數(shù)名后邊,該函數(shù)將被調(diào)用來(lái)處理這個(gè)模板字符串。其它情況下返回值為在內(nèi)部,整數(shù)和浮點(diǎn)數(shù)使用同樣的存儲(chǔ)方法,所以和被視為同一個(gè)值。 簡(jiǎn)介 ES6目標(biāo),讓JavaScript變成一個(gè)企業(yè)級(jí)的開發(fā)語(yǔ)言,不僅僅限制與前端頁(yè)面的腳本語(yǔ)言。 標(biāo)準(zhǔn)(Standard): 用于定義與其他事物區(qū)別的一套規(guī)則 實(shí)現(xiàn)(Implementation): 某個(gè)標(biāo)準(zhǔn)的具體實(shí)施/真實(shí)實(shí)...

    MSchumi 評(píng)論0 收藏0
  • ECMAScript6標(biāo)準(zhǔn)入門(一)新增變量與數(shù)據(jù)結(jié)構(gòu)

    摘要:一簡(jiǎn)介與的關(guān)系是的規(guī)格,是的一種實(shí)現(xiàn)另外的方言還有和轉(zhuǎn)碼器命令行環(huán)境安裝直接運(yùn)行代碼命令將轉(zhuǎn)換成命令瀏覽器環(huán)境加入,代碼用環(huán)境安裝,,根目錄建立文件加載為的一個(gè)鉤子設(shè)置完文件后,在應(yīng)用入口加入若有使用,等全局對(duì)象及上方法安裝 一、ECMAScript6 簡(jiǎn)介 (1) 與JavaScript的關(guān)系 ES是JS的規(guī)格,JS是ES的一種實(shí)現(xiàn)(另外的ECMAScript方言還有Jscript和...

    Tangpj 評(píng)論0 收藏0
  • ECMAScript6學(xué)習(xí)筆記

    摘要:筆記和和是塊作用域的,是聲明常量用的。一個(gè)對(duì)象如果要有可被循環(huán)調(diào)用的接口,就必須在的屬性上部署遍歷器生成方法原型鏈上的對(duì)象具有該方法也可。這種方式會(huì)訪問(wèn)注冊(cè)表,其中存儲(chǔ)了已經(jīng)存在的一系列。這種方式與通過(guò)定義的獨(dú)立不同,注冊(cè)表中的是共享的。 ECMAScript6 筆記 let 和 const let和const是塊作用域的 ,const是聲明常量用的。 {let a = 10;} a ...

    CODING 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<