【JavaScript手写篇】基础对象操作之手写 Object.create()


Object.create() 是 JavaScript 中用于创建新对象的核心方法之一。它允许你指定新对象的原型([[Prototype]],是实现原型继承最直接、最纯粹的方式。


一、Object.create() 做了什么事情?

1. 基本语法

Object.create(proto, propertiesObject)
  • proto:新创建对象的原型对象(可以为 null)。
  • propertiesObject(可选):一个对象,其自身可枚举属性作为新对象的属性描述符。

2. 核心功能

  • 创建一个新对象
  • 将该对象的内部 [[Prototype]] 指向传入的 proto
  • 可选地,通过 propertiesObject 定义新对象自身的属性(使用属性描述符)。

3. 示例

const parent = {
  sayHello() {
    console.log('Hello!');
  }
};

const child = Object.create(parent, {
  name: {
    value: 'Alice',
    writable: true,
    enumerable: true,
    configurable: true
  }
});

console.log(child.name);        // 'Alice'
child.sayHello();               // 'Hello!'(继承自 parent)
console.log(Object.getPrototypeOf(child) === parent); // true

二、手写 Object.create() 的实现思路

核心目标

  1. 创建一个新对象。
  2. 设置其原型为 proto
  3. 如果提供了 propertiesObject,使用 Object.defineProperties 定义属性。
  4. 处理边界情况(如 protonull 或非对象)。

实现步骤

  1. 类型检查:确保 protonullobject,否则抛出 TypeError
  2. 创建对象:可用构造函数 + new,或直接 {}
  3. 设置原型
    • 使用 F.prototype = proto + new F(),或
    • 使用 Object.setPrototypeOf()
  4. 定义属性:使用 Object.defineProperties(obj, propertiesObject)
  5. 返回对象

三、手写实现

基础版(不支持 propertiesObject

function create(proto) {
  // 1. 类型检查
  if (typeof proto !== 'object' && typeof proto !== 'function' && proto !== null) {
    throw new TypeError('Object prototype may only be an Object or null');
  }

  // 2. 创建一个空构造函数
  function F() {}
  // 3. 将其 prototype 指向 proto
  F.prototype = proto;
  // 4. 创建新对象,其 __proto__ 指向 proto
  const obj = new F();

  // 5. 特殊处理 proto 为 null 的情况
  if (proto === null) {
    return Object.setPrototypeOf({}, null);
  }

  return obj;
}

注意:new F() 无法创建 [[Prototype]]null 的对象,因为当 F.prototypenull 时,实例的 [[Prototype]] 会退回到 Object.prototype


完整版(支持 propertiesObjectnull 原型)

function create(proto, propertiesObject) {
  // 1. 类型检查
  if (typeof proto !== 'object' && typeof proto !== 'function' && proto !== null) {
    throw new TypeError('Object prototype may only be an Object or null');
  }

  // 2. 创建新对象
  let obj;
  if (proto === null) {
    obj = Object.setPrototypeOf({}, null);
  } else {
    function F() {}
    F.prototype = proto;
    obj = new F();
  }

  // 3. 如果传入 propertiesObject,定义属性
  if (propertiesObject !== undefined) {
    Object.defineProperties(obj, propertiesObject);
  }

  return obj;
}

更现代的实现(推荐)

function create(proto, propertiesObject) {
  // 1. 类型检查
  if (typeof proto !== 'object' && typeof proto !== 'function' && proto !== null) {
    throw new TypeError('Object prototype may only be an Object or null');
  }

  // 2. 创建空对象
  const obj = {};

  // 3. 设置原型
  Object.setPrototypeOf(obj, proto);

  // 4. 定义属性(可选)
  if (propertiesObject) {
    Object.defineProperties(obj, propertiesObject);
  }

  return obj;
}

推荐使用此版本:逻辑清晰,兼容 null 原型,代码简洁。


四、测试实现

// 测试 1:正常继承
const parent = { greet() { console.log('Hello!'); } };
const child = create(parent);
child.greet(); // 'Hello!'
console.log(Object.getPrototypeOf(child) === parent); // true

// 测试 2:null 原型
const obj = create(null);
console.log(Object.getPrototypeOf(obj)); // null
console.log(obj.toString); // undefined

// 测试 3:带属性定义
const person = create(
  { species: 'Human' },
  {
    name: {
      value: 'Alice',
      writable: true,
      enumerable: true,
      configurable: true
    }
  }
);
console.log(person.name);       // 'Alice'
console.log(person.species);    // 'Human'

五、与 new 的区别

对比项Object.create(proto)new Constructor()
原型设置直接指定原型对象原型来自 Constructor.prototype
构造函数不调用构造函数调用 Constructor 函数
适用场景纯原型继承、对象字面量继承构造函数模式、类继承

使用场景对比

// Object.create 更适合“直接继承一个对象”
const animal = { sleep() { console.log('zzz'); } };
const rabbit = Object.create(animal);

// new 更适合“通过构造函数创建实例”
function Dog(name) { this.name = name; }
Dog.prototype.bark = function() { console.log('Woof!'); };
const dog = new Dog('Rex');

六、总结

Object.create() 做了什么?

  • 创建一个新对象。
  • 设置其 [[Prototype]] 为指定对象(或 null)。
  • 可选地定义自身属性。

手写实现思路:

  1. 类型检查:确保 proto 合法。
  2. 创建对象:可用 new F(){}
  3. 设置原型:通过 F.prototypeObject.setPrototypeOf
  4. 定义属性:使用 Object.defineProperties
  5. 返回对象。

建议

  • 优先使用 Object.setPrototypeOf 版本,更简洁。
  • 解释清楚 null 原型的处理。
  • 对比 newObject.create 的使用场景。

掌握 Object.create 的实现,就掌握了 JavaScript 原型继承的本质。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值