关于阅读 ES6- Symbol 整理的问题

1、ES6为什么引入 Symbol ?

答:ES5中的对象的属性名是字符串,属性名不能重复,否则会覆盖。
当你使用别人定义的对象,并想往里面添加新的方法,
如果方法名和对象中的属性名进行重复,就会造成覆盖的后果,
因此Symbol就是为了解决这个问题而产生的。

let obj = {
 [Symbol('a')]: 111,
 [Symbol('a')]: 222,
}

2、Symbol类型

答:Symbol值通过Symbol()函数进行生成,可作为对象的属性名。
Symbol类型的属性名是独一无二的,不会与其他属性名产生冲突。

let s1 = Symbol(), s2 = Symbol();
s1 == s2 // false
s1 === s2 // false

3、Symbol()函数怎么使用

答:可以接受一个字符串作为参数,表示对Symbol实例的描述
因此相同参数的Symbol函数的返回值是不一样的

let s = Symbol() // Symbol()
let s1 = Symbol('s1')// Symbol(s1)
s1.toString() // 'Symbol(s1)'

4、Symbol()函数的参数如果是一个对象,会如何处理

答:会先调用对象的 toString()方法,转为字符串,然后再转为 Symbol值

var o = {a: 111} 
var s = Symbol(o)// Symbol([object Object])

5、Symbol值可以和其他类型的值进行运算吗?

答:不能,会报错

6、Symbol值怎么显示的转换为字符串

答:分别使用 toString()方法或String()方法

var s = Symbol(11)
s.toString() // 'Symbol(11)'
String(s) // 'Symbol(11)'

7、Symbol值怎么显示的转换为布尔值

答:使用Boolean()方法
注意:Symbol值不能转换为数值

var s = Symbol(0)
Boolean(s) // true

8、如何获取Symbol的描述

答:通过Symbol的属性description

var s = Symbol('aa')
s.description // 'aa'

9、对象中如何设置Symbol作为对象的属性

答:有三种方式,具体如下:

let a = {}, s = Symbol()
a[s] = 'a' // 方式1

let b = {// 方式2
  [s]: 222, 
  [Symbol()]: 111 
}
let c = {}

Object.defineProperty(c, s, {value: 333}) // 方式3

10、获取对象中Symbol属性对应的值

答:使用数组获取值的方式,即:对象 [变量名] 格式
不能通过 对象.变量名 的方式进行获取

let s = Symbol()
let o = {[s]: 'Symbol值', s: 111}
o[s] // 'Symbol值'
o['s'] // 111
o.s // 111 实际上点号后面的变量名是字符串类型的

11、Symbol值可以有哪些作用

答:作为对象的属性名,保证独一无二,避免相同变量名出现的覆盖问题
定义为常量的值,保证值得独一无二
消除魔法字符串
扩展:Symbol值作为属性名,该属性是共有属性,不是私有属性

12、魔术字符串是什么

答:指的是在代码中多次出现的,与代码强耦合在一起的某一个具体字符串或者数值。
例如下面代码中switch语句中case的值 ‘child’

switch(type){
  case 'child':  // 'child' 为魔术字符串
    return 111;
    break;
}

13、怎么消除魔术字符串

答:改用变量进行代替

14、获取 对象中 Symbol类型的变量名

答:使用 Object.getOwnPropertySymbols(obj),得到以Symbol类型组成的数组
扩展:Symbol类型的属性名不能使用 for…in、 for…of 、Object.keys()、 Object.entries()、
Object.getOwnPropertyNames() 、JSON.Stringify() 遍历或者返回。
可以通过 Reflect.ownKeys()方法获取到所欲的类型的键名,包括常规键名和Symbol类型的键名

let o = {
  [Symbol('a')]: 1,
  [Symbol('b')]: 2
}
Object.getOwnPropertySymbols(o) // [Symbol(a), Symbol(b)]

15、如何实现重新使用同一个Symbol值

答:使用 Symbol.for(参数)

