日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Symbol 类型 的简单理解和应用

發布時間:2023/12/16 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Symbol 类型 的简单理解和应用 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Symbol 的概念

symbol?是一種基本數據類型 (primitive data type)。Symbol()函數會返回symbol類型的值,該類型具有靜態屬性和靜態方法。它的靜態屬性會暴露幾個內建的成員對象;它的靜態方法會暴露全局的symbol注冊,且類似于內建對象類,但作為構造函數來說它并不完整,因為它不支持語法:"new Symbol()"。

1? 每個從Symbol()返回的symbol值都是唯一的。一個symbol值能作為對象屬性的標識符;這是該數據類型僅有的目的

? ?也就是說每一個Symbol的值都是不同的?

?

const symbol1 = Symbol(); const symbol2 = Symbol('foo'); const symbol3 = Symbol('foo');console.log(typeof symbol1); // expected output: "symbol"console.log(symbol2 === 42); // expected output: falseconsole.log(symbol3.toString()); // expected output: "Symbol(foo)"console.log(Symbol('foo') === Symbol('foo')); // expected output: falselet copyValue1 = 2 let copyValue2 = 2 console.log(copyValue1,copyValue2,Symbol('foo'),Symbol('foo'),copyValue1==copyValue2,symbol2==symbol3) //2 2 Symbol(foo) Symbol(foo) true false

上面的代碼創建了三個新的symbol類型。 注意,Symbol("foo")?不會強制將字符串 “foo” 轉換成symbol類型。它每次都會創建一個新的 symbol類型:

?

全局共享的 Symbol

上面使用Symbol()?函數的語法,不會在你的整個代碼庫中創建一個可用的全局的symbol類型。 要創建跨文件可用的symbol,甚至跨域(每個都有它自己的全局作用域)?, 使用?Symbol.for()?方法和 ?Symbol.keyFor()?方法從全局的symbol注冊表設置和取得symbol。

在對象中查找 Symbol 屬性

Object.getOwnPropertySymbols()?方法讓你在查找一個給定對象的符號屬性時返回一個symbol類型的數組。注意,每個初始化的對象都是沒有自己的symbol屬性的,因此這個數組可能為空,除非你已經在對象上設置了symbol屬性。

Symbol 包裝器對象作為屬性的鍵

當一個 Symbol 包裝器對象作為一個屬性的鍵時,這個對象將被強制轉換為它包裝過的 symbol 值:

var sym = Symbol("foo"); var obj = {[sym]: 1}; obj[sym]; // 1 obj[Object(sym)]; // still 1

?

對 symbol 使用 typeof 運算符

?typeof運算符能幫助你識別 symbol 類型

typeof Symbol() === 'symbol' typeof Symbol('foo') === 'symbol' typeof Symbol.iterator === 'symbol'

Symbol 類型轉換

