整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          Javascript ES6新引入的類型Symbol詳解以及示例

          ES6引入的新的原始數據類型Symbol,表示獨一無二的值,它是js中的第7種數據類型,是一種類似于字符串的數據類型。

          Symbol特點:

          1、Symbol的值是唯一的,用來解決命名沖突的問題。

          2、Symbol值不能與其他數據進行運算。

          3、Symbol定義的對象屬性不能使用for...in循環遍歷,但是可以使用Reflect.ownKeys來獲取對象的所有鍵名。然后遍歷。

          如何創建?

          可以使用函數創建。

          let s = Symbol('demo');

          或者

          let s1 = Symbol.for('demo');

          使用for函數可以得到某個字符串唯一的symbol值,例如下面的比較是相等的。

          let s2 = Symbol.for('demo');

          s1 === s2 返回的就是true。

          Symbol內置的值

          用做對象的屬性。通過對這些內置值的設置,來改變對象在某些特定場景下的表現。

          最常用的有:

          在使用操作符時調用。

          class Person{
            static [Symbol.hasInstance](param){
            console.log(param);
            console.log('我被用來檢查類型了')
            return false;
            }
          }
          let obj = {}
          console.log(obj instanceof Person)

          使用concat來合并兩個數組的時候,js會默認將數組內的元素展開然后合并為一個數組返回(原數組不變),這個行為es6以后可以使用Symbol.改變,將其置為false就可以將數組作為一整個對象合并到過去。

          let animals = ['cat','dog','panda']
          let fruit = ['apple','pear']
          fruit[Symbol.isConcatSpreadable] = true
          console.log(animals.concat(fruit)) // 結果是['cat','dog','panda','apple','pear']
          fruit[Symbol.isConcatSpreadable] = false
          console.log(animals.concat(fruit)) // 結果是['cat','dog','panda', Array(2)]

          用于給對象定義迭代方法,這樣就可以使用es6中新提供的for...of語法,需要注意的是,自定義的這個迭代器方法,需要按照一定的規范來寫,需要返回一個具有next方法的對象,next方法需要返回具有value和done兩個屬性的對象。done會被用來判斷什么時候結束迭代。

          const banji = {
          name: "終極一班",
          stus: [ 'xiaoming', 'xiaoning', 'xiaotian', 'knight' ],
          [Symbol.iterator]() {
          // 索引變量
          let index = 0;
          // 保存this
          let _this = this;
          return {
          next: function() {
          if (index < _this.stus.length) {
          const result = { value: _this.stus[index], done: false };
          // 下標自增
          index++;
          // 返回結果
          return result;
          } else {
          return { value: undefined, done: true };
          }
          }
          };
          }
          }
          // 遍歷這個對象
          for (let v of banji) {
          
          console.log(v);
          }

          一個在調用 String..match() 方法時調用的方法, 直白點說就是如果你定義一個字符串,當你調用.match(),如果這個對象定義了Symbol.match方法時,就會執行這個方法。

          let animal = {
            [Symbol.match](str){
              console.log(str) //打印出字符串 cat
              return str.indexOf('animal');
            }
          }
          let kitty = "cat"
          console.log(kitty.match(animal)) //返回值-1,這里打印出-1

          一個在調用 String..replace() 方法時調用的方法,和上面的一樣,當一個字符串調用.replace()時,會去執行中的Symbol.replace方法。

          let animalName = {
            /* strValue 會返回調用者本身,replacement為調用repalce方法時傳入的第二個參數 */
            [Symbol.replace](strValue, replacement){
              console.log("strValue: " + strValue,"replacement: " + replacement) //strValue: cat, its name is {params} replacement: {params}
              return strValue.replace("{params}", "kitty")
            }
          }
          let kitty = "cat, its name is {params}"
          console.log(kitty.replace(animalName, "{params}")) //cat, its name is kitty

          一個在調用 String..search() 方法時調用的方法,用于在字符串中定位子串,這個也和上面str相關擴展一樣直接看示例。

          let animalName = {
          /* strValue就是調用者本身 */
            [Symbol.search](strValue){
              console.log(strValue) //cat, its name is kitty
              return strValue.split("name is")[1]
            }
          }
          let kitty = "cat, its name is kitty"
          console.log(kitty.search(animalName)) //kitty

          一個在調用 String..split() 方法時調用的方法,用于分割字符串。

          let animalName = {
            /* strValue就是調用者本身 */
            [Symbol.split](strValue){
              console.log(strValue) //cat, its name is kitty
              return strValue.indexOf("name")
            }
          }
          let kitty = "cat, its name is kitty"
          console.log(kitty.split(animalName)) //8

          這個方法決定了當一個對象被轉換為原始值時的行為。引擎在每個類型值的原型上定義了Symbol.方法。這個方法被調用時,會接受一個字符串參數,表示當前運算的模式,一共有三種模式:

          number: 該場景下需要轉換成數值.對應操作符:* / -

          string: 該場景下需要轉換成字符串,顯示使用string的構造方法

          default:該場景下可以轉換成數值,也可以轉換成字符串,對應操作符:+

          let obj = {
            [Symbol.toPrimitive](hint){
              switch(hint){
              case 'number':
              	return 123;
              case 'string':
              	return 'str';
              case 'default':
              	return 'default';
              default:
          
              	throw new Error();
              }
            }
          }
          console.log(2 * obj) //246
          console.log(3 + obj) //3default
          console.log(obj == 'default') //true
          console.log(String(obj)) //str

          對象的Symbol.species屬性,指向一個構造函數,創建衍生對象時,會使用該屬性。這個的主要用途是,有些類庫是在基類的基礎上修改的,那么子類使用繼承的方法時,作者可能希望返回基類的實例,而不是子類的實例。

          class MyArray extends Array {
            static get [Symbol.species](){
              return Array;
            }
          }
          //b,c是a的衍生對象
          const a = new MyArray(1,2,3)
          const b = a.map(x => x+1)
          const c = a.filter(x => x > 0)
          //如果沒有定義上面的Symbol.species,那么下面的instanceof均返回true
          console.log(b instanceof MyArray) //true
          console.log(c instanceof MyArray) //true
          //定義了上面的Symbol.species時,返回值是下面這樣
          console.log(b instanceof MyArray) //false
          console.log(b instanceof Array) //true

          一個在調用 String..() 方法時使用的字符串,用于創建對象描述。在對象上面調用Object..方法時,如果這個屬性存在,它的返回值會出現在方法返回的字符串中,表示對象的類型。

          //第一種寫法,注意這里的get關鍵字是必須的,call方法需要用到get取值器
          let animal = {
            get [Symbol.toStringTag](){
              return 'animal'
            }
          }
          console.log(Object.prototype.toString.call(animal)) // [object animal]
          //第二種寫法
          console.log({[Symbol.toStringTag]: 'tag'}.toString()) // [object tag]

          一個定義了一些不可被 with 語句引用的對象屬性名稱的對象集合。集合中的屬性名稱,會在with環境綁定中被排除。

          const animal = {
            type: 'animal',
            name: 'kitty'
          }
          with(animal){
            console.log(type, name) //animal kitty
          }
          //定義Symbol.unscopables以便在with環境中排除某些屬性
          animal[Symbol.unscopables] = {
            type: true
          }
          with(animal){
            console.log(type) //Uncaught ReferenceError: type is not defined
          }

          以上這些被稱為眾所周知的symbols,其實其中很多值并不常用,為了驗證這些symbols的準確用法,我搜了很多資料,總算把每一個都親自驗證了一遍。

          這里附上一個地址,這里面有特別詳細的示例代碼,我也是自己費了半天勁兒快驗證完的時候才發現這個網址的,白白浪費了好多時間。

          大家百度搜索一下關鍵字Symbol MDN ,可以看到有mozilla的一個開發者網站,這上面也有可以參考的示例。

          另外,之所以要研究這個,主要是最近在學vue3 + ,身為一個沒太多基礎的前端小白,學習的過程中遇到一個知識點可能都會要查半天資料才能弄懂,不過我也樂在其中。


          主站蜘蛛池模板: 亚洲国产成人一区二区精品区| 国产裸体舞一区二区三区| 一区二区三区高清| 欧美日韩一区二区成人午夜电影| 国产精品高清一区二区人妖| 久久亚洲国产精品一区二区| 偷拍精品视频一区二区三区| 日韩精品一区二区三区在线观看l| 久久精品无码一区二区无码| 麻豆精品人妻一区二区三区蜜桃 | 无码囯产精品一区二区免费 | 国产成人综合一区精品| 色婷婷av一区二区三区仙踪林| 久久久精品一区二区三区 | 免费一区二区视频| 国产一区韩国女主播| 国内精品视频一区二区三区| 亚洲午夜在线一区| 亚洲欧美日韩中文字幕在线一区| 88国产精品视频一区二区三区| 亚洲色婷婷一区二区三区| 国产成人片视频一区二区| 国产精品一区二区三区久久| 国产福利一区二区精品秒拍| 国产成人精品一区二三区熟女| 无码人妻精品一区二区三区9厂 | 中文字幕一区日韩在线视频 | 国产精品一区二区香蕉| 日韩在线视频一区| 高清国产精品人妻一区二区| 久久久久人妻一区精品性色av| 无码播放一区二区三区| 动漫精品一区二区三区3d| 丰满少妇内射一区| 色狠狠色狠狠综合一区| 日本韩国黄色一区二区三区| 一区二区三区美女视频| 久久久久成人精品一区二区| 久久精品黄AA片一区二区三区| 国产精品视频分类一区| 国内精品一区二区三区最新|