Object.create继承

用Object.create()来实现继承

首先了解下这个方法

Object.create() 是什么?

Object.create(A, propertiesObject) 用来创建一个新对象 ,并且把它的原型(__proto__)设置为 A

ini 复制代码
const person = {
  greet() {
    console.log(`Hi, I am ${this.name}`);
  }
};

const tom = Object.create(person); // 以 person 作为tom的原型
tom.name = "Tom";

tom.greet(); // Hi, I am Tom

这里:

  • tom.__proto__ === person
  • tom 自己没有 greet,所以会顺着原型链去 person 找。### 第二个参数(可选)

你还可以传入属性描述符:

js 复制代码
const obj = Object.create({}, {
  name: {
    value: "Alice",
    writable: false,   // 不可修改
    enumerable: true,  // 可枚举
    configurable: false // 不可删除
  }
});

console.log(obj.name); // Alice
obj.name = "Bob";      // 修改无效
console.log(obj.name); // Alice

常见用途

  1. 继承

    js 复制代码
    function Animal(name) {
      this.name = name;
    }
    Animal.prototype.sayHi = function() {
      console.log(`I am ${this.name}`);
    };
    
    function Dog(name) {
      Animal.call(this, name);
    }
    
    Dog.prototype = Object.create(Animal.prototype); // 继承
    Dog.prototype.constructor = Dog;
    
    const d = new Dog("Lucky");
    d.sayHi(); // I am Lucky
  2. 创建纯净对象(无原型)

    ini 复制代码
    const dict = Object.create(null);
    dict.apple = "苹果";
    console.log(dict); // { apple: "苹果" }
    console.log(dict.toString); // undefined (因为没有继承 Object.prototype)

对于Object.create()继承中的几个问题

问题一:Dog.prototype = Object.create(Animal.prototype);这里如果写成 Dog.prototype = Animal.prototype可不可以

区别对比

✅ 推荐写法

ini 复制代码
Dog.prototype = Object.create(Animal.prototype);
  • Dog.prototype 是一个全新的对象 ,它的 __proto__ 指向 Animal.prototype
  • DogAnimal 各自的原型对象是独立的
  • 即使你在 Dog.prototype 上新增方法,也不会影响 Animal.prototype

❌ 如果写成

ini 复制代码
Dog.prototype = Animal.prototype;
  • 这表示 Dog.prototypeAnimal.prototype 变成了同一个对象

  • 那么:

    1. Dog.prototype 添加方法时,其实就是在改 Animal.prototype
    2. 所有 Animal 的实例都会意外地拥有 Dog 的方法,破坏继承结构。

举个例子

javascript 复制代码
function Animal() {}
Animal.prototype.sayHi = function() {
  console.log("I am an animal");
};

function Dog() {}
// 错误写法
Dog.prototype = Animal.prototype;

Dog.prototype.bark = function() {
  console.log("Woof!");
};

const a = new Animal();
a.bark(); // ❌ 本来不该有 bark 方法

这里 aAnimal 的实例,结果却能调用 bark,说明原型链被"污染"了。


✅ 正确写法的好处

ini 复制代码
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.bark = function() {
  console.log("Woof!");
};

const a = new Animal();
a.bark(); // ❌ 报错,符合预期
  • Dog 的实例可以继承 Animal 的方法。
  • Animal 的实例不会被"污染"。

总结

  • Dog.prototype = Object.create(Animal.prototype) → 正确、安全的继承方式
  • Dog.prototype = Animal.prototype → 错误,会导致 AnimalDog 共用一个原型对象,互相影响

问题二:Dog.prototype.constructor = Dog;为什么要加上这句话

1. 默认情况下

当你定义一个函数时,JS 会自动给它附带一个原型对象 prototype,并且这个原型对象自带一个 constructor 属性,指向这个函数本身。

javascript 复制代码
function Dog() {}
console.log(Dog.prototype.constructor === Dog); // true

所以默认情况下,constructor 是"指回自己"的。


2. 当你覆盖原型时

在继承时我们常常写:

ini 复制代码
Dog.prototype = Object.create(Animal.prototype);

这会用一个新的对象 替换掉原本的 Dog.prototype

而这个新对象是通过 Object.create(Animal.prototype) 创建的,所以它的 constructor 来自 Animal.prototype.constructor,而不是 Dog

ini 复制代码
console.log(Dog.prototype.constructor === Animal); // true ❌

这就出现了问题:

  • Dog 的实例原型链是对的(能继承 Animal 的方法),
  • Dog.prototype.constructor 却错误地指向了 Animal

3. 手动修复

因此我们需要手动把它修正回来:

ini 复制代码
Dog.prototype.constructor = Dog;

这样做是为了让原型对象的 constructor 指向正确的构造函数。


4. 为什么重要?

虽然在日常开发中 constructor 用得不多,但它能反映某个实例最初是由哪个构造函数创建的

ini 复制代码
const d = new Dog("Lucky");

console.log(d.constructor === Dog);    // true ✅
console.log(d.constructor === Animal); // false

如果不修复,可能导致一些依赖 constructor 的逻辑出错,比如序列化、类型检查等。


✅ 总结

  • 每个函数自带的 prototype 都有一个 constructor,默认指向该函数。
  • 一旦你用 Object.create 替换了 Dog.prototype,它的 constructor 就会错指向 Animal
  • 所以需要 Dog.prototype.constructor = Dog 来修复。
相关推荐
莫的感情22 分钟前
下载按钮点击一次却下载两个文件问题
前端
一个很帅的帅哥26 分钟前
JavaScript事件循环
开发语言·前端·javascript
小宁爱Python31 分钟前
Django Web 开发系列(二):视图进阶、快捷函数与请求响应处理
前端·django·sqlite
fox_31 分钟前
深入理解React中的不可变性:原理、价值与实践
前端·react.js
Github项目推荐33 分钟前
你的错误处理一团糟-是时候修复它了-🛠️
前端·后端
Code小翊38 分钟前
C语言bsearch的使用
java·c语言·前端
云枫晖39 分钟前
Webapck系列-初识Webpack
前端·javascript
慧一居士42 分钟前
HTML5 功能介绍,使用场景,对应功能点完整使用示例
前端
海在掘金611271 小时前
告别“undefined is not a function”:TS如何让你的函数调用更安心
前端
云中雾丽1 小时前
Flutter中Stream的各种使用场景和实现方式
前端