Javascript:理解原型链

Javascript: Understanding Prototype chain

本文关键字:原型 Javascript      更新时间:2023-09-26

我创建了一个简单的类,如下:

var Class = function() {};
Class.prototype.testObj = {a:2, b:3};

现在如果我做console.log(Class.testObj),我得到undefined。但是如果我像这样创建这个类的实例:

var instance = new Class();
console.log(instance.testObj)

我得到了预期的输出。

在我的理解中,所有变量都被视为对象并具有原型属性。当在对象中没有找到某个键时,遍历原型链以查找键值对。但是对于Class,它没有遍历原型链。

我错过了什么?new关键字还做了什么使属性可访问?

  1. 您必须清楚Class()是您的constructor,而不是instance object。所以Class.testObject会返回undefined因为Class没有property

  2. 您可以将prototype视为对象的配方。几乎每个函数都有一个prototype属性,在创建新实例期间使用,并且 prototype在所有对象实例中共享

  3. 构造函数就是与new一起用来创建对象的函数

  4. 当你这样做var instance = new Class();这意味着你正在创建Class的实例对象,因此instance将继承Classprototype属性

  5. 测试:
  6. console.log(instance instanceof Class); // => true
    console.log(instance.constructor === Class); // => true
    console.log(Object.prototype.isPrototypeOf(Class)); // => true
    console.log(Class.prototype.isPrototypeOf(instance)); // => true
    

无论何时创建对象(例如函数),它都继承自object构造函数,因此

var Class = function() {};

是一个对象,它有自己的prototype属性,可以通过

访问。
Class.prototype

,你可以用

prototype对象上创建新的属性
Class.prototype.testObj = {a:2, b:3};

如果你想访问它,你实际上必须执行

console.log(Class.prototype.testObj)

,这是一个添加到Classprototype属性的属性。

当您使用new关键字时,一些神奇的事情发生了,创建了一个全新的对象(称为实例),并且该对象继承自Class.prototype,从docs

当代码new Class(…)被执行时,会发生以下事情:

  1. 继承Class.prototype创建一个新对象

  2. 使用指定的参数调用构造函数Class和this绑定到新创建的对象。new Class等价于new Class(),即如果没有指定参数列表,则调用Class没有参数。

  3. 构造函数返回的对象成为结果全新的表达方式。如果构造函数没有显式返回一个对象,使用步骤1中创建的对象代替。(通常构造函数不返回值,但如果它们想要覆盖正常的对象创建,它们可以选择这样做过程。)

您误解了ClassClass.prototype的关系。

Class是构造函数。严格地说,JavaScript不区分构造函数和通用函数,但现在这并不重要。Class.prototype是Class的实例的原型。也就是说,当您实例化类var x = new Class()时,Class.prototype作为委托对象附加到x上。

这意味着对x的查找将沿着委托链传播,并在原型实例上引用变量。

在我的理解中,所有变量都被视为对象并具有prototype属性。

这是不正确的。JavaScript有很多基本类型,只有函数有一个名为"prototype"的属性。原型委托只有在使用new和构造函数或ECMAScript 5 object.create()符号创建时才附加到引用类型(对象、数组和函数)。

顺便说一下,Class确实有一个原型委托,因为它是Function()的一个实例。委托函数方法的一个实例是apply()

简单地说,Class不是Class的实例,它是Function的实例,那么它为什么要继承Class.prototype呢?Class原型链的第一个环节是Function.prototype

我们可以看到,如果我们从Function.prototype中选择一个函数,比如call,它存在于Class中。

typeof Class.call; //function

对象实例用它们的构造函数的原型建立它们的原型链。因此,只有作为Class实例的对象才会使用Class.prototype来设置它们的原型链。

添加对象到prototype
如果您执行console.log(Class.prototype),您将看到对象。

new关键字实例化对象,这将显示附加到其原型的属性作为实例化对象的属性。
因为新实例化的对象实际上继承了父对象的prototype,而不是父对象本身。