简体   繁体   中英

JavaScript function call or not call

I have two codes of JavaScript,they are the same result of executing,so i am confused and wonder why we use call function.

Not use function call:

<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();     

use function call:

<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();     

In this instance, the outcome is the same, but these two code snippets are very different. In the first, ClassA is not following the pattern of an object constructor. Instead, it takes as its argument an object, and it modifies that object (by adding a property and method to it). While the syntax is valid, I would argue that this is poor practice, because naming a function that starts with an uppercase letter usually indicates it is an object constructor, and therefore it should use this , not modify one of its arguments. It also exhibits inconsistent behavior:

var objA = new ClassA();   // will throw error
var objB = new ClassB();   // valid object constructor

The second example is a more standard example of object construction in JavaScript. You can create an instance of ClassA by saying new ClassA and you can create an instance of ClassB by calling new ClassB . Nice and consistent.

I would go with the second example. I would also read up on object models in JavaScript to get a better understanding of what's going on here. A good place to start is Douglas Crockford's essay on object-oriented programming in JavaScript .

I totally agree with what @EthanBrown has said. If you have a function which its responsibility is to modify an object, don't start your function's name with an uppercase letter.

Other than this, the whole idea behind your code is to add the color and sayColor to the ClassB, which is kind of inheriting.

The point here is, the second snippet is the way we usually implement inheritance in JavaScript. it doesn't mean that your code has completely implemented inheritance , but the idea of using call in a constructor to invoke another constructor is mostly used in inheritance. if you want to completely inherit the ClassB from ClassA , the only missing parts is to copy the prototypes, and set the constructor, like this:

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

the only drawback in your second snippet is not using prototype , you better use it to create the sayColor and sayName function, and if you completely implement the inheritance in your code, using the 2 lines above, then you can easily do this:

ClassA.prototype.sayColor = function() {
    alert(this.color);
};
ClassB.prototype.sayName = function() {
    alert(this.color);
};

then you can create you ClassB instance:

var objB = new ClassB("red", "Luke");
objB.sayColor();
objB.sayName();

and the most important point here is:

objB instanceof ClassA;
objB instanceof ClassB;

both are true.


you can create a simple inherit method like:

function inherit(class, baseClass){
    class.prototype = Object.create(baseClass.prototype);
    class.constructor = baseClass;
}

then use it like:

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 is used when you want to control the scope that will be used in the function called(we inject the scope inside the function). You might want the this keyword to be something else than the scope you assigned the function to, in those cases you need to use call or apply to bring the right scope into the function.

Some example:

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

After calling ClassA function we extend WINDOW object, and now you call window.sayColor method.

So we use call method in your example to extend ClassB object

function ClassB(sColor, sName) {
    ClassA.call(this,sColor);
    this.name = sName;
    this.sayName = function () {
        alert(this.name);
    };
}

Now when you write next code:

var b = new ClassB("Color", "Name");
// b will have sayName method, sayColor method

the non-call way is just like this, in the constructor of ClassB, the function ClassA is called to add a property and method to current ClassB instance. in this case, obj in ClassA points to current ClassB's object.

in the call way, in the constructor of ClassB, call function ClassA but change its execution context to current ClassB object. in this case, the 'this' points to ClassB's object.

so in the above two cases, obj and this in ClassA both point to ClassB objects.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM