当前位置: 首页 > news >正文

《从分遗产说起:JS 原型与继承详解》

 

“天天开心就好”


先来讲讲概念: 

原型(Prototype)

什么是原型?

原型是 JavaScript 中实现对象间共享属性和方法的机制。每个 JavaScript 对象(除了 null)都有一个内部链接指向另一个对象,这个对象就是它的"原型"(prototype)。

继承(Inheritance)

什么是继承?

继承是面向对象编程中的一个核心概念,它允许一个对象(子对象)获取另一个对象(父对象)的属性和方法。在 JavaScript 中,继承主要通过原型链来实现。

好的现在我们明确了什么是原型,什么是继承。简单来说,原型就是一个机制,每个对象内部都一个内部链接指向他的原型。继承我的理解就是一种行为,就是像继承财产那样继承父对象的属性和方法,可谓是形容十分贴切。

原型基础

原型对象 (prototype)

  • 每个函数都有一个 prototype 属性(箭头函数除外)
  • 这个属性指向一个对象,称为"原型对象"
  • 原型对象包含可以被特定类型的所有实例共享的属性和方法
function Person() {}
Person.prototype.name = 'Default';
Person.prototype.sayHello = function() {console.log(`Hello, I'm ${this.name}`);
};

__proto__ 属性

  • 每个对象都有一个 __proto__ 属性(现已标准化为 Object.getPrototypeOf()
  • 指向创建该对象的构造函数的原型对象
const person = new Person();
console.log(person.__proto__ === Person.prototype); // true

这个很好理解了,我在这里想用c语言里面的指针来形容了。prototype就像是地址对应的数据,而_proto_就像是指向他的指针。不太恰当哈

 我们经常这样说:对象的继承是通过原型链实现的。

那么什么是原型链:

什么是原型链?

原型链(Prototype Chain)是 JavaScript 中实现继承的核心机制。当访问一个对象的属性或方法时,JavaScript 引擎会沿着对象的原型链向上查找,直到找到该属性或到达原型链的末端(null)。

原型链的构成

  1. ​每个对象都有一个 __proto__ 属性​​(现已标准化为 Object.getPrototypeOf()
  2. ​每个函数都有一个 prototype 属性​
  3. ​原型链的终点是 null

原型链的工作原理

当访问一个对象的属性时:

  1. 首先在对象自身查找该属性
  2. 如果没有找到,则查找对象的 __proto__(即其构造函数的 prototype
  3. 如果还没有找到,继续查找 __proto__.__proto__,依此类推
  4. 直到找到该属性或到达 null(此时返回 undefined
function Animal(name) {this.name = name;
}
Animal.prototype.eat = function() {console.log(`${this.name} is eating`);
};function Dog(name, breed) {Animal.call(this, name);this.breed = breed;
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.bark = function() {console.log('Woof!');
};const myDog = new Dog('Buddy', 'Golden Retriever');// 原型链:
// myDog -> Dog.prototype -> Animal.prototype -> Object.prototype -> null

我们讲原型和继承就是在意js中继承这种行为是怎么实现的,就像现实中大家只在乎怎么分遗产一样!

继承实现方式

 1.原型链继承

function Parent() {this.parentProperty = true;
}
Parent.prototype.getParentValue = function() {return this.parentProperty;
};function Child() {this.childProperty = false;
}
// 继承 Parent
Child.prototype = new Parent();const instance = new Child();
console.log(instance.getParentValue()); // true

​问题​​:

  • 所有子类实例共享同一个父类实例
  • 无法向父类构造函数传参

2. 构造函数继承

function Parent(name) {this.name = name;
}function Child(name) {Parent.call(this, name); // 在子类构造函数中调用父类构造函数
}const child = new Child('Alice');
console.log(child.name); // 'Alice'

​优点​​:

  • 可以向父类传参
  • 每个子类实例都有独立的父类属性副本

​缺点​​:

  • 无法继承父类原型上的方法

3.组合继承(最常用)

function Parent(name) {this.name = name;
}
Parent.prototype.sayName = function() {console.log(this.name);
};function Child(name, age) {Parent.call(this, name); // 第二次调用 Parentthis.age = age;
}
Child.prototype = new Parent(); // 第一次调用 Parent
Child.prototype.constructor = Child; // 修复构造函数指向const child = new Child('Alice', 25);
child.sayName(); // 'Alice'

​优点​​:

  • 结合了原型链和构造函数的优点
  • 既能继承原型方法,又能保证实例属性独立

​缺点​​:

  • 父类构造函数被调用了两次

4. 原型式继承

function object(o) {function F() {}F.prototype = o;return new F();
}const parent = { name: 'Parent' };
const child = object(parent);
console.log(child.name); // 'Parent'

ES5 标准化为 Object.create()

const child = Object.create(parent);

5. 寄生式继承

function createAnother(original) {const clone = Object.create(original);clone.sayHi = function() {console.log('Hi');};return clone;
}

6. 寄生组合式继承(最佳实践)

function inheritPrototype(child, parent) {const prototype = Object.create(parent.prototype);prototype.constructor = child;child.prototype = prototype;
}function Parent(name) {this.name = name;
}
Parent.prototype.sayName = function() {console.log(this.name);
};function Child(name, age) {Parent.call(this, name);this.age = age;
}inheritPrototype(Child, Parent);const child = new Child('Alice', 25);
child.sayName(); // 'Alice'

​优点​​:

  • 只调用一次父类构造函数
  • 原型链保持正确
  • 最理想的继承方式

ES6 的 class 继承

class Parent {constructor(name) {this.name = name;}sayName() {console.log(this.name);}
}class Child extends Parent {constructor(name, age) {super(name); // 调用父类构造函数this.age = age;}
}const child = new Child('Alice', 25);
child.sayName(); // 'Alice'

​注意​​:

  • class 本质上是语法糖,底层仍然是基于原型的继承
  • extends 实现了寄生组合式继承
  • 必须在使用 this 前调用 super()

继承是js中很核心的机制了,有很多中方式来实现继承,继承的好处就是我们可以直接继承父对象的方法和属性而不用自己再次定义了。用好继承可以大大提升我们的代码水平,帮助我们实现更多复杂需求。 


相关文章:

  • 测地型GNSS接收机_毫米高精度精准定位
  • NEPCON China 2025 | 具身智能时代来临,灵途科技助力人形机器人“感知升级”
  • 读写算杂志读写算杂志社读写算编辑部2025年第12期目录
  • 现场问题排查-postgresql某表索引损坏导致指定数据无法更新影响卷宗材料上传
  • 97A6-ASEMI无人机专用功率器件97A6
  • 【神经网络与深度学习】端到端方法和多任务学习
  • 2025系统架构师---事件驱动架构
  • Android10.0 Android.bp文件详解,以及内置app编写Android.bp文件
  • iOS自定义电池电量显示控件 BatteryView 实现
  • uniapp自定义一个选择年月日时分的组件。
  • SpringBoot驾校报名小程序实现
  • 重构数字信任基石:Java 24 网络安全特性的全维度革新与未来防御体系构建
  • List 的介绍 [数据结构 初阶]
  • OceanBase数据库-学习笔记2-C#/C++程序如何访问
  • error mounting 报错解决办法
  • 【Android】dialogX对话框框架
  • 数值分析、数值代数之追赶法
  • 高功率无人机动力方案首选:CKESC ROCK 220A-H CAN 电调工程性能实测
  • AI-Browser适用于 ChatGPT、Gemini、Claude、DeepSeek、Grok的客户端开源应用程序,集成了 Monaco 编辑器。
  • Web安全:威胁解析与综合防护体系构建
  • 中国贸促会:有近50%的外贸企业表示将减少对美业务
  • 一季度规模以上工业企业利润由降转增,国家统计局解读
  • 体坛联播|巴萨“三杀”皇马夺国王杯,陈妤颉破亚洲少年纪录
  • 网络游戏用户规模和市场销售创新高,知识产权保护面临哪些挑战?
  • 摩根士丹利基金雷志勇:AI带来的产业演进仍在继续,看好三大景气领域
  • 石磊当选河北秦皇岛市市长