ES6 Symbol的属性(well-known symbol)

版权声明:本文为个人知识整理,欢迎指正、交流、转载。 https://blog.csdn.net/u014711094/article/details/80917916
  • Symbol.hasInstance

The Symbol.hasInstance well-known symbol is used to check if an object constructor recognizes an object as its instance. The instanceof operator’s behavior can be customized by this symbol.
operator

class ArrayA {
  static [Symbol.hasInstance] (o) {
    return Object.prototype.toString.call(o)
  }
}

[] instanceof ArrayA            // true, 相当于执行下句
ArrayA[Symbol.hasInstance]([])  // true
  • Symbol.iterator

The Symbol.iterator specifics the default iterator of an object. Used by for ... of.

let o = {}

o[Symbol.iterator] = function* () {
  yield 1
  yield 2
  yield 3
}

console.log([...o])     // [1, 2, 3]
for (let v of o) {
  console.log(v)
}
// 1, 2, 3
let s1 = 'this'

s1['a'] = 0
// 在值类型(primitive type)变量上添加属性无效
Object.getOwnPropertyNames(s1)
// ['0', '1', '2', '3', 'length']
s1['a']                 // undefined

function* gen() = {yield* [1, 2, 3]}
s1[Symbol.iterator] = () => gen()
// 仍然是调用的String.prototype[Symbol.iterator]
[...s1]     // ['t', 'h', 'i', 's']
s1[Symbol.iterator]     // [Function: [Symbol.iterator]]

let s2 = new String('this')
s2 = () => gen()
[...s2]     // [1, 2, 3]
  • Symbol.toStringTag

The Symbol.toStringTag well-known symbol specifics a string valued property in the creation of string description of an object. It is accessed internally by the Object.prototype.toString() method.

let toStringTag = function(o) {
  return Object.prototype.toString.call(o)
}

// 基本数据类型
toStringTag(1)          // '[object Number]'
toStringTag(true)       // '[object Boolean]'

// 内建数据结构,GeneratorFunction/RegExp/Array/Map等
toStringTag(function(){})           // '[object Function]'
toStringTag(Promise.resolve(1))     // '[object Promise]'
toStringTag(new Set())              // '[object Set]'

// 新建类
class ClassA {}
class ClassB {
  // 一个getter
  get [Symbol.toStringTag] () { return 'B' }
}

toStringTag(new ClassA())   // '[object Object]', 默认
toStringTag(new ClassB())   // '[object B]', 仍然有前面的object
  • Symbol.match

The Symbol.match well-known symbol specifics the matching of a regular expression against a string. The function is called by the String.prototype.match() method.

let r = /is/
let s = 'this is a test.'

let arr = s.match(r)    // ['is', index: 2, input: 'this is a test.']
r[Symbol.match](s)      // 同上句

arr instanceof Array    // true, 返回数组
for (let k in arr) {
  console.log(k, arr[k])
}
// 0 'is', index 2, input: '...'

/is/g[Symbol.match](s)  // ['is', 'is']
s.match(/abc/)          // null, 注意不是[]和undefined  

The subclass of RegExp can override the [@@match]() method to modify the default behavior.

class RegExpA extends RegExp {
  [Symbol.match] (str) { return 1 }
}

'this'.match(new RegExpA(/is/))     // 1, 始终返回1

The function is also used to identify if an object has behavior of regular expression. For example, the methods String.prototype.startsWith(), String.prototype.endsWith() and String.prototype.includes() check if the first argument is a regular expression object, and will throw a TypeError if they are. Now, if the match symbol is set to false (or a falsy value), it indicates that the object is not intended to be used as a regular expression object.

let r = /is/
let s = 'th/is/'

s.includes(r)
// TypeError:First argument to String.prototype.includes
// must not be a regular expression.

r[Symbol.match] = false // 或其他falsy(0, '', undefined, null, ...)
s.includes(r)           // true
  • Symbol.search Symbol.replace Symbol.split
class MyClass {
  constructor (val) {
    this.val = val
  }
  [Symbol.search] (str) {
    return this.val + str[0]
  }
  [Symbol.replace] (str) {
    return this.val + str[1]
  }
  [Symbol.split] (str) {
    return this.val + str[2]
  }
}

let s1 = 'this'
let s2 = new MyClass('is')

// Object.prototype的方法默认调用MyClass.prototype上对应的symbol
s1.search(s2)   // ist
s1.replace(s2)  // ish
s1.split(s2)    // isi
  • Symbol.toPrimitive

The Symbol.toPrivitive well-known symbol specifics a funcion valued property that is called to convert an object to a corresponding primitive value.

let o = {}

console.log(+o, `${o}`, o + '', o + 1)
// NaN, '[object Object]', '[object Object]', '[object Object]1'

o[Symbol.toPrimitive] = function(hint) {
  if (hint == 'number') return 1
  if (hint == 'string') return 's'
  return 'o'
}


console.log(+o, `${o}`, o + '', o + 1)
// 1, 's', 'o', 'o1'
  • Symbol.isConcatSpreadable

The Symbol.isConcatSepreadable well-known symbol is used to config if an object should be flattened to its array elements when using the Array.prototype.concat() method.

let arr1 = [1, 2, 3]
let arr2 = [4, 5]
let fakeArr = {
  '0': 4,
  '1': 5,
  length: 2
}

arr1.concat[arr2]       // [1, 2, 3, 4, 5]
arr1.concat[fakeArray]  // [1, 2, 3, {...}]

arr2[Symbol.isConcatSpreadable] = false
o[Symbol.isConcatSpreadable] = true

arr1.concat[arr2]
// [1, 2, 3, [4, 5, [Symbol.isConcatSpreadable]: false]]
arr1.concat[fakeArray]  // [1, 2, 3, 4, 5]
  • Symbol.species

The Symbol.species well-known symbol specifics a function-value property that the constructor function uses to create the derived objects.

class ArrayA extends Array {}
class ArrayB extends Array {
  static get [Symbol.species] () { return Array }
}

let a = new ArrayA(...[1, 2, 3])
let b = new ArrayB(...[1, 2, 3])

let mapA = a.map(val => val)
let sliceA = a.slice()

let mapB = b.map(val => val)
let slcieB = b.slice()

a instanceof Array          // true
a instanceof ArrayA         // true

mapA instanceof ArrayA      // true
sliceA instanceof ArrayA    // true

b instanceof Array          // true
b instanceof ArrayB         // true

mapB instanceof Array       // true
mapB instanceof ArrayB      // false,衍生对象不是ArrayB的实例

slice instanceof Array      // true
sliceB instanceof ArrayB    // false,衍生对象不是ArrayB的实例
  • Symbol.unscopables
// with相关

参考:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol

猜你喜欢

转载自blog.csdn.net/u014711094/article/details/80917916