azl397985856 / fe-interview

宇宙最强的前端面试指南 (https://lucifer.ren/fe-interview)
Apache License 2.0
2.84k stars 260 forks source link

【每日一题】- 2019-11-19 - 模拟实现es6的symbol #64

Closed azl397985856 closed 4 years ago

azl397985856 commented 4 years ago

模拟实现es6的symbol

stale[bot] commented 4 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

azl397985856 commented 4 years ago

一点点背景

symbol是ES6新加的基本数据类型。 我们先来看下基本用法:

  1. 创建一个新的symbol(注意不能是new)
    let symbol = Symbol()
    typeof symbol // "symbol"
  2. 每次创建的都不相同,有点像uuid

let symbol1 = Symbol()
let symbol2 = Symbol()

symbol1 === symbol2 // false

let symbol3 = Symbol('lucifer')
let symbol4 = Symbol('lucifer')

symbol3 === symbol4 // false
  1. 可以当对象的key用(之前只能是字符串类型)
const SECRET = Symbol('secret')
let data = { }
data[SECRET] = 10
let newData = Object.assign({ }, data)

Object.getOwnPropertyNames(data)  // []
(SECRET in data)                  // true
(SECRET in newData)               // true
  1. 有一些内置的symbol类型。 比如Symbol.match ,Symbol.iterator等
const MATCH = RegExp.prototype[Symbol.match]

RegExp.prototype[Symbol.match] = function(searchString) {
  return !!MATCH.call(this, searchString) // return true or false
}

"foo".match(/foo/) // true
"foo".match(/bar/) // false

开始

我们首先实现uuid函数。

function uuidv4() {
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
    var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
    return v.toString(16);
  });
}

然后我们创建一个函数,就叫mySymbol好了。

function mySymbol(memo) {
   return uuidv4()
}

我们再来挂在几个内置symbol。

mySymbol.match = uuid()
mySymbol.iterator = uuid()

最后我们来实现symbol.for:

mapper = {}
mySymbol.for = (name) => {
  if (name in mapper) {
    return mapper[name]
  }
  const res = uuid()
  mapper[res] = res
  return res
}