我有两个JavaScript代码,它们与执行结果相同,所以我很困惑并想知道为什么我们使用调用函数。
不使用函数调用:
<script language="javascript">
function ClassA(obj, sColor) {
obj.color = sColor;
obj.sayColor = function() {
alert(obj.color);
};
}
function ClassB(sColor, sName) {
ClassA(this, sColor);
this.name = sName;
this.sayName = function () {
alert(this.name);
};
}
var objB = new ClassB("red", "Luke");
objB.sayColor();
objB.sayName();
使用函数调用:
<script language="javascript">
function ClassA(sColor) {
this.color = sColor;
this.sayColor = function() {
alert(this.color);
};
}
function ClassB(sColor, sName) {
ClassA.call(this,sColor);
this.name = sName;
this.sayName = function () {
alert(this.name);
};
}
var objB = new ClassB("red", "Luke");
objB.sayColor();
objB.sayName();
答案 0 :(得分:3)
在这种情况下,结果是相同的,但这两个代码片段是非常不同的。在第一个中,ClassA
不遵循对象构造函数的模式。相反,它将对象作为其参数,并修改该对象(通过向其添加属性和方法)。虽然语法是有效的,但我认为这是不好的做法,因为命名以大写字母开头的函数通常表明它是一个对象构造函数,因此它应该使用this
,而不是修改它的一个参数。它也表现出不一致的行为:
var objA = new ClassA(); // will throw error
var objB = new ClassB(); // valid object constructor
第二个示例是JavaScript中对象构造的更标准示例。您可以通过说出ClassA
来创建new ClassA
的实例,并且可以通过调用ClassB
来创建new ClassB
的实例。很好,也很一致。
我会选择第二个例子。我还会阅读JavaScript中的对象模型,以便更好地理解这里发生的事情。一个好的开始是Douglas Crockford's essay on object-oriented programming in JavaScript。
答案 1 :(得分:1)
我完全同意@EthanBrown的说法。如果您有一个其职责是修改对象的函数,请不要用大写字母启动函数的名称。
除此之外,代码背后的整个想法是将color
和sayColor
添加到ClassB,这是一种继承。
这里的要点是,第二个代码段是我们通常在JavaScript中实现inheritance
的方式。这并不意味着您的代码已完全实现inheritance
,但在call
中使用constructor
来调用另一个构造函数的想法主要用于继承。如果你想从ClassB
完全继承ClassA
,唯一缺少的部分是复制原型,并设置构造函数,如下所示:
ClassB.prototype = Object.create(ClassA.prototype);
ClassB.constructor = ClassA;
您的第二个代码段中唯一的缺点是没有使用prototype
,您最好使用它来创建sayColor
和sayName
函数,如果您在代码中完全实现了继承,使用上面的2行,您可以轻松地执行此操作:
ClassA.prototype.sayColor = function() {
alert(this.color);
};
ClassB.prototype.sayName = function() {
alert(this.color);
};
然后您可以创建ClassB
实例:
var objB = new ClassB("red", "Luke");
objB.sayColor();
objB.sayName();
这里最重要的一点是:
objB instanceof ClassA;
objB instanceof ClassB;
两者都是真的。
您可以创建一个简单的继承方法,如:
function inherit(class, baseClass){
class.prototype = Object.create(baseClass.prototype);
class.constructor = baseClass;
}
然后使用它:
function ClassA(sColor) {
this.color = sColor;
}
ClassA.prototype.sayColor = function() {
alert(this.color);
};
function ClassB(sColor, sName) {
ClassA.call(this, sColor);
this.name = sName;
}
ClassB.prototype.sayName = function() {
alert(this.color);
};
inherit(ClassB, ClassA);
答案 2 :(得分:0)
调用。您可能希望this关键字不是您为函数指定的范围,在这种情况下,您需要使用call或apply将正确的范围引入函数。
一些例子:
function ClassA(sColor) {
// if we say ClassA.call(window), **this** will be window (inject)
this.color = sColor;
this.sayColor = function() {
alert(this.color);
};
}
// use call method
ClassA.call(window, "red");
ClassA.call(document, "blue"); // after this document will have sayColor method
调用ClassA函数后,我们扩展了WINDOW对象,现在调用 window.sayColor 方法。
因此我们在您的示例中使用call方法来扩展ClassB对象
function ClassB(sColor, sName) {
ClassA.call(this,sColor);
this.name = sName;
this.sayName = function () {
alert(this.name);
};
}
现在编写下一个代码时:
var b = new ClassB("Color", "Name");
// b will have sayName method, sayColor method
答案 3 :(得分:0)
非调用方式就是这样,在ClassB的构造函数中,调用函数ClassA将属性和方法添加到当前的ClassB实例。在这种情况下,ClassA中的obj指向当前ClassB的对象。
在调用方式中,在ClassB的构造函数中,调用函数ClassA但将其执行上下文更改为当前的ClassB对象。在这种情况下,'this'指向ClassB的对象。
所以在上面两种情况下,obj和ClassA中的这两个都指向ClassB对象。