什么是原型链以及它在javascript中如何运作?【教程】

8次阅读

javaScript的原型链就是其继承机制本身,对象通过__proto__链接到原型对象形成查找链,属性读取时逐级委托查找,写操作仅作用于自身。

什么是原型链以及它在javascript中如何运作?【教程】

javascript 中的原型链不是“继承机制的替代方案”,它就是继承机制本身——所有对象都通过 __proto__ 链接到一个原型对象,而这个原型对象也可能有它自己的原型,层层向上,直到 NULL

对象的 __proto__ 指向谁?

每个对象(除 Object.create(null) 创建的)都有一个内部属性 [[prototype]],可通过 __proto__ 访问(不推荐直接用,但调试时很直观):

  • {}.__proto__ === Object.prototype
  • [] .__proto__ === Array.prototype
  • function(){}.__proto__ === Function.prototype
  • new date().__proto__ === Date.prototype

注意:__proto__访问器属性,不是标准写法;正式代码中应使用 Object.getPrototypeOf(obj) 获取,Object.setPrototypeOf(obj, proto) 设置。

prototype 属性只存在于函数上

只有函数对象才有 prototype 属性(普通对象没有),它是被该函数作为构造器调用时,新实例的 __proto__ 默认指向的目标:

立即学习Java免费学习笔记(深入)”;

  • function Foo() {}Foo.prototype 是一个普通对象,默认含 constructor: Foo
  • const f = new Foo()f.__proto__ === Foo.prototype
  • Foo.prototype.__proto__ === Object.prototype(因为 Foo.prototype 是对象字面量创建的)

混淆点常在这里:把 prototype(函数专属)和 __proto__(所有对象都有)当成一回事。它们作用不同,但共同构成查找链。

属性查找怎么走原型链?

当你读取 obj.x 时,js 引擎按以下顺序查找:

  • 先查 obj 自身是否含 xhasOwnPropertytrue
  • 没有就查 obj.__proto__.x
  • 再没有就查 obj.__proto__.__proto__.x
  • ……直到某一级是 null,抛出 undefined

这就是“委托”:对象自己不实现方法,而是委托给原型。比如 [1,2].map 实际在 Array.prototype.map 上,而 Array.prototype.toString 又继承自 Object.prototype.toString

注意:写操作(obj.x = 1)永远只在 obj 自身设置,不会修改原型上的同名属性 —— 这是屏蔽(shadowing),不是覆盖。

es6 class 并没改变原型链本质

class 只是语法糖,背后仍是函数 + prototype

class Bar {   constructor(v) { this.v = v; }   method() { return this.v; } } // 等价于: function Bar(v) { this.v = v; } Bar.prototype.method = function() { return this.v; };

所以 new Bar().__proto__ === Bar.prototype 依然成立。class 的 extends 也只是自动设置了 Sub.prototype.__proto__ === Super.prototype,并让 Super.call(this)子类构造器中显式调用父类逻辑。

真正容易被忽略的是:原型链查找发生在运行时,且不可跳过 —— 即使你给实例加了同名方法,也不会影响原型上其他方法的复用逻辑;而一旦误删或覆盖了原型上的关键方法(如 toString),可能破坏调试、序列化等底层行为。

text=ZqhQzanResources