如何在javascript中正确继承?

时间:2011-09-12 15:50:40

标签: javascript oop inheritance prototypal-inheritance

我的理解是,如果对象具有给定成员而没有检查原型链,则“hasOwnProperty”返回true。但是当我继承其他对象时,我会在最后一个对象中看到所有成员。

考虑以下示例:

var Object1 = function (param) {
    this.prop1 = "p1 " + param;
    this.prop2 = "p2 " + param;
};

var Object2 = function (param) {
    Object1.apply(this, arguments);
    this.prop3 = 'p3' + param;
};

Object2.prototype = new Object1();

var b = new Object2('this is Object 2');

for (var v in b)
    print(v + ": " + b[v] + (b.hasOwnProperty(v)?' (own)':' (inherited)'));

此代码打印:

--prop1: p1 this is Object 2 (own)
--prop2: p2 this is Object 2 (own)
--prop3: p3this is Object 2 (own)

如果我查看调试器,我看到:

b
  Object2
    prop1: "p1 this is Object 2"
    prop2: "p2 this is Object 2"
    prop3: "p3this is Object 2"
    __proto__: Object1

但是,id我删除apply行,所有更有意义,但基础对象没有初始化:

--prop3: p3this is Object 2 (own)
--prop1: p1 undefined (inherited)
--prop2: p2 undefined (inherited)

现在我在调试器中看到了:

b
  Object2
    prop3: "p3this is Object 2"
    __proto__: Object1
      prop1: "p1 undefined"
      prop2: "p2 undefined"
      __proto__: Object

据我所知,apply就像执行超类构造函数,因此超级成员被正确初始化,但显然会改变子对象的形状。

为什么会这样?在JS中继承的正确方法是什么 - 或者至少不那么混乱?

我正在查看有关它的一些信息,显然每个开发人员对如何做有不同的感受。

问候。

1 个答案:

答案 0 :(得分:2)

apply完全不像执行超类构造函数。作为构造,它在第一个提供的参数的范围内执行任何函数。当您将this传递给Object1函数(作为函数而不是构造函数执行)时,您将通过第二个函数(Object2)所在的作用域执行。

要查看正在发生的情况,请尝试执行Object1("param") ,不要 new

Object1("test");

当我们执行new Object1("test")时,我们会找回一个如下所示的对象:

Object { prop1="p1 test", prop2="p2 test"}

但是当我们执行Object1("test")时,我们会返回undefined ...并且对象等于this(在浏览器JavaScript的情况下最有可能是window)我们找到两个新变量... prop1prop2

发生了什么事?

这里的关键是:

Object1("param") !== new Object1("param");

第一个版本(Object1("param"))在一些已经存在的范围内执行函数(Object1)(在浏览器JavaScript中,最常见的范围是顶级范围,其中this === window。)这是您拨打Object1时调用Object1.apply(this)的方式。

第二个版本(new Object1("param"))执行一个函数作为构造函数 - 也就是说,它创建一个 new 对象并将this设置为是那个新对象。如果我们使用相同的apply函数来证明这一点,我们会写Object1.apply({});

关于如何在JavaScript环境中进行类似OOP编程正确的主题,我见过的最明确的答案之一,请参阅Bobince's answer to this question