亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

深入了解JavaScript中的Symbol的使用方法

2019-11-20 11:58:36
字體:
來源:轉載
供稿:網友

Symbol 是什么?

Symbols 不是圖標,也不是指在代碼中可以使用小圖片:

2015728114935470.jpg (291×49)

也不是指代其他一些東西的語法。那么,Symbol 到究竟是什么呢?
七種數據類型

JavaScript 在 1997 年被標準化時,就有 6 種數據類型,直到 ES6 出現之前,程序中的變量一定是以下 6 種數據類型之一:

    Undefined
    Null
    Boolean
    Number
    String
    Object

每種數據類型都是一系列值的組合,前面 5 種數據類型值的數量都是有限的。Boolean 類型只有兩個值:true 和 false,為 Boolean 類型的變量賦值時,并不會產生新的值(共享了true 和 false 這兩個值)。對于 Number 和 String 來說,它們的值則多得多了,標準的說法是有 18,437,736,874,454,810,627 個 Number 類型的值(包括 NAN)。String 類型的個數就難以統計了,我原以為是 (2144,115,188,075,855,872 ? 1) ÷ 65,535…不過也許我算錯了。

對象值的個數是無限的,每個對象都是獨一無二的,每次打開一個網頁,都創建了一系列的對象。

ES6 中的 Symbol 也是一種數據類型,但是不是字符串,也不是對象,而是一種新的數據類型:第七種數據類型。

下面我們來看一個場景,也許 Symbol 能派上用場。
一個布爾值引出的問題

有時,把一些屬于其他對象的數據暫存在另一個對象中是非常方便的。例如,假設你正在編寫一個 JS 庫,使用 CSS 中的 transition 來讓一個 DOM 元素在屏幕上飛奔,你已經知道不能同時將多個 transition 應用在同一個 div 上,否則將使得動畫非常不美觀,你也確實有辦法來解決這個問題,但是首先你需要知道該 div 是否已經在移動中。

怎么解決這個問題呢?

其中一個方法是使用瀏覽器提供的 API 來探測元素是否處于動畫狀態,但殺雞焉用牛刀,在將元素設置為移動時,你的庫就知道了該元素正在移動。

你真正需要的是一種機制來跟蹤哪些元素正在移動,你可以將正在移動的元素保存在一個數組中,每次要為一個元素設置動畫時,首先檢查一下這個元素是否已經在這個列表中。

啊哈,但是如果你的數組非常龐大,即便是這樣的線性搜索也會產生性能問題。

那么,你真正想做的就是直接在元素上設置一個標志:

if (element.isMoving) { smoothAnimations(element);}element.isMoving = true; if (element.isMoving) { smoothAnimations(element);}element.isMoving = true;

這也有一些潛在的問題,不得不承認這樣一個事實:還有其他代碼也可能操作該 ODM 元素。

  •     在其他代碼中,你創建的屬性會被 for-in 或 Object.keys() 枚舉出來;
  •     在其他一些庫中也許已經使用了同樣的方式(在元素上設置了相同的屬性),那么這將和你的代碼發生沖突,產生不可預計的結果;
  •     其他一些庫可能在將來會使用同樣的方式,這也會與你的代碼發生沖突;
  •     標準委員會可能會為每個元素添加一個 .isMoving() 原生方法,那么你的代碼就徹底不能工作了。

當然,對于最后三個問題,你可以選擇一個無意義的不會有人會使用到的字符串:

if (element.__$jorendorff_animation_library$PLEASE_DO_NOT_USE_THIS_PROPERTY$isMoving__) { smoothAnimations(element);}element.__$jorendorff_animation_library$PLEASE_DO_NOT_USE_THIS_PROPERTY$isMoving__ = true; if (element.__$jorendorff_animation_library$PLEASE_DO_NOT_USE_THIS_PROPERTY$isMoving__) { smoothAnimations(element);}element.__$jorendorff_animation_library$PLEASE_DO_NOT_USE_THIS_PROPERTY$isMoving__ = true;

這似乎太不靠譜了,看了讓人眼睛痛。

你還可以用加密算法來生成一個幾乎唯一的字符串:

// get 1024 Unicode characters of gibberishvar isMoving = SecureRandom.generateName();...if (element[isMoving]) { smoothAnimations(element);}element[isMoving] = true; // get 1024 Unicode characters of gibberishvar isMoving = SecureRandom.generateName(); ... if (element[isMoving]) { smoothAnimations(element);}element[isMoving] = true;

