【问题标题】:Constructor inheritance; what am I not getting here?构造函数继承;我没有到达这里是什么?
【发布时间】:2009-08-13 11:51:39
【问题描述】:

我正在尝试理解 Javascript 中的继承,但是这段代码(在 Firebug 中测试)没有按我预期的方式工作。我有什么不明白的?

var A = function(v){
  this.v = v || 'foo';
}

A.prototype.shout = function(){ alert(this.v); }

var B = function(){};

B.prototype = new A;

var test = new B('bar')
test.shout() // returns 'foo'

我期望的是,当我分配 test 时,属性 this.v 设置为“bar”。据我了解,JS 原型继承设置B 的原型为A 意味着B 中的所有内容都被覆盖。我希望它的构造函数被覆盖,并且调用new B('bar') 将使用参数“bar”执行A 的构造函数。

如果我的理解不正确,请有人纠正我。找到我想要做的事情的解决方案也很好:

// constructors from above
B.prototype.yell = function(){ alert('hello world'); }
var test1 = new B('bar'), test2 = new B('spam'), test3 = new B('eggs');

...所以我正在创建的 JS 对象遵循与标准 OOP 类似的继承模式,因此 B 将继承 A 的构造函数和方法。

编辑:

阅读完 cmets 后,我相信一个更好的问题是问如何用 A 的构造函数覆盖 B 的构造函数?

【问题讨论】:

  • 什么不符合您的预期?你在期待什么?

标签: javascript oop inheritance


【解决方案1】:

下面是一个构造函数。它在你调用 new A 时运行。

var A = function(v){
  this.v = v || 'foo';
}

B中的构造函数是function(){};所以你没有设置 this.v

要达到您正在尝试的结果,您应该遵循以下模式:

var A = function(v){
  this.v = v || 'foo';
}

A.prototype.shout = function(){ alert(this.v); }

var B = function(v){
    B.prototype.constructor.call(this,v); // here you call A constructor 
};

B.prototype = new A;


var test = new B('bar')
test.shout() // returns 'bar

【讨论】:

  • 据我了解,在设置B.prototype 时,它从A 复制了一切?这不正确吗?
  • 是的。但是,当您调用 new Class() 时,您只是在调用构造函数。而在 B 情况下,构造函数是 function(){} 什么都不做。
【解决方案2】:

当你设置时

var B = function(){};

你创建一个无参数的构造函数 B。然后当你这样做时

B.prototype = new A;

您正在调用不带参数的A 构造函数(导致this.v = 'foo'),然后导致B 的原型指向来自A 的vshout。但是,B 为构造函数没有改变。这可以通过在'B'的定义中添加一些参数来看出,例如:

var B = function(x){this.v += x};

应该产生'foobar'。

附录: 我能想到的最接近“复制”构造函数的方法实际上是使用一些第三方函数创建两个构造函数并分配给 A 和 B。示例:

var objmaker = function(defaultval) {
    return function(v) { this.v = v || defaultval; };
}

var A = objmaker('foo');
A.prototype.shout = function(){ alert(this.v); }

var B = objmaker('bar');
B.prototype = A.prototype; // B can now shout()

var testA1 = new A('A');
testA1.shout(); // returns 'A'
var testA2 = new A();
testA2.shout(); // returns default 'foo'

var testB1 = new B('B');
testB1.shout(); // returns 'B'
var testB2 = new B();
testB2.shout(); // returns default 'bar'

这并不是真正的复制,正如您可以通过不同的默认值看到的那样,但这是确保两个定义保持同步的一种方法。

【讨论】:

  • 那么,有没有办法让B 的构造函数被A 的构造函数替换?
  • B 是构造函数。 B 不是一个类,它是一个构造函数。 Javascript 没有类。
  • Djko 确实在那里,但很好。子句“B 的构造函数”意味着 phillip 将 B 视为与构造函数分开的实体。那么如果 B 不是构造函数,它是什么?很可能是一堂课!除了B的constructor之外,再问B的构造函数,好像B和构造函数不是一回事一样。
【解决方案3】:

不要将原型设置为A 的新实例,而是将Bprototype 委托给Aprototype。 Crockford 称之为beget,它在Dojo 中实现为dojo.delegate。这是一个简单的函数,如下所示:

function delegate(o){
  F = function(){}
  F.prototype = o;
  return new F;
}

您可以使用它在原型之间创建此链接:

var B = function(){}
B.prototype = delegate(A.prototype);

通过这样做,A 构造函数永远不会被调用,v 的值永远不会被设置。这将继承限制为仅原型,而不是原型加构造函数。

【讨论】:

  • 我忘记使用临时 F() 来设置原型链。感谢您的解释。只有一个问题,是不是一定要设置B.prototype.constructor = B来保证B是instanceof B?
【解决方案4】:

试试

var test2 = new A('baz');
test2.shout(); //returns baz

我认为,当您将“var B”设为一个新函数时,而不是将其设为“新 A”,您会消灭您将“A”设为的“构造函数”。 我不确定原始文件是如何被调用以将测试的 v 实例设置为 'foo'。

【讨论】:

  • 我不认为这是解决方案,例如:A 包含由BC 继承的常用方法。 B 定义了 A 没有的附加方法,C 也是如此。所以我需要创建一个B的实例,但是通过使用A的构造函数。
【解决方案5】:

与其尝试让 javascript 像其他语言一样工作,不如从中学习一些新的东西,然后使用它,让它像 javascript 一样工作,怎么样?

看看这个: http://javascript.crockford.com/prototypal.html

【讨论】:

  • am 试图像 javascript 一样使用它。我理解一种语言的成语,我正在寻求帮助,以便在另一种语言中复制该成语。
  • 但这不像javascript。就像其他语言一样。这个成语在 javascript 中没有意义。阅读链接,你就会明白。它内部有一个指向另一个页面的链接,其中包含您想要做什么的说明。
  • 我的意思是,您可能会问如何在 javascript 中执行“Goto”,我指出 javascript 没有 GOTO 命令是不合理的吗?
  • 一点也不。但是,如果说“对不起,在 Javascript 中使用 GOTO 是不可能的。你可以通过 this... 获得类似的效果”(虽然我真的希望如果我在 JS 中询问 GOTO,有人会打我一巴掌;)。
  • 我做得更好。我给了你一个链接,指向复制你的成语和更多像 javascript 这样的成语的说明。你不欣赏我重用他人工作的能力吗?
猜你喜欢
  • 2012-04-16
  • 2018-02-28
  • 1970-01-01
  • 2017-10-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多