出处:掘金
原作者:金泽宸
为什么要手写 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;
}