美文网首页
__proto__, [[prototype]] , proto

__proto__, [[prototype]] , proto

作者: 魂斗驴 | 来源:发表于2021-02-07 12:31 被阅读0次

    原型是构造函数上的属性,该函数设置将成为构造对象的proto属性。

    每个对象都可以有另一个对象作为其原型。然后,前一个对象继承了其所有原型的属性。对象通过内部属性指定其原型[[Prototype]]。通过[[Prototype]]属性连接的对象链称为原型链:

    Prototype

    为了了解基于原型的继承(或原型)的继承方式,让我们看一个示例(使用用于指定[[Prototype]]属性的发明语法):

    var proto = {
        describe: function () {
            return 'name: '+this.name;
        }
    };
    var obj = {
        [[Prototype]]: proto,
        name: 'obj'
    };
    
    > obj.describe
    [Function]
    > obj.describe()
    'name: obj'
    

    __proto__是一个存取器属性的的Object.prototype对象。它公开了内部原型链接[[Prototype]])

    function Foo(name) {
      this.name = name;
    }
    
    var b = new Foo('b');
    var a = new Foo('a');
    b.say = function() {
      console.log('Hi from ' + this.whoAmI());
    }
    
    console.log(a.__proto__ === Foo.prototype); // true
    console.log(a.__proto__ === b.__proto__); // true
    
    prototype

    JavaScript引擎将say()方法添加到b对象,而不是Foo.prototype对象。

    如您在图中所看到的,a.proto暴露了[[Prototype]]指向Foo.prototype对象的。同样,b.proto也指向与a.proto

    示例1:通过构造函数创建对象

    除了通过指定的模式创建对象外,构造函数还可以做另一件事-它会自动为新创建的对象设置prototype。该prototype存储在ConstructorFunction.prototype属性中。

    例如在之前示例中, 我们可以用构造函数重写带有对象b.

    function Foo(y) {
      this.y = y;
    }
    
    Foo.prototype.x = 10;
    Foo.prototype.calculate = function (z) {
      return this.x + this.y + z;
    };
    
    var b = new Foo(20);
    
    b.calculate(30); // 60
    console.log(
      b.__proto__ === Foo.prototype, // true
      b.__proto__.calculate === Foo.prototype.calculate // true
      b.__proto__.calculate === b.calculate, // true
      Foo === b.constructor, // true
      Foo === Foo.prototype.constructor, // true
    );
    

    如上所示,b是从Foo()继承的方法。“ Foo.prototype”自动创建一个特殊属性“ constructor”,该属性是对构造函数本身的引用。
    实例“ b”可以通过委托找到它,并用于检查其构造函数。

    prototype

    示例2:JavaScript经典继承图

    这是一个关于通过构造函数创建对象的示例,但是我们将重点放在这些对象和实例系列期间的原型链问题。原型对象也只是简单的对象,可能有自己的原型。如果某个原型对其原型具有非空引用,依此类推,则称为原型链

    原型链png

    现在,从图中可以看出为什么当我们从Animal继承Dog时,我们会这样做:

    function Dog() {} // the usual constructor function
     Dog.prototype = new Animal();
     Dog.prototype.constructor = Dog;
    

    当new()一个实例时会发生什么:

    需要注意的是,原型在Foo.prototype是不是形成一个原型链。Foo.prototype 指向原型链中的某些位置,但是Foo的原型属性不是构成原型链。什么构成了一个原型链是proto朝上链,且对象指向proto,如去富.__ proto__,马上要到富..__ proto__,依此类推,直到空为止。

    proto和原型的关系

    JavaScript的工作方式如下:我是一个构造函数,我只是一个函数,并且我拥有一个原型引用,并且每当调用foo = new Foo()时,我都会让foo .__ proto__指向我的原型对象。因此,Foo.prototype和obj .__ proto__是两个不同的概念。Foo.prototype指示创建Foo的对象时,这是新对象的原型链应指向的位置,即foo .__ proto__应指向Foo.prototype指向的位置。

    如果需要添加功能怎么办?

    如果woofie对象没有move方法,它将像任何原型继承场景一样,沿着原型链上升,首先到达woofie .__ proto__指向的对象,这与Dog.prototype引用的对象相同至。如果方法move不是该对象的属性(意味着Dog类没有方法move),请在原型链中上一层,即woofie .__ proto . proto__,或与Animal.prototype相同。

    Animal.prototype.move = function() { ... };
    
    __proto__

    即使foo.constructor === Foo,构造方法属性也不是foo自己的属性。它实际上是通过向上访问foo .__ proto__所指向的原型链来获得的。这同样适用于Function.constructor。当我们看到Constructor.prototype,foo .__ proto__,Foo.prototype.constructor时,该图可能很复杂,有时会造成混淆。

    为了验证该图,请注意,即使foo.constructor将显示一个值,该属性构造函数也不是foo的自己的属性,而是通过跟踪原型链来获得的,如foo.hasOwnProperty(“ constructor”)所示。

    笔记:

    **[[Prototype]]**对象通过内部属性指定其原型

    **__proto__**直接访问[[Prototype]]

    **prototype**是的对象是用于构建__proto__,当你创建一个对象new.

    **prototype** 在实例本身(或其他对象)上不可用,而仅在构造函数上可用。

    **prototype**仅在函数上可用,因为它们是从中复制的FunctionObject,而在其他任何函数中则不是。但是,**__proto__**随处可见。

    ( new Foo ).__proto__ === Foo.prototype  //true
    ( new Foo ).prototype === undefined      //true
    

    委托原型和串联继承

    Cat.prototype = new Animal();
    //它将通过继承层次结构正确遵循原型链。
    
    Cat.prototype = Animal.prototype
    //Cat原型的任何运行时更改也会影响动物
    

    原型上不存在静态属性/功能。在prototype一个时才使用new被创建的实例。

    喜欢这个故事吗?对别人有帮助吗?轻按下面的心脏,它可以帮助我知道您是否想写更多有关他的话题的信息,并帮助人们看到故事。

    参考

    Javascript inheritance behind the scene proto, [[prototype]] and prototype

    相关文章

      网友评论

          本文标题:__proto__, [[prototype]] , proto

          本文链接:https://www.haomeiwen.com/subject/chkotltx.html