ES6之Symbol
来源:互联网 发布:淘宝怎么赚集分宝 编辑:程序博客网 时间:2024/06/04 17:44
Symbol
Symbol 是一种互不等价的标志,字面量对象除了可以使用字符串、数字作为属性键以外,还可以使用 Symbol 作为属性键,因此便可以利用 Symbol 值的互不等价特性来实现属性操作的互不干扰。
目录:
- Symbol
- 基本语法
- 生成唯一的 Symbol 值
- 注册全局可重用 Symbol
- 获取全局 Symbol 的 key
- 常用 Symbol 值
- iterator
- hasInstance
- match
- unscopables
- toPrimitive
- toStringTag
- 基本语法
基本语法
生成唯一的 Symbol 值
执行 Symbol([description]) 函数可以生成一个与其他 Symbol 值互不等价的 Symbol 值,其中 Symbol() 函数可以接受一个除 Symbol 值以外的值作为该 Symbol 值的描述,以便通过开发者的辨认判断其为可选的。
const symbol = Symbol(); // Symbol()const symbolForSomething = Symbol('something'); // Symbol(something)const symbolWithNumber = Symbol(3.14); // Symbol(3.14)const symbolWithObject = Symbol({'foo': 'bar'}); // Symbol([object Object])// Don't use a symbol to be another symbol's descriptionconst anotherSymbol = Symbol(symbol); // Uncaught TypeError: Cannot convert a Symbol value to a string
需要注意的是,我们设定的描述仅仅是起到了描述的作用,而不会对 Symbol 值本身起到任何的改变作用,因此,即使是两个具有相同描述值的 Symbol 值也并不具有等价性。
const symbol1 = Symbol('foo');const symbol2 = Symbol('foo');symbol1 == symbol2; // false
还要非常注意的一点是, Symbol 函数并不是一个构造函数,所以开发者不能使用 new 语句来生成一个 Symbol “对象”,否则将会抛出一个 TypeError 错误。
new Symbol(); // Uncaught TypeError: Symbol is not a constructor
由此可知,Symbol 是一种值类型而非引用类型,这就意味着如果将 Symbol 值作为函数形参进行传递,将会进行复制值传递而非引用传递,这跟其他值类型(字符串、数字等)的行为是一致的。
const symbol = Symbol('hello');function fn1(_symbol){ return _symbol == symbol;}console.log(fn1(symbol)); // truefunction fn2(_symbol){ _symbol = null; console.log(_symbol);}fn2(symbol); // nullconsole.log(symbol); // Symbol(hello)
当然,如果真的希望得到一个 Symbol “对象”,可以使用 Object() 函数实现。
const symbol = Symbol('foo');typeof symbol; // symbolconst symbolObj = Object(symbol);typeof symbolObj; // object
注册全局可重用 Symbol
开发者可以通过一个 key 向当前运行时注册一个需要在其他程序中使用的 Symbol:Symbol.for([key]) : Symbol
cosnt symbol = Symbol.for('foo');
Symbol.for() 与 Symbol() 区别是,Symbol.for() 会根据传入的 key 在全局作用域中注册一个 Symbol 值,如果某一个 key 从未被注册到全局作用域中,便会创建一个 Symbol 值并根据 key 注册到全局环境中,如果该 key 已被注册,就会返回一个与第一次使用创建的 Symbol 的值等价的 Symbol 值。
const symbol = Symbol.for('foo');const obj = {};obj[symbol] = 'bar';// ...const anotherSymbol = Symbol.for('foo');console.log(symbol === anotherSymbol); // trueconsole.log(obj[anotherSymbol]); // bar
获取全局 Symbol 的 key
用法:Symbol.keyFor(<global symbol>) : String
。
const symbol = Symbol.for('foo');console.log(Symbol.keyFor(symbol)); // foo
常用 Symbol 值
iterator
在 ES6 中定义了可迭代对象(Iterable Object)和新的 for-of 循环语句,其中可迭代对象并不是一种类型,而是带有@@iterator 属性和可以被 for-of 循环语句所遍历的对象的统称。
ES6 中默认的可迭代对象有: 数组(Array)、字符串(String)、类型数组(TypedArray)、映射对象(Map)、集合对象(Set)和生成器实例(Generator),而在浏览器的运行环境中,DOM 元素集合(如 NodeList) 也是可迭代对象。
// Arrayfor(const el of [1, 2, 3]) console.log(el);// Stringfor(const word of 'hello world') console.log(word);// TypedArrayfor(const value of new Uint8Array([0x00, 0xff])) console.log(value);// Mapfor(const entry of new Map([['a', 1], ['b', 2]])) console.log(entry);// Setfor(const el of new Set([1, 2, 3, 3, 3])) console.log(el);// Generatorfunction* fn(){ yield 1; }for(const value of fn()) console.log(value);
可迭代对象都会有一个使用 Symbol.iterator 作为方法名的属性,该方法会返回一个迭代器(Iterator)。把迭代器看作一种协议,即迭代器协议(Iterator Protocol),该协议定义了一个方法 next(),含义是进入下一次迭代的迭代状态,第一次执行返回第一次的迭代状态,该迭代状态对象需要带有两个属性。
利用 Symbol.iterator 在对象中实现一个迭代器需要将 Symbol.iterator 作为属性键,定义一个方法。
实现单向链表:
class Item{ constructor(value, prev = null, next = null){ this.value = value; this.next = next; } get hasNext(){ return !!this.next}}class LinkedList{ constructor(iterable){ /* ... */} push(value){ /* ... */} pop(){ /* ... */} // ... get length(){ /* ... */} get head(){ /* ... */} get tail(){ /* ... */}}
为其定义相关方法,使其支持 for-of 循环语句的迭代,首先为链表类添加一个以 Symbol.iterator 为属性键的方法:
class LinkedList{ [Symbol.iterator](){ // ... }}
假设我们需要让链表对象在 for-of 循环语句中是顺序遍历的,那么就可以将每一个元素都作为迭代器的一个状态:
[Symbol.iterator](){ let currItem = {next: this.head} return { next(){ currItem = currItem.next; currItem.next = currItem.next || {hasNext: false} return { value: currItem.value, done: !currItem.hasNext } } }}
此处需要注意的是,迭代器需要以一个空状态作为结束标志,也就是说即使迭代器遍历到了需要输出的最后一个元素,其所对应的状态依然是未结束状态(done: false),所以最后需要再输出一个空状态来表示结束。
hasInstance
Symbol.hasInstance 为开发者提供了可以用于扩展 instanceof 语句内部逻辑的权限,开发者可以将其作为属性键,用于为一个类定义静态方法,该方法的第一个形参便是被检测的对象,而该方法的返回值便是决定了当次 instanceof 语句的返回结果。
class Foo{ static [Symbol.hasInstance](obj){ console.log(obj); // {} return true; }}console.log({} instanceof Foo); // true
match
开发者可以通过 Symbol.match 来自行实现 match() 方法的运行逻辑。
const re = /foo/;re[Symbol.match] = function(str){ const regexp = this; console.log(str); // bar // ... return true;}'bar'.match(re); // true
unscopables
with 语句的作用是将一个对象变成一段代码的上下文,在这段代码中变量或者表达式的寻找都会先从这个对象的属性开始,但有些方法是不能被 with 语句所展开的,也就是说不能被 with 语句所包含的代码检索到。
const arr = [1, 2, 3, 4, 5];with(arr){ console.log(slice(0, 3)); // [1, 2, 3] console.log(entries()); // ReferenceError: entries is no defined}
能不能被检索到都是通过 Symbol.unscopables 作为属性键所定义的,我们可以尝试着把 Array 类型的 entries 方法设置为 false(为 true 表示该属性禁止在 with 语句中被使用):
const arr = [1, 2, 3, 4, 5];arr[Symbol.unscopables].entries = false;with(arr){ console.log(entries()); // ArrayIterator {}}
这也可以用在开发者自行创建的对象中:
const data = { foo: 1, bar: 2, something:3}const something = 'boom';data[Symbol.unscopables] = { foo: true, bar: false, something: true}with(data){ console.log(bar); // 2 console.log(something); // boom console.log(foo); // ReferenceError: foo is no defined}
toPrimitive
Symbol.toPrimitive 提供给开发者自定义处理引用类型的对象转化为值类型的控制。
开发者可以使用 Symbol.toPrimitive 作为属性键为对象定义一个方法,这个方法接受一个参数,这个参数用于判断当前隐式转换的目标类型。
需要注意的式,这里的 default 并不是因为目标类型无法被转换,而是因为语法上容易造成混乱,比如: 10 + obj + “” ,处于严谨,在 ES6 中被定义为 default ,由开发者自行决定:
const obj = {};console.log(+obj); // NaNconsole.log(`${obj}`); // [object Object]console.log(obj + ""); // [object Object]const Ten = { [Symbol.toPrimitive](hint){ switch(hint){ case 'number': return 10; case 'string': return 'Ten'; case 'default': return true; } }}console.log(+Ten); // 10console.log(`${Ten}`); // Tenconsole.log(Ten + ""); // true
toStringTag
Symbol.toStringTag 的作用式可以决定这个类的实例在调用 toString() 方法时的标签内容:
class Bar{};class Foo{ get [Symbol.toStringTag](){ return 'bar'; }}const obj = new Foo();console.log(obj.toString()); // [object Bar]
- ES6之路--Symbol
- ES6之Symbol
- ES6入门之Symbol
- ES6之Symbol
- ES6之Symbol
- ES6学习笔记之Symbol
- ES6学习笔记之《Symbol》
- 学习笔记:ES6之Symbol
- ES6--Symbol
- ES6 symbol
- 【ES6】symbol
- es6-symbol
- ES6--symbol
- 【es6】symbol
- es6->Symbol
- 初步探究ES6之Symbol类型
- ES6新特性之Symbol使用细节
- ES6学习之路10----Symbol
- Fiddler实现会话的过滤,对比以及请求的编解码
- python的dataframe转换为多维矩阵
- Conda虚拟环境
- BitmapFactory Decode大小的时候需要获取所有的流文件吗?
- TensorFlow中global_step的简单分析
- ES6之Symbol
- Advanced Programming in UNIX Environment Episode 14
- 6.3
- HDFS文件
- 摧毁数组
- 摩尔定律对IT未来发展的影响
- ArrayList 的实现分析
- 那些年在Opencv遇到过的Mat坑
- CSS中上下左右提示框主要代码