object[name] 語法允許我們將任何字符串作為屬性名,代碼能正常工作,沖突幾乎是不可能了,代碼看起來也美觀多了。

但是,這回導致糟糕的調試體驗,每次使用 console.log() 打印出包含該屬性的元素時,你回看到一個龐大的垃圾字符串,并且如果還不止一個這樣的屬性呢?每次刷新后屬性名都發生了變化,怎么樣使這些屬性看起來更加直觀呢?

為什么這么難?我們只是為了保存一個小小的標志位。
用 Symbol 來解決問題

Symbol 值可以由程序創建,并可以作為屬性名,而且不用擔心屬性名沖突。

var mySymbol = Symbol();var mySymbol = Symbol();

調用 Symbol() 方法將創建一個新的 Symbol 類型的值,并且該值不與其它任何值相等。

與數字和字符串一樣,Symbol 類型的值也可以作為對象的屬性名,正是由于它不與任何其它值相等,對應的屬性也不會發生沖突:

obj[mySymbol] = "ok!"; // guaranteed not to collideconsole.log(obj[mySymbol]); // ok! obj[mySymbol] = "ok!"; // guaranteed not to collideconsole.log(obj[mySymbol]); // ok!

下面是使用 Symbol 來解決上面的問題:

// create a unique symbolvar isMoving = Symbol("isMoving");...if (element[isMoving]) { smoothAnimations(element);}element[isMoving] = true; // create a unique symbolvar isMoving = Symbol("isMoving"); ... if (element[isMoving]) { smoothAnimations(element);}element[isMoving] = true;

上面代碼需要注意幾點:

  •     方法 Symbol("isMoving") 中的 "isMoving" 字符串被稱為 Symbol 的描述信息,這對調試非常有幫助??梢酝ㄟ^ console.log(isMoving) 打印出來,或通過 isMoving.toString() 將 isMoving 轉換為字符串時,或在一些錯誤信息中顯示出來。
  •     element[isMoving] 訪問的是 symbol-keyed 屬性,除了屬性名是 Symbol 類型的值之外,與其它屬性都一樣。
  •     和數組一樣,symbol-keyed 屬性不能通過 . 操作符來訪問,必須使用方括號的方式。
  •     操作 symbol-keyed 屬性也非常方便,通過上面代碼我們已經知道如何獲取和設置 element[isMoving] 的值,我們還可以這樣使用:if (isMoving in element) 或 delete element[isMoving]。
  •     另一方面,只有在 isMoving 的作用域范圍內才可以使用上述代碼,這可以實現弱封裝機制:在一個模塊內創建一些 Symbol,只有在該模塊內部的對象才能使用,而不用擔心與其它模塊的代碼發生沖突。

由于 Symbol 的設計初衷是為了避免沖突,當遍歷 JavaScript 對象時,并不會枚舉到以 Symbol 作為建的屬性,比如,for-in 循環只會遍歷到以字符串作為鍵的屬性,Object.keys(obj)和 Object.getOwnPropertyNames(obj) 也一樣,但這并不意味著 Symbol 為鍵的屬性是不可枚舉的:使用 Object.getOwnPropertySymbols(obj) 這個新方法可以枚舉出來,還有 Reflect.ownKeys(obj) 這個新方法可以返回對象中所有字符串和 Symbol 鍵。(我將在后面的文章中詳細介紹 Reflect 這個新特性。)

庫和框架的設計者將會發現很多 Symbol 的用途,稍后我們將看到,JavaScript 語言本身也對其有廣泛的應用。
Symbol 究竟是什么呢

> typeof Symbol()"symbol" > typeof Symbol()"symbol"

Symbol 是完全不一樣的東西。一旦創建后就不可更改,不能對它們設置屬性(如果在嚴格模式下嘗試這樣做,你將得到一個 TypeError)。它們可以作為屬性名,這時它們和字符串的屬性名沒有什么區別。

另一方面,每個 Symbol 都是獨一無二的,不與其它 Symbol 重復(即便是使用相同的 Symbol 描述創建),創建一個 Symbol 就跟創建一個對象一樣方便。

