出处:掘金

原作者:金泽宸


为什么要手写 Object.create

在面试、框架源码中,它经常出现:

  • 用于原型继承的核心方法
  • 被用在 new 实现、寄生组合继承、polyfill 中
  • 许多框架如 Vue 早期的继承方案中使用它创建 prototype chain

Object.create(proto) 原理回顾

这个方法的作用是:创建一个新对象,这个对象的 __proto__ 会指向传入的 proto

举例:

const a = Object.create({ x: 1 });
console.log(a.x); // 1(通过原型访问到)
console.log(a.__proto__); // { x: 1 }

最简单实现版本

function myCreate(proto) {
  function F() {}
  F.prototype = proto;
  return new F();
}

测试验证

const parent = { sayHi() { console.log('hi'); } };
const child = myCreate(parent);
 
console.log(child.__proto__ === parent); // true
child.sayHi(); // hi

补充细节(ES5 语义补全)

原生 Object.create 第二个参数可以传入属性描述符:

Object.create(proto, {
  name: {
    value: 'Mark',
    enumerable: true
  }
});

这是面试高级考法,Polyfill 实现如下:

function myCreate(proto, properties) {
  if (typeof proto !== 'object' && typeof proto !== 'function' || proto === null) {
    throw new TypeError('proto must be object or function and not null');
  }
 
  function F() {}
  F.prototype = proto;
 
  const obj = new F();
 
  if (properties !== undefined) {
    Object.defineProperties(obj, properties);
  }
 
  return obj;
}

常见易错点

错误理解正确做法
认为会拷贝属性❌ 实际是“链接”原型,不复制
忘记判断 proto 非空对象应做类型校验
误以为可以用于多继承JS 不支持真正的多继承,只有多重原型链查找

扩展

自己封装 inherits(child, parent) 工具函数

function inherits(child, parent) {
  child.prototype = Object.create(parent.prototype);
  child.prototype.constructor = child;
}