【问题标题】:__proto__ vs. prototype inheritance in javascript__proto__ 与 javascript 中的原型继承
【发布时间】:2015-11-13 02:51:23
【问题描述】:

首先,这个问题与这个网站上的其他几个问题非常相似。我已阅读它们,但仍有疑问

这两个帮助,但并没有让我一路走好:

我有一个 javascript 框架/库的基本设置:

(function(global){

    var TMath = function() {
        return new TMath.init();
    }

    TMath.prototype = {
        add: function(a, b) {
            return a+b;
        }
    };

    TMath.init = function(){};

    TMath.init.prototype = TMath.prototype;

    global.TMath = global.$$ = TMath;

})(window);

当我这样运行它时:

var test = $$()

console.log(test);

我在控制台中看到以下内容:

我不明白的是:

如果我 console.log 输出 test.__proto__,我会得到 Object{}

我不应该得到TMath.Init.prototype,因为那是function constructor 我的test 实例是用它创建的吗?

这是一个确实发生这种情况的示例:

function Person(name){
    this.dob = dob
 }; 

var person = new Person("name");

console.log(person.__proto__);

这会输出Person{},而不是 Object{}

【问题讨论】:

  • var test = $$() => var test = TMath(); 然后你从new TMath.init();得到一个新对象,它的原型是TMath.prototype,所以test.__proto__TMath.prototype,也就是object add 方法,有什么问题?
  • 避免jQuery antipattern :-)
  • 嗯,TMath.Init.prototype Object{}?同样是=== TMath.prototype;,那么控制台应该如何知道要显示哪个名称? 名称没有任何意义。 尤其是在您寻找对象身份时。
  • 这些是同一个东西,控制台只是给它一个通用名称,$$().__proto__ === $$.prototype; // true
  • @Bergi 好的 - 很酷。命名的东西让我有点困惑:)

标签: javascript prototype prototypal-inheritance


【解决方案1】:

让我们逐段浏览您的代码,看看我们最终会得到什么。

在下图中,这是命名法:

  • 椭圆 = 函数
  • 矩形 = 对象
  • 箭头 = 属性
    • p = .prototype
    • c = .constructor
    • P = .__proto__[[Prototype]]
  • 所有匿名项目都是空形状,所有命名项目都包含名称

1) 创建函数TMath

在创建函数时,JS引擎也会创建一个匿名对象,并使用.prototype.constructor属性将两者绑定如下:

function foo(){}

/* performed by JS engine */
// foo.prototype = {};
// foo.prototype.constructor = foo;


var TMath = function() {
    return new TMath.init();
}


2) 将函数的prototype 替换为另一个对象

我们正在重新分配链接TMath.prototype,以便它现在指向新对象。

这个新对象中还有一个匿名函数,由.add() 引用。 并且该函数带有自己的默认.prototype对象。

TMath.prototype = {
    add: function(a, b) {
        return a+b;
    }
};


3) 为对象或函数添加属性

这个很简单。 只需将新链接添加到添加新属性的对象/函数即可。

在我们的例子中,链接是.init(),属性是一个匿名函数。

TMath.init = function(){};


4) 将函数的prototype 替换为另一个对象

就像第 2 步一样,我们重新分配链接 TMath.prototype。 但我们不是创建一个新对象,而是将其指向一个现有对象。

TMath.init.prototype = TMath.prototype;


让我们稍微清理一下图纸。


5) 实例化

还和我在一起吗?

好!因为这就是魔法发生的地方。

当你做var test = $$()时,你实际上是在做var test = TMath(),也就是var test = new TMath.init()

我们甚至可以说这与 完全相同
var test = new <function referenced by TMath.init>().

在调用函数时使用new 时,适用以下规则:

如果在赋值中使用new,则返回的对象带有属性.__proto__
(或[[Prototype]]),这是对所引用的对象的引用
构造函数的.prototype

因此,创建的对象(在本例中为 test)具有指向 TMath.init.prototype 的属性 __proto__

您可以通过执行以下操作来确认所有这些:

console.log(test.__proto__ === TMath.init.prototype) // true
console.log(test.__proto__ === TMath.prototype) // true

结论

确实你最初认为是正确的

如果我 console.log 输出 test.\_\_proto\_\_,我会得到 Object{}

我不应该得到TMath.Init.prototype,因为这是我的test 实例创建时使用的函数构造函数吗?

为了掌握 JS 的这些核心概念,我强烈推荐阅读http://www.javascripttutorial.net/javascript-prototype/

【讨论】:

    猜你喜欢
    • 2015-05-23
    • 2013-11-07
    • 2011-03-29
    • 1970-01-01
    • 2010-09-28
    • 2010-09-28
    • 2018-02-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多