var s1 = Symbol.for(),    s2 = Symbol.for();        s1 === s2; // true
var s1 = Symbol.for(1),   s2 = Symbol.for(1);      s1 === s2;// true
var s1 = Symbol.for('a'),   s2 = Symbol.for('a');      s1 === s2;// true

16、Symbol和Symbol.for()有什么区别

答:两者都会生成新的Symbol值
Symbol.for()会被登记在全局进行搜索,不会每次调用都生成新的Symbol类型的值,
而是会检查key是否已经存在,如果不存在才会创建新的值。
Symbol()每次都是创建新的值,没有登记机制

17、Symbol.keyFor()方法

答:获取Symbol值登记的名字,无论有没有在全局环境中运行

let s1 = Symbol('a'), k1 = Symbol.keyFor(s1);
let s2 = Symbol.for('a'), k2 = Symbol.keyFor(s2);
let s3 = Symbol.for(), k3 = Symbol.keyFor(s3);
console.log(k1, k2, k3) // undefined   'a'  'undefined'

18、模块的Singleton模式

答:Singleton模式指的是调用同一个类,任何时候返回都是同一个实例。
可以通过将方法或者类或者文件挂在顶层对象的某个属性上,
由于普通属性可能有被覆盖的风险,那么可以使用Symbol类型的属性进行代替。

19、对象的Symbol.hasInstance属性作用

答:当在代码中使用 instanceof运算符,判断对象为某个对象的实例的时候,就会内部调用Symbol.hasInstance

class My{
  [Symbol.hasInstance](obj){
    return obj instanceof Array
   }
}
[1,2,3] instanceof new My() // true
var a = {} ;        
a instanceof new My() // false

20、对象的Symbol.isConcatSpreadable属性

答:当对象使用 Array.prototype.concat()方法时,是否时可展开的
数组的 Symbol.isConcatSpreadable属性值为 undefined 或者 true,进行concat拼接的时是可展开的
对象的 Symbol.isConcatSpreadable属性值为 false,进行concat拼接时不可展开,如需展开,可手动设置值为true

let obj = {length: 2, 0: 'a', 1: 'd'}
['a', 'b'].concat(obj, 'e') // ['a', 'b', obj, 'e']
obj[Symbol.isConcatSpreadable] = true
['a', 'b'].concat(obj, 'e') // ['a', 'b', 'a', 'd',  'e']

21、对象的Symbol.species属性

答:指向当前对象的构造函数,创建实例的时候会默认调用它

class My extends Array{
  static get [Symbol.species](){ return this} // 默认指向当前对象的构造函数my
}
var a = new My()
a instanceof My // true
下面代码中,修改调用构造函数的指向:
class My extends Array{
  static get [Symbol.species](){ return Array} // 指向当前对象的构造函数修改为 Array
}
var a = new My()
a instanceof My // false

22、对象的Symbol.match属性

答:该属性指向一个函数,当执行 str.match(obj)时能匹配到str属性,会调用这个属性对应的方法

class My{
  [Symbol.match](string){
     return 'Hello world' indexOf(string)
  }
}
'e'.match(new My()) // 1

23、对象的Symbol.replace属性

答:该属性指向一个方法。当对象被String.prototype.replace方法调用的时候,会调用该属性指向的方法
String.prototype.replace(searchValue, replaceValue) 等同于 searchValue[Symbol.replace](this, replaceValue)

var s = {}
s[Symbol.replace] = (...rest) => console.log(rest) // rest剩余参数,是一个数组
'hello'.replace(s, 'world') // ['hello', 'world']    ,这里Symbol.replace接收两个参数 'hello' 和 'world'

24、对象的Symbol.search属性

答:该属性指向一个方法。当对象被String.prototype.search方法调用的时候,会调用这个属性指向的方法
String.prototype.search(regexp) 等同于 regexpSymbol.search

class MySearch {
  constructor(value) {
    this.value = value;
  }
  [Symbol.search](string) {
    return string.indexOf(this.value);
  }
}
'foobar'.search(new MySearch('foo')) // 0

