JS手写ES6的Object.create方法

2,006 阅读2分钟

我正在参加「掘金·启航计划」

方法介绍

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

用法:

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

Object.defineProperties()方法直接在一个对象上定义新的属性或修改现有属性,并返回该对象。

Object.defineProperties()使用示例:

let obj1 = { a: 2, b: 3 }

Object.defineProperties(obj1, {
  a: {
    enumerable: false, // 数据、存储描述符号
    configurable: false, // 数据描述符
    writable: false, // 数据描述符
    value: 'xxx' // 数据描述符号
    get: function(){}, // 储存描述符
    set: function(){} // 储存描述符
  }
})

有关Object.defineProperties()的具体细节请看我的这篇文章:戳我传送

Object.create 返回值:一个新对象,带着指定的原型对象及其属性。

使用Object.create(null)的原因

很多框架源码作者使用它来初始化一个新的对象,难道是最佳实践?

通过Object.create(null)创建出来的对象,没有任何属性,显示No properties。我们可以将其当成一个干净的 map 来使用,自主定义 toString,hasOwnProperty等方法,并且不必担心将原型链上的同名方法被覆盖。

注意: {...}创建的对象,使用for in遍历对象的时候,会遍历原型链上的属性,带来性能上的损耗。使用Object.create(null)则不必再对其进行遍历了。

框架源码对性能的要求极高,哪怕是一点点,都值得关注。

开始手写

// 第一个参数传递null时,返回的实例原型为null
// 第一个参数类型只能是object、function或者null,否则报错。
// 第二个参数类型,不能是null,否则报错
// 第二个参数如果不为 undefined ,需要将其挂载到实例的  Object.defineProperties 上。

Object.mjy_create = function(proto, defineProperties) {
    if ( typeof proto !== 'object' && typeof proto !== 'function' ) {
      throw new TypeError(`Object prototype may only be an Object or null: ${proto}`)
    }
    if ( defineProperties === null ) {
      throw new TypeError('Cannot convert undefined or null to object')
    }
  
  	// 定义新对象 
      const obj = {}
    
      // 设置原型
      // obj.__proto__ = proto // 不建议这么做了
      // 通常,应该使用 Object.setPrototypeOf() 方法来设置对象的原型。
      // 因为 Object.prototype.__proto__ 访问器已被弃用。
       Object.setPrototypeOf(obj, proto) // 建议使用setPrototypeOf设置原型

    if ( defineProperties !== undefined ) {
      Object.defineProperties(obj, defineProperties)
    }
    return obj
  }
  let obj1={b:2}
  let obj2 = Object.mjy_create(obj1, { a: { enumerable: false } })
  console.log(obj2)//{}
  let obj2_ = Object.mjy_create(obj1, { a: { enumerable: true } })
  console.log(obj2_)//{ a: undefined }
  let obj3 = Object.create('222', undefined) // TypeError: Object prototype may only be an Object or null: 222
  let obj4 = Object.create(obj1, null) // TypeError: Cannot convert undefined or null to object
  console.log(obj2.a) // undefined