美文网首页
js的第七种数据类型Symbol

js的第七种数据类型Symbol

作者: 贝程学院_前端 | 来源:发表于2019-08-09 08:46 被阅读0次

    Symbol类型是ES6中新加入的一种原始类型。

    每个从Symbol()返回的symbol值都是唯一的。一个symbol值能作为对象属性的标识符;这是该数据类型仅有的目的。

    下面来看看Symbol类型具有哪些特性。

    Symbol的特性

    1.独一无二

    直接使用Symbol()创建新的symbol变量,可选用一个字符串用于描述。当参数为对象时,将调用对象的toString()方法。

    var sym1 = Symbol();  // Symbol() 
    var sym2 = Symbol('ConardLi');  // Symbol(ConardLi)
    var sym3 = Symbol('ConardLi');  // Symbol(ConardLi)
    var sym4 = Symbol({name:'ConardLi'}); // Symbol([object Object])
    console.log(sym2 === sym3);  // false
    

    我们用两个相同的字符串创建两个Symbol变量,它们是不相等的,可见每个Symbol变量都是独一无二的。

    如果我们想创造两个相等的Symbol变量,可以使用Symbol.for(key)。

    使用给定的key搜索现有的symbol,如果找到则返回该symbol。否则将使用给定的key在全局symbol注册表中创建一个新的symbol。

    var sym1 = Symbol.for('ConardLi');
    var sym2 = Symbol.for('ConardLi');
    console.log(sym1 === sym2); // true
    

    原始类型

    注意是使用Symbol()函数创建symbol变量,并非使用构造函数,使用new操作符会直接报错。

    new Symbol(); // Uncaught TypeError: Symbol is not a constructor
    

    我们可以使用typeof运算符判断一个Symbol类型:

    typeof Symbol() === 'symbol'
    typeof Symbol('ConardLi') === 'symbol'
    

    不可枚举

    当使用Symbol作为对象属性时,可以保证对象不会出现重名属性,调用for...in不能将其枚举出来,另外调用Object.getOwnPropertyNames、Object.keys()也不能获取Symbol属性。

    可以调用Object.getOwnPropertySymbols()用于专门获取Symbol属性。

    var obj = {
      name:'ConardLi',
      [Symbol('name2')]:'code秘密花园'
    }
    Object.getOwnPropertyNames(obj); // ["name"]
    Object.keys(obj); // ["name"]
    for (var i in obj) {
       console.log(i); // name
    }
    Object.getOwnPropertySymbols(obj) // [Symbol(name)]
    

    Symbol的应用场景

    下面是几个Symbol在程序中的应用场景。

    应用一:防止XSS

    在React的ReactElement对象中,有一个$$typeof属性,它是一个Symbol类型的变量:

    var REACT_ELEMENT_TYPE =
      (typeof Symbol === 'function' && Symbol.for && Symbol.for('react.element')) ||
      0xeac7;
    

    ReactElement.isValidElement函数用来判断一个React组件是否是有效的,下面是它的具体实现。

    ReactElement.isValidElement = function (object) {
      return typeof object === 'object' && object !== null && object.$$typeof === REACT_ELEMENT_TYPE;
    };
    

    可见React渲染时会把没有$$typeof标识,以及规则校验不通过的组件过滤掉。

    如果你的服务器有一个漏洞,允许用户存储任意JSON对象, 而客户端代码需要一个字符串,这可能会成为一个问题:

    // JSON
    let expectedTextButGotJSON = {
      type: 'div',
      props: {
        dangerouslySetInnerHTML: {
          __html: '/* put your exploit here */'
        },
      },
    };
    let message = { text: expectedTextButGotJSON };
    <p>
      {message.text}
    </p >
    

    而JSON中不能存储Symbol类型的变量,这就是防止XSS的一种手段。

    应用二:私有属性

    借助Symbol类型的不可枚举,我们可以在类中模拟私有属性,控制变量读写:

    const privateField = Symbol();
    class myClass {
      constructor(){
        this[privateField] = 'ConardLi';
      }
      getField(){
        return this[privateField];
      }
      setField(val){
        this[privateField] = val;
      }
    }
    

    应用三:防止属性污染

    在某些情况下,我们可能要为对象添加一个属性,此时就有可能造成属性覆盖,用Symbol作为对象属性可以保证永远不会出现同名属性。

    例如下面的场景,我们模拟实现一个call方法:

    Function.prototype.myCall = function (context) {
      if (typeof this !== 'function') {
        return undefined; // 用于防止 Function.prototype.myCall() 直接调用
      }
      context = context || window;
      const fn = Symbol();
      context[fn] = this;
      const args = [...arguments].slice(1);
      const result = context[fn](...args);
      delete context[fn];
      return result;
    }
    

    我们需要在某个对象上临时调用一个方法,又不能造成属性污染,Symbol是一个很好的选择。

    相关文章

      网友评论

          本文标题:js的第七种数据类型Symbol

          本文链接:https://www.haomeiwen.com/subject/iptcjctx.html