當使用 symbol 值進行類型轉換時需要注意一些事情:

  • 嘗試將一個 symbol 值轉換為一個 number 值時,會拋出一個?TypeError?錯誤? (e.g.?+sym?or?sym | 0).
  • 使用寬松相等時,?Object(sym) == sym?returns?true.
  • 這會阻止你從一個 symbol 值隱式地創建一個新的 string 類型的屬性名。例如,Symbol("foo") + "bar" 將拋出一個?TypeError?(can't convert symbol to string).
  • "safer"?String(sym)?conversion?的作用會像symbol類型調用?Symbol.prototype.toString()?一樣,但是注意?new String(sym)?將拋出異常。

Symbols 與?for...in?迭代

Symbols 在?for...in?迭代中不可枚舉。另外,Object.getOwnPropertyNames()?不會返回 symbol 對象的屬性,但是你能使用?Object.getOwnPropertySymbols()?得到它們。

var obj = {};obj[Symbol("a")] = "a"; obj[Symbol.for("b")] = "b"; obj["c"] = "c"; obj.d = "d";for (var i in obj) {console.log(i); // logs "c" and "d" }

Symbols 與?JSON.stringify()

當使用 JSON.stringify() 時,以 symbol 值作為鍵的屬性會被完全忽略:

JSON.stringify({[Symbol("foo")]: "foo"}); // '{}'

更多細節,請看?JSON.stringify()。

?

應用場景1:使用Symbol來作為對象屬性名(key)

在這之前,我們通常定義或訪問對象的屬性時都是使用字符串,比如下面的代碼:

let obj = {abc: 123,"hello": "world" }obj["abc"] // 123 obj["hello"] // 'world'

而現在,Symbol可同樣用于對象屬性的定義和訪問:

? const PROP_NAME = Symbol() const PROP_AGE = Symbol()let obj = {[PROP_NAME]: "一斤代碼" } obj[PROP_AGE] = 18obj[PROP_NAME] // '一斤代碼' obj[PROP_AGE] // 18

隨之而來的是另一個非常值得注意的問題:就是當使用了Symbol作為對象的屬性key后,在對該對象進行key的枚舉時,會有什么不同?在實際應用中,我們經常會需要使用Object.keys()或者for...in來枚舉對象的屬性名,那在這方面,Symbol類型的key表現的會有什么不同之處呢?來看以下示例代碼:

? let obj = {[Symbol('name')]: '一斤代碼',age: 18,title: 'Engineer' }Object.keys(obj) // ['age', 'title']for (let p in obj) {console.log(p) // 分別會輸出:'age' 和 'title' }Object.getOwnPropertyNames(obj) // ['age', 'title']

由上代碼可知,Symbol類型的key是不能通過Object.keys()或者for...in來枚舉的,它未被包含在對象自身的屬性名集合(property names)之中。所以,利用該特性,我們可以把一些不需要對外操作和訪問的屬性使用Symbol來定義。

也正因為這樣一個特性,當使用JSON.stringify()將對象轉換成JSON字符串的時候,Symbol屬性也會被排除在輸出內容之外:

JSON.stringify(obj) // {"age":18,"title":"Engineer"}

我們可以利用這一特點來更好的設計我們的數據對象,讓“對內操作”和“對外選擇性輸出”變得更加優雅。

然而,這樣的話,我們就沒辦法獲取以Symbol方式定義的對象屬性了么?非也。還是會有一些專門針對Symbol的API,比如:

? // 使用Object的API Object.getOwnPropertySymbols(obj) // [Symbol(name)]// 使用新增的反射API Reflect.ownKeys(obj) // [Symbol(name), 'age', 'title']

應用場景2:使用Symbol來替代常量

先來看一下下面的代碼,是不是在你的代碼里經常會出現?

? const TYPE_AUDIO = 'AUDIO' const TYPE_VIDEO = 'VIDEO' const TYPE_IMAGE = 'IMAGE'function handleFileResource(resource) {switch(resource.type) {case TYPE_AUDIO:playAudio(resource)breakcase TYPE_VIDEO:playVideo(resource)breakcase TYPE_IMAGE:previewImage(resource)breakdefault:throw new Error('Unknown type of resource')} }

如上面的代碼中那樣,我們經常定義一組常量來代表一種業務邏輯下的幾個不同類型,我們通常希望這幾個常量之間是唯一的關系,為了保證這一點,我們需要為常量賦一個唯一的值(比如這里的'AUDIO'、'VIDEO'、 'IMAGE'),常量少的時候還算好,但是常量一多,你可能還得花點腦子好好為他們取個好點的名字。

現在有了Symbol,我們大可不必這么麻煩了:

?
  • const TYPE_AUDIO = Symbol()

  • const TYPE_VIDEO = Symbol()

  • const TYPE_IMAGE = Symbol()

  • 這樣定義,直接就保證了三個常量的值是唯一的了!是不是挺方便的呢。

    應用場景3:使用Symbol定義類的私有屬性/方法

    我們知道在JavaScript中,是沒有如Java等面向對象語言的訪問控制關鍵字private的,類上所有定義的屬性或方法都是可公開訪問的。因此這對我們進行API的設計時造成了一些困擾。

    而有了Symbol以及模塊化機制,類的私有屬性和方法才變成可能。例如:

    • 在文件 a.js中
    const PASSWORD = Symbol()class Login {constructor(username, password) {this.username = usernamethis[PASSWORD] = password}checkPassword(pwd) {return this[PASSWORD] === pwd} }export default Login
    • 在文件 b.js 中
    ? import Login from './a'const login = new Login('admin', '123456')login.checkPassword('admin') // truelogin.PASSWORD // oh!no! login[PASSWORD] // oh!no! login["PASSWORD"] // oh!no!

    由于Symbol常量PASSWORD被定義在a.js所在的模塊中,外面的模塊獲取不到這個Symbol,也不可能再創建一個一模一樣的Symbol出來(因為Symbol是唯一的),因此這個PASSWORD的Symbol只能被限制在a.js內部使用,所以使用它來定義的類屬性是沒有辦法被模塊外訪問到的,達到了一個私有化的效果。

    ?

    ?

    參考文檔

    【1】https://blog.csdn.net/weixin_33711641/article/details/89659385?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EOPENSEARCH%7Edefault-5.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EOPENSEARCH%7Edefault-5.control

    【2】https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Symbol#規范?

    總結

    以上是生活随笔為你收集整理的Symbol 类型 的简单理解和应用的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。