关于原型链

27 阅读2分钟

什么是原型

原型是 JavaScript 中每个对象都有的一个内置属性,它指向另一个对象。这个被指向的对象就称为该对象的"原型"。

  • 关键特性
  1. 共享机制:原型上的属性和方法可以被所有实例共享

  2. 备用存储:当对象自身没有某个属性时,会去原型上找

  3. 函数特有:只有函数对象才有 prototype 属性(用作构造函数时)

什么是原型链

原型链是由多个原型对象通过 [[Prototype]] 链接形成的链式结构。当查找一个属性时,JavaScript 会沿着这条链一直向上查找。

为什么要有原型链

1. 减少内存浪费

  • 没有原型链的情况
function Person(name) {
  this.name = name
  this.sayName = () => {
    console.log(this.name)
  }
}

let alice = new Person('Alice')
let bob = new Person('Bob')
console.log(alice.sayName === bob.sayName) // 不相等
  • 有原型链的情况
function Person(name) {
  this.name = name
}
Person.prototype.sayName = () => {
  connsole.log(this.name)
}
let alice = new Person('Alice')
let bob = new Person('Bob')
console.log(alice.sayName === bob.sayName) // 相等

2. 代码复用/继承问题

没有原型链:只能通过复制属性实现继承(低效且容易出错) 有原型链:自然形成继承链,方法和属性自动复用

// 传统继承方式(繁琐)
function extend(child, parent) {
  for (var key in parent) {
    if (parent.hasOwnProperty(key)) {
      child[key] = parent[key]
    }
  }
}

// 原型链继承(简洁优雅)
function Animal() {}
Animal.prototype.eat = function () {}

function Dog() {}
Dog.prototype = Object.create(Animal.prototype)
// Dog 自动获得 eat 方法

注意这里的extend和类的extend是不一样的,而es6之后的类是原型链的语法糖,也就是说es6的extend是基于原型链实现的

为什么不建议用__proto__

原因说明
非标准 & 已弃用规范不推荐,未来可能移除
性能杀手破坏引擎优化,导致严重 slowdown
安全隐患可能引发原型污染漏洞
语义模糊易与 prototype 混淆,降低代码可读性

特别的

所有原型链的终点都指向于Object.prototype,而他的上一层是null