ES6 中的 Symbol 與傳統語言(如 Lisp 和 Ruby)中的 Symbol 中的類似,但并不是完全照搬到 JavaScript 中。在 Lisp 中,所有標識符都是 Symbol;在 JavaScript 中,標識符和大多數屬性仍然是字符串,Symbol 只是提供了一個額外的選擇。

值得注意的是:與其它類型不同的是,Symbol 不能自動被轉換為字符串,當嘗試將一個 Symbol 強制轉換為字符串時,將返回一個 TypeError。

> var sym = Symbol("<3");> "your symbol is " + sym// TypeError: can't convert symbol to string> `your symbol is ${sym}`// TypeError: can't convert symbol to string > var sym = Symbol("<3");> "your symbol is " + sym// TypeError: can't convert symbol to string> `your symbol is ${sym}`// TypeError: can't convert symbol to string

應該避免這樣的強制轉換,應該使用 String(sym) 或 sym.toString() 來轉換。
獲取 Symbol 的三種方法

  1.     Symbol() 每次調用時都返回一個唯一的 Symbol。
  2.     Symbol.for(string) 從 Symbol 注冊表中返回相應的 Symbol,與上個方法不同的是,Symbol 注冊表中的 Symbol 是共享的。也就是說,如果你調用 Symbol.for("cat") 三次,都將返回相同的 Symbol。當不同頁面或同一頁面不同模塊需要共享 Symbol 時,注冊表就非常有用。
  3.     Symbol.iterator 返回語言預定義的一些 Symbol,每個都有其特殊的用途。

如果你仍不確定 Symbol 是否有用,那么接下來的內容將非常有趣,因為我將為你演示 Symbol 的實際應用。
Symbol 在 ES6 規范中的應用

我們已經知道可以使用 Symbol 來避免代碼沖突。之前在介紹 iterator 時,我們還解析了 for (var item of myArray) 內部是以調用 myArray[Symbol.iterator]() 開始的,當時我提到這個方法可以使用 myArray.iterator() 來代替,但是使用 Symbol 的后向兼容性更好。

在 ES6 中還有一些地方使用到了 Symbol。(這些特性還沒有在 FireFox 中實現。)

  •     使 instanceof 可擴展。在 ES6 中,object instanceof constructor 表達式被標準化為構造函數的一個方法:constructor[Symbol.hasInstance](object),這意味著它是可擴展的。
  •     消除新特性和舊代碼之間的沖突。
  •     支持新類型的字符串匹配。在 ES5 中,調用 str.match(myObject) 時,首先會嘗試將 myObject 轉換為 RegExp 對象。在 ES6 中,首先將檢查 myObject 中是否有 myObject[Symbol.match](str) 方法,在所有正則表達式工作的地方都可以提供一個自定義的字符串解析方法。

