[英]JavaScript function call or not call
我有两个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();
在这种情况下,结果是相同的,但是这两个代码段非常不同。 首先, 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的关于JavaScript的面向对象编程的文章 。
我完全同意@EthanBrown所说的。 如果您有一个负责修改对象的函数,请不要以大写字母开头该函数的名称。
除此之外,代码背后的整个想法是将color
和sayColor
添加到ClassB中,这是一种继承。
这里的重点是,第二个片段是我们通常在JavaScript中实现inheritance
的方式。 这并不意味着您的代码已完全实现inheritance
,但是在constructor
函数中大多使用在构造函数中使用call
来调用另一个构造函数的想法。 如果要从ClassA
完全继承ClassB
,则唯一缺少的部分是复制原型并设置构造函数,如下所示:
ClassB.prototype = Object.create(ClassA.prototype);
ClassB.constructor = ClassA;
第二个片段的唯一缺点是不使用prototype
,最好使用它来创建sayColor
和sayName
函数,如果使用上述两行代码在代码中完全实现了继承,那么您可以轻松地做到这一点:
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);
当您要控制将在调用的函数中使用的范围时,将使用call (我们将范围注入到函数内部)。 您可能希望this关键字是您为其分配功能的范围之外的其他东西,在这种情况下,您需要使用call或应用将正确的范围带入功能。
一些例子:
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
非调用方式就是这样,在ClassB的构造函数中,调用ClassA函数为当前ClassB实例添加属性和方法。 在这种情况下,ClassA中的obj指向当前ClassB的对象。
以调用方式,在ClassB的构造函数中,调用函数ClassA,但将其执行上下文更改为当前的ClassB对象。 在这种情况下,“ this”指向ClassB的对象。
因此在以上两种情况下,ClassA中的obj和this都指向ClassB对象。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.