JS面试手写:创造没有原型的对象

316 阅读2分钟

如何创建一个没有原型的对象?

最开始的想法是:直接将新创建的对象的__proto__改为null就好了

追问:有什么方法可以直接拿到吗?

const specialObj = Object.create(null);
console.log(specialObj.__proto__); // undefined

继续追问:这个Object.create干了什么呢?能仿写一个吗?

Object.create方法用于创建一个新对象,使用现有的对象(传入的参数)来作为新创建对象的原型

function createObject(o) { 
    function Fn() {} 
    Fn.prototype = o 
    return new Fn() 
}

追问:Object.create只能有一个参数吗?

// 可以有两个参数:
// proto: 新创建对象的原型对象
// propertiesObject: 如果该参数被指定且不为undefined,则该传入对象的自有可枚举属性(即其自身定义的属性,而不是其原型链上的枚举属性)将为新创建的对象添加指定的属性值和对应的属性描述符。这些属性对应于Object.defineProperties()的第二个参数。
// 简单来说:第一个参数会是新对象的原型,第二个参数是新对象的属性
// Object.create(proto, propertiesObject)

// 案例:
let o = Object.create(Object.prototype, {
  // foo is a regular 'value property'
  foo: {
    writable: true,
    configurable: true,
    value: 'hello'
  },
  // bar is a getter-and-setter (accessor) property
  bar: {
    configurable: false,
    get: function() { return 10; },
    set: function(value) {
      console.log('Setting `o.bar` to', value);
    }
  }
})

console.log(o)
// 得到:
// {bar: 10, foo: "hello", get bar: ƒ (), set bar: ƒ (value), [[Prototype]]: Object }

继续追问:既然提到了原型,那么写一下寄生组合式继承吧

// 实现寄生组合式函数继承核心函数之一:原型继承式函数(旧写法需要用到)
function createObject(o) {
  function Fn() {}
  Fn.prototype = o
  return new Fn()
}
// 实现寄生组合式函数继承核心函数之一:寄生式继承
function inheritPrototype(SubType, SuperType) {
  // 旧的写法
  SubType.prototype = createObject(SuperType.prototype)
  // 新的写法
  // SubType.prototype = Object.create(SuperType.prototype)
  // 这一步是为了让新创建的原型对象中的constructor指向先前的构造函数
  Object.defineProperty(SubType.prototype, "constructor", {
    enumerable: false,
    configurable: true,
    writable: true,
    value: SubType
  })
}