25、对象的Symbol.split属性

答:该属性指向一个方法。当对象被String.prototype.split方法调用的时候,会调用这个属性指向的方法
String.prototype.split(separator, limit) // 等同于 separator[Symbol.split](this, limit)

class MySplitter {
  constructor(value) {
    this.value = value;
  }
  [Symbol.split](string) {
    let index = string.indexOf(this.value);
    if (index === -1) {
      return string;
    }
    return [
      string.substr(0, index),
      string.substr(index + this.value.length)
    ];
  }
}
'foobar'.split(new MySplitter('foo'))// ['', 'bar']

26、对象的Symbol.iterator属性

答:该属性指向对象的默认遍历器方法

const myIterable = {};
myIterable[Symbol.iterator] = function* () {
  yield 1;
  yield 2;
  yield 3;
};
[...myIterable] // [1, 2, 3]

27、对象的Symbol.toPrimitive属性

答:该属性指向一个方法。当该对象转换为原始数据类型的值时,会调用该属性指向的方法。
该属性对应的方法有个字符串形式的入参,表示当前运算的模式。
一共有三种模式:
Number 转为数值
String 转为字符串
Default 转为数值或者字符串

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

28、对象的Symbol.toStringTag属性

答:该属性指向一个方法。当在对象中调用 Object.propotype.toString方法时,会调用该属性指向的方法。
这个方法中可以用来定制 ‘[object Object]’ 或者 '[object Array]'中 object后面那个字符串

({[Symbol.toStringTag]: 'Foo'}.toString())  // '[object Foo]'
class Collection {
  get [Symbol.toStringTag]() {
    return 'xxx';
  }
}
let x = new Collection();
Object.prototype.toString.call(x) // "[object xxx]"

29、ES6 新增内置对象的Symbol.toStringTag属性值有哪些

答:共13种

JSON[Symbol.toStringTag]'JSON'

Math[Symbol.toStringTag]'Math'

Module 对象M[Symbol.toStringTag]'Module'

ArrayBuffer.prototype[Symbol.toStringTag]'ArrayBuffer'

DataView.prototype[Symbol.toStringTag]'DataView'

Map.prototype[Symbol.toStringTag]'Map'

Promise.prototype[Symbol.toStringTag]'Promise'

Set.prototype[Symbol.toStringTag]'Set'

%TypedArray%.prototype[Symbol.toStringTag]'Uint8Array'WeakMap.prototype[Symbol.toStringTag]'WeakMap'

WeakSet.prototype[Symbol.toStringTag]'WeakSet'

%MapIteratorPrototype%[Symbol.toStringTag]'Map Iterator'

%SetIteratorPrototype%[Symbol.toStringTag]'Set Iterator'

%StringIteratorPrototype%[Symbol.toStringTag]'String Iterator'

Symbol.prototype[Symbol.toStringTag]'Symbol'

Generator.prototype[Symbol.toStringTag]'Generator'

GeneratorFunction.prototype[Symbol.toStringTag]'GeneratorFunction'

30、对象的Symbol.unscopables属性

答:该属性指向一个对象。当使用with关键字时,哪些属性会被with环境排除
Array.prototype[Symbol.unscopables] // 默认如下设置,有7个属性被with命令排除

/*{
//   copyWithin: true,
//   entries: true,
//   fill: true,
//   find: true,
//   findIndex: true,
//   includes: true,
//   keys: true
 }
*/
//----------------没有 unscopables 时----------------
class MyClass {
  foo() { return 1; }
}
var foo = function () { return 2; };
with (MyClass.prototype) {
  foo(); // 1
}
//------------------------有 unscopables 时-----------------
class MyClass {
  foo() { return 1; }
  get [Symbol.unscopables]() {
    return { foo: true };
  }
}
var foo = function () { return 2; };
with (MyClass.prototype) {
  foo(); // 2
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值