I went for an interview the day before yesterday, and a gg asked me about some js knowledge. There was a question about the usage of call and apply. Although I had used the call method 365 days ago, I still couldn’t answer it at that time. I will summarize it in depth today.
call and apply, their function is to bind the function to another object to run.
The format and parameter definitions of both:
call( thisArg [, arg1, arg2, ... ] ); // Parameter list, arg1, arg2, ...
apply(thisArg [, argArray] ); // parameter array, argArray
The this pointer inside the above two functions will be assigned thisArg, which can realize the purpose of running the function as a method of another object.
1. Simple usage of call
First, let’s look at a simple example (call):
Copy the code code as follows:
<!doctype html>
<html>
<head>
<title> call-apply </title>
</head>
<body>
<input type="text" id="idTxt" value="input text">
<script type="text/javascript">
var value = "global var";
function mFunc()
{
this.value = "member var";
}
function gFunc()
{
alert(this.value);
}
window.gFunc();// show gFunc, global var
gFunc.call(window);// show gFunc, global var
gFunc.call(new mFunc());// show mFunc, member var
gFunc.call(document.getElementById('idTxt'));// show element, input text
</script>
<script language="javascript">
var func = new function()
{
this.a = "func";
}
var func2 = function(x)
{
var a = "func2";
alert(this.a);
alert(x);
}
func2.call(func, "func2");// show func and func2
</script>
</body>
</html>
Then, the running results are as follows:
global varglobal var
member var
input text
func
func2
Test environment: Google Chrome10.0.648.45
Finally, analyze the results
1. The global object window calls the function gFunc, and this points to the window object, so this.value is global var.
2. The function gFunc calls the call method. This points to the first parameter window object by default, so this.value is also a global var.
3. The function gFunc calls the call method. This defaults to the first parameter new mFunc(), which is the object of mFunc. Therefore, this.value is the member variable of mFunc.
4. The function gFunc calls the call method. By default, this points to the first parameter input text control, that is, the control with id='idTxt'. Therefore, this.value is the value input text of the input control.
5. Function func2 calls the call method. This defaults to the first parameter func function object, so this.value is this.a, which is func.
6. Function func2 calls the call method. The second parameter belongs to the parameter of function object func2, so alert(x) is the second parameter func2.
2. Call inheritance usage and improvement
js uses call to simulate inheritance
Test code:
Copy the code code as follows:
<!doctype html>
<html>
<head>
<title> call - apply for inherit </title>
</head>
<body>
<script type="text/javascript">
function baseA()// base Class A
{
this.member = "baseA member";
this.showSelfA = function()
{
window.alert(this.member);
}
}
function baseB()// base Class B
{
this.member = "baseB member";
this.showSelfB = function()
{
window.alert(this.member);
}
}
function extendAB()// Inherit Class from A and B
{
baseA.call(this);// call for A
baseB.call(this);// call for B
}
window.onload = function()
{
var extend = new extendAB();
extend.showSelfA();// show A
extend.showSelfB();// show B
}
</script>
</body>
</html>
The running results are as follows:baseB member
baseB member
Test environment: Google Chrome10.0.648.45
Result analysis:
The expected result should be to output baseA member and baseB member, but the actual output is baseB member and baseB member.
(It has been tested in IE9, 8, 6, Maxthon, Chrome, FF, Opera, Safari, 360 and other browsers, and the result is the latter: baseB member)
At this point, the machine is not wrong, which requires us to conduct in-depth analysis
We may easily think that it is caused by this. This points to the baseB object twice, but is this really the case?
In order to explore the essence, we used the debugging tool of the Chrome browser to set breakpoints and debug, and found that:
When extend.showSelfA(); is called, this points to extendAB (not to the baseB object as we speculated twice)
The real reason is that the member variable member of the extendAB object is overwritten by the member member of baseB when it is instantiated by baseB.call(this);, that is, the member member of extendAB is assigned from the baseA member to the baseB member.
Of course, we can also slightly modify the baseA code above to verify the correctness of our debugging analysis:
Copy the code code as follows:
function baseA()// base Class A
{
this.memberA = "baseA member"; // member is changed to memberA to distinguish the member in baseB
this.showSelfA = function()
{
window.alert(this.memberA); // Display memberA
}
}
Run browsers such as chrome again, the results are as follows:
baseA member
baseB member
The results are the same as our expectations, and the chrome debugging information also verifies our correctness:
Inheritance improvements (prototype)
The above simulated inheritance method is not the best after careful analysis.
Because every time a member method is defined in a function (class), it will cause a copy of the instance, so you can use the prototype prototype to make improvements.
Examples of improvements are as follows:
Copy the code code as follows:
<!doctype html>
<html>
<head>
<title> call - apply for prototype </title>
</head>
<body>
<script type="text/javascript">
varClass = {
create: function()// create Function
{
return function()
{
this.initialize.apply(this, arguments);
}
}
};
var Person = Class.create();// Create Class Person
Person.prototype = {// prototype initialize
initialize: function(obj1, obj2)
{
this.obj1 = obj1;
this.obj2 = obj2;
},
showSelf: function()
{
alert("obj: " + this.obj1 + " and " + this.obj2);
}
}
// instance Class
var person = new Person("man", "women");// two params
person.showSelf();// show person
</script>
</body>
</html>
The running results are as follows:
obj: men and women