ES6读书简记·Symbol

CY 2019年01月05日 88次浏览

阮老师的这一章我读了好几遍,感觉有些内容还是蛮“敷衍”的,有些例子感觉是在强行举例。

概述

Symbol表示独一无二的值,可以用它来做的事情挺多。

SymbolJavaScript除了undefinednull、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)之外的第七种数据类型。

Symbol不能使用new命令

Symbol的参数接受一个字符串,目的是为了容易区分,就算两个Symbol接受同一个字符串,这两个Symbol也不会相等

Symbol不能和其他类型的值进行运算,Symbol可以显式的转换为字符串(toString()),Symbol也可以转换为布尔值,但它不能转换为数值。

Symbol.prototype.description

ES2019Symbol添加了属性,可以直接返回Symbol参数中的那个用来做描述的字符串。

Symbol作为属性名

Symbol作为对象的属性名的时候不能用点运算符,对象内部使用Symbol定义属性时,Symbol必须放在方括号中,这时因为避免将Symbol类型和字符串类型进行混淆。

Symbol 值作为属性名时,该属性还是公开属性,不是私有属性。

使用Symbol消除魔术字符串

感觉这个例子有些牵强?

const shapeType = {
  triangle: Symbol() // 这里使用Symbol代表一个独一无二的值,可以避免使用魔术字符串
};

function getArea(shape, options) {
  let area = 0;
  switch (shape) {
    case shapeType.triangle:
      area = .5 * options.width * options.height;
      break;
  }
  return area;
}

getArea(shapeType.triangle, { width: 100, height: 100 });

Symbol属性名的遍历

使用常规的遍历对象属性名的方式是无法遍历出Symbol类型的属性名的。

Object.getOwnPropertySymbols()Reflect.ownKeys()可以遍历出Symbol属性名

利用这种无法被常规方法遍历到的特点可以为对象定义非私有的,但是只用于内部的方法,所以说可以用Symbol来模拟私有函数

Symbol.for(),Symbol.keyFor()

Symbol.for()方法可以传递一个字符串,然后根据这个字符串去查找全局有没有该Symbol值,如果有就返回原来的,没有的话就会创建一个新的,并且登记到全局环境,注意无论在什么地方执行Symbol.for()都会被登记到全局。

所以无论用同一个参数执行多少次Symbol.for()都会返回同一个结果,但是使用Symbol()每次都会返回一个新的。

Symbol.keyFor()方法可以返回一个已经登记了的SymbolkeySymbol.for()用来在全局做登记,只有使用Symbol.for()登记了的Symbol才可以使用Symbol.keyFor()方法获取到key

Symbol.for()的这个全局登记特性,可以用在不同的 iframeservice worker 中取到同一个值。

iframe = document.createElement('iframe');
iframe.src = String(window.location);
document.body.appendChild(iframe);

iframe.contentWindow.Symbol.for('foo') === Symbol.for('foo') // true

内置的一些Symbol的值

ES6 还提供了 11 个内置的 Symbol 值。

Symbol.hasInstance

var obj = {
    [Symbol.hasInstance]: function(instance) { // 改写了instanceof关键字
        console.dir(instance);
        return true;
    }
}
1 instanceof obj; // 1 true

Symbol.isConcatSpreadable

let arr2 = ['c', 'd'];
arr2[Symbol.isConcatSpreadable] = false; // 不允许arr2展开
['a', 'b'].concat(arr2, 'e') // ['a', 'b', ['c','d'], 'e']

Symbol.species

用来决定衍生对象的类型

查看原文

Symbol.match

用来改写自定义对象的match方法

var obj = {
    [Symbol.match]: function(str) {
        return "改写了match方法" + str;
    }
};

"xxx".match(obj); // "改写了match方法xxx"

Symbol.replace

用来改写自定义对象的replace方法

Symbol.search

用来改写自定义对象的search方法

Symbol.split

用来改写自定义对象的split方法

Symbol.iterator【重要】

对象的Symbol.iterator属性,指向该对象的默认遍历器方法,对象进行for...of循环时,会调用Symbol.iterator方法,返回该对象的默认遍历器

var obj = {};
obj[Symbol.iterator] = function* () {
    yield "来了";
    yield "老弟";
};
for (var i of obj) {
    console.dir(i)
}
// 来了
// 老弟

Symbol.toPrimitive

对象的Symbol.toPrimitive属性,指向一个方法。该对象被转为原始类型的值时,会调用这个方法,返回该对象对应的原始类型值。

var obj = {
    [Symbol.toPrimitive]: function(hint) {
        console.dir(hint);
        return 1000;
    }
};

2 * obj // number 2000
3 + obj // default 1003
String(obj) // string "1000"

Symbol.toStringTag

对象的Symbol.toStringTag属性,指向一个方法。在该对象上面调用Object.prototype.toString方法时,如果这个属性存在,它的返回值会出现在toString方法返回的字符串之中,表示对象的类型。也就是说,这个属性可以用来定制[object Object][object Array]object后面的那个字符串。

var obj = {
    [Symbol.toStringTag]: "自定义"
};
obj.toString() // "[object 自定义]"

Symbol.unscopables

对象的Symbol.unscopables属性,指向一个对象。该对象指定了使用with关键字时,哪些属性会被with环境排除

var obj = {
    foo: "bar", 
    [Symbol.unscopables]: {
        foo: true // 排除foo属性
    }
};

with(obj) {
    console.dir(foo) // Uncaught ReferenceError: foo is not defined
}