這些用途還比較窄,但僅僅通過我文章中的代碼很難看到這些新特性產生的重大影響。JavaScript 的 Symbol 是 PHP 和 Python 中 __doubleUnderscores 的改進版本,標準組織將使用它來為語言添加新特性,而不會對已有代碼產生影響。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
91精品久久久久久久久不口人| 欧美国产精品va在线观看| 亚洲欧美成人精品| 久久久精品国产| 日本中文字幕不卡免费| 国产亚洲人成网站在线观看| 亚洲图片欧美午夜| 欧美成人合集magnet| 久久久999国产精品| 欧美成人精品激情在线观看| 欧美电影免费观看网站| 欧美巨猛xxxx猛交黑人97人| 亚洲国产精品电影| 欧美激情精品久久久久久大尺度| 欧美人交a欧美精品| 日韩中文字幕在线视频播放| 琪琪亚洲精品午夜在线| 亚洲人成网站色ww在线| 最近2019中文字幕一页二页| 亚洲成人三级在线| 国产999精品视频| 亚洲视频电影图片偷拍一区| 欧美插天视频在线播放| 91精品视频免费观看| 国内精品一区二区三区| 亚洲精品视频免费在线观看| 日韩va亚洲va欧洲va国产| 日韩电影视频免费| 精品国产老师黑色丝袜高跟鞋| 亚洲精品一区二区在线| 欧美巨乳美女视频| 久久九九国产精品怡红院| 在线观看国产精品91| 日韩精品高清视频| 日韩av中文字幕在线| 在线丨暗呦小u女国产精品| 亚洲精品网址在线观看| 国产综合久久久久久| 日韩欧美在线视频观看| 久久久久久久一区二区三区| 日韩成人在线视频| 亚洲欧美中文另类| 成人在线免费观看视视频| 国产成人精品网站| 久久九九热免费视频| 欧美成人免费观看| 欧美高清在线播放| 久久久久久九九九| 国产日韩在线免费| 欧美视频在线观看免费网址| 欧美疯狂做受xxxx高潮| 伊人久久久久久久久久久| 韩国19禁主播vip福利视频| 91美女高潮出水| 色综合亚洲精品激情狠狠| 伊人久久大香线蕉av一区二区| 欧美日韩成人在线观看| 亚洲国产另类 国产精品国产免费| 亚洲成人免费网站| 久久国产精品久久久久久| 亚洲xxxx视频| 欧美一级淫片videoshd| 欧美日韩国产123| 国产色婷婷国产综合在线理论片a| 日本国产一区二区三区| 欧美巨猛xxxx猛交黑人97人| 欧美亚洲第一区| 久久久久久亚洲精品不卡| 影音先锋日韩有码| 欧美丝袜一区二区三区| 国产亚洲人成网站在线观看| 国产视频亚洲精品| 国产69精品久久久久久| 亚洲深夜福利视频| 国产suv精品一区二区三区88区| 国产精品久久久久久久久免费| 97国产在线观看| 欧美激情xxxx性bbbb| 久久精品久久久久久| 亚洲成人激情图| 欧美成人精品一区二区三区| 91精品久久久久久久| 国产精品成人一区二区| 欧美精品在线免费观看| 91亚洲精品久久久| 色樱桃影院亚洲精品影院| 国产午夜精品全部视频在线播放| 一区二区av在线| 日韩电视剧免费观看网站| 久久精品99国产精品酒店日本| 97色在线视频观看| 亚洲一区二区三区久久| 国产精品免费一区| 久久成年人免费电影| 色在人av网站天堂精品| 中国日韩欧美久久久久久久久| 欧美一区二区三区……| 亚洲伊人久久大香线蕉av| 国产精品女主播视频| 日韩国产中文字幕| 91产国在线观看动作片喷水| 亚洲欧美精品伊人久久| 亚洲天堂视频在线观看| 亚洲欧美一区二区激情| 欧美黄色片免费观看| 一本色道久久88综合亚洲精品ⅰ| 欧美性视频网站| 日韩欧美在线免费观看| 亚洲精品第一国产综合精品| 国产网站欧美日韩免费精品在线观看| 国语自产精品视频在线看抢先版图片| 国产免费亚洲高清| 亚洲一区二区免费在线| 国产成人福利网站| 夜色77av精品影院| 色偷偷亚洲男人天堂| 茄子视频成人在线| 国产精品入口福利| 欧美视频一二三| 精品亚洲一区二区| 亚洲自拍偷拍色片视频| 中文字幕视频在线免费欧美日韩综合在线看| 亚洲香蕉av在线一区二区三区| 久久视频免费在线播放| 国产精品视频一区国模私拍| 久久免费视频网站| 日韩免费在线免费观看| 日韩av免费在线观看| 国产精品视频在线播放| 亚洲一区亚洲二区亚洲三区| 亚洲精品乱码久久久久久金桔影视| 欧美丰满少妇xxxxx做受| 国产狼人综合免费视频| 欧美天天综合色影久久精品| 欧美性猛交xxxx偷拍洗澡| 亚洲情综合五月天| 91po在线观看91精品国产性色| 国产噜噜噜噜久久久久久久久| 国产91免费观看| 中文字幕久热精品视频在线| 久久久精品国产网站| 91地址最新发布| 欧美日韩裸体免费视频| 69久久夜色精品国产69乱青草| 国产亚洲日本欧美韩国| 亚洲区在线播放| 久久久精品国产一区二区| 青草青草久热精品视频在线观看| 中文字幕亚洲字幕| 国产成人精品一区二区在线| 日韩在线观看你懂的| 日韩国产精品亚洲а∨天堂免| 日本一区二区在线免费播放| 欧美精品videosex性欧美| 欧美激情久久久| 北条麻妃一区二区在线观看| 性色av香蕉一区二区| 琪琪亚洲精品午夜在线| 欧美成人自拍视频| 成人在线视频网站| 国产精品一区二区久久久| 成人精品福利视频| 日本亚洲精品在线观看| 国产精品视频久久久|