JavaScript函数调用与否调用

时间:2014-02-20 06:34:51

标签: javascript

我有两个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();     

4 个答案:

答案 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的说法。如果您有一个其职责是修改对象的函数,请不要用大写字母启动函数的名称。

除此之外,代码背后的整个想法是将colorsayColor添加到ClassB,这是一种继承。

这里的要点是,第二个代码段是我们通常在JavaScript中实现inheritance的方式。这并不意味着您的代码已完全实现inheritance,但在call中使用constructor来调用另一个构造函数的想法主要用于继承。如果你想从ClassB完全继承ClassA,唯一缺少的部分是复制原型,并设置构造函数,如下所示:

ClassB.prototype = Object.create(ClassA.prototype);
ClassB.constructor = ClassA;

您的第二个代码段中唯一的缺点是没有使用prototype,您最好使用它来创建sayColorsayName函数,如果您在代码中完全实现了继承,使用上面的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对象。