简介
JS 是一种基于原型的编程语言,在 JS 中,一个对象通过引用它原型对象的属性或方法,来达到复用代码的目的,从而实现了类似其他语言中继承的特性。
原型的优点
- 复用性: 原型允许开发者一次性定义一组属性和方法,并在多个对象中重复使用。通过将一个对象的原型设置为另一个对象,我们可以继承其所有的属性和方法,这就减少了代码的重复,使我们的代码更加模块化,更容易维护。
- 动态性: 原型是动态的,这意味着我们可以在运行时向原型对象添加或删除属性和方法。这使得我们很容易扩展和修改现有的对象或创建具有定制功能的新对象。
- 性能: 因为 JS 中的所有对象都是基于原型的,所以访问对象的属性和方法是非常快的。JS 引擎优化了原型的查找,使其比传统的基于继承的语言更快。
原型的缺点
- 复杂性: 原型链可能会变得复杂和难以管理,特别是在处理深层的继承层次时。这可能会导致错误,并使推理对象的行为变得更加困难。
- 冲突: 如果多个原型定义了同一个属性或方法,就会产生冲突。JS 使用一种叫做 "属性阴影 "的方法来解决这些冲突,但如果开发者不小心的话,这可能会导致意想不到的行为。
原型链
原型中存储共享的属性和方法。当我们访问一个对象的属性时,JS 引擎会先看当前对象中是否有这个属性,如果没有的就会查找他的原型对象中是否有这个属性,如此递推下去,一直检索到 Object 的原型 null 为止。这么一个寻找的过程就形成了原型链的概念。
理解原型链最关键的是弄清楚__proto__、prototype、constructor 三者的关系:
// 常见对象
const obj = {}, arr = [], foo = ()=>{};
//它们的原型链关系
obj ---__proto__---> Object.prototype ---__proto__---> null
arr ---__proto__---> Array.prototype ---__proto__---> Object.prototype ---__proto__---> null
foo ---__proto__---> Function.prototype ---__proto__---> Object.prototype ---__proto__---> null
//它们的构造关系
obj ---constructor---> Object ---constructor---> Function
arr ---constructor---> Array ---constructor---> Function
foo ---constructor---> Function ---constructor---> Function
Object.prototype ---constructor---> Object
Array.prototype ---constructor---> Array
Function.prototype ---constructor---> Function
需要注意的是,以上关系除了Object.prototype.__proto__ 为 null 且不可改变,其他关系均可以手动改变