ES6系列二.一:Symbol原理

2019-07-20  本文已影响0人  原型设计

上节我们介绍了symbol 基本用法,这节我们来实现它的每一个特性。

特性

  1. Symbol 值通过 Symbol 函数生成,使用 typeof,结果为 "symbol"
  2. Symbol 函数前不能使用 new 命令,否则会报错
  3. instanceof 的结果为 false
  4. Symbol 函数可以接受一个字符串作为参数,表示对 Symbol 实例的描述
  5. 如果 Symbol 的参数是一个对象,就会调用该对象的 toString 方法,将其转为字符串
  6. Symbol 函数的参数只是表示对当前 Symbol 值的描述,相同参数的 Symbol 函数的返回值是不相等的
  7. Symbol 值不能与其他类型的值进行运算,会报错。
  8. Symbol 值可以显式转为字符串。
  9. Symbol 值可以作为标识符,用于对象的属性名,可以保证不会出现同名的属性。
  10. Symbol 作为属性名,该属性不会出现在 for...in、for...of 循环中,也不会被 Object.keys()、Object.getOwnPropertyNames()、JSON.stringify() 返回。但是,它也不是私有属性,有一个 Object.getOwnPropertySymbols 方法,可以获取指定对象的所有 Symbol 属性名。
  11. 如果我们希望使用同一个 Symbol 值,可以使用 Symbol.for。它接受一个字符串作为参数,然后搜索有没有以该参数作为名称的 Symbol 值。如果有,就返回这个 Symbol 值,否则就新建并返回一个以该字符串为名称的 Symbol 值。
  12. Symbol.keyFor 方法返回一个已登记的 Symbol 类型值的 key。

这么多特性大家有没有想过如何用原生js 怎么去实现这个symbol 函数。

下面我们去一个一个特性去实现。

特性一实现:

typeof 常常判断基本数据类型(包括symbol),首先我们必须知道js typeof 的原理:

js 在底层存储变量的时候,会在变量的机器码的低位1-3位存储其类型信息。

对于 undefined 和 null 来说,这两个值的信息存储是有点特殊的。

null:所有机器码均为0

undefined:用 −2^30 整数来表示。

typeof 在判断 null 的时候就出现问题了,由于 null 的所有机器码均为0,因此直接被当做了对象来看待。

typeof null
"object"

symbol : 低三位是怎么样的呢?有兴趣的可以告诉我。
这个功能我不知道怎么去实现,大家有兴趣可以探讨一下,我估计底层机器码是判断低三位是不是那个特定值来实现。

特性二实现:

实现很简单,一句话,估计大家都想到了。

// Symbol 函数前不能使用 new 命令
if (this instanceof Symbol) {
  throw new TypeError('Symbol is not a constructor');
}

特性三实现:

在特性二的时候用到了 instanceof,我们来探究这个。

用途: instanceof来判断一个实例是否属于某种类型。

原理分析:instanceof 主要的实现原理就是只要右边变量的 prototype 在左边变量的原型链上即可,返回状态分为三种:

知道instanceof 原理,那我们用一个函数来表示,这里涉及到js 原型继承知识点,需要小伙伴们自己去查看相应的知识点:

function myInstanceOf (left,right){
  let rightProto = right.prototype; 
  let leftVaule = left.__proto__; 
  if (left === null) {
     return false;  
  }
  if (leftVaule === rightProto) {
      return true;  
  }  
}

链接学习获取js 自身属性

特性四实现:

理解 😄

特性五实现:

function Symbol(description) {
        // 对象模拟返回symbol
        var descString = description === undefined ? undefined : String(description)

        var symbol = Object.create(null)

        Object.defineProperties(symbol, {
            '__Description__': {
                value: descString,
                writable: false,
                enumerable: false,
                configurable: false
            }
        });
        return symbol;
    }

特性六实现:

参考特训五的实现,因为每次创建都是通过 Object.create(null) 创建的,所以每个symbol() 不相等,小伙伴不要理解错了,底层我估计不是用Object.create(null) 创建的,是其他方法。

特性七实现:

var symbol = Object.create({
         toString: function() {
               return this.__Name__;
           },
           valueOf: function() {
               return this;
           }
       })

特性十实现:

Object.defineProperties(symbol, {
          '__Description__': {
                value: descString,
                writable: false,
                enumerable: false, // 设置为false 就可以不可枚举
                configurable: false
            }
        });

特性十一实现:

Object.defineProperties(SymbolPolyfill, {
        'for': {
            value: function(description) {
                var descString = description === undefined ? undefined : String(description)
                return forMap[descString] ? forMap[descString] : forMap[descString] = SymbolPolyfill(descString);
            },
            writable: true,
            enumerable: false,
            configurable: true
        },
    });

特性十二实现:

Object.defineProperties(SymbolPolyfill, {
        'keyFor': {
            value: function(symbol) {
                for (var key in forMap) {
                    if (forMap[key] === symbol) return key;
                }
            },
            writable: true,
            enumerable: false,
            configurable: true
        }
    });

感谢你读到这里:

给大家一个完整的symbol函数的实现:

(function() {
    var root = this;

    var generateName = (function(){
        var postfix = 0;
        return function(descString){
            postfix++;
            return '@@' + descString + '_' + postfix
        }
    })()

    var SymbolPolyfill = function Symbol(description) {

        if (this instanceof SymbolPolyfill) throw new TypeError('Symbol is not a constructor');

        var descString = description === undefined ? undefined : String(description)

        var symbol = Object.create({
            toString: function() {
                return this.__Name__;
            },
            valueOf: function() {
                return this;
            }
        })

        Object.defineProperties(symbol, {
            '__Description__': {
                value: descString,
                writable: false,
                enumerable: false,
                configurable: false
            },
            '__Name__': {
                value: generateName(descString),
                writable: false,
                enumerable: false,
                configurable: false
            }
        });

        return symbol;
    }

    var forMap = {};

    Object.defineProperties(SymbolPolyfill, {
        'for': {
            value: function(description) {
                var descString = description === undefined ? undefined : String(description)
                return forMap[descString] ? forMap[descString] : forMap[descString] = SymbolPolyfill(descString);
            },
            writable: true,
            enumerable: false,
            configurable: true
        },
        'keyFor': {
            value: function(symbol) {
                for (var key in forMap) {
                    if (forMap[key] === symbol) return key;
                }
            },
            writable: true,
            enumerable: false,
            configurable: true
        }
    });

    root.SymbolPolyfill = SymbolPolyfill;

})()
上一篇下一篇

猜你喜欢

热点阅读