The original link in the magic of JavaScript in the Apply, call, bind
Although many online articles, mostly copy and paste, and obscure difficult to understand, I hope that through this article, can clearly improve the apply, call, bind understanding, and list some of their magical use to deepen memory.
Apply, call
In JavaScript, call and apply are meant to change the context in which a function is run, in other words, to change the direction of this within the function body.
A major feature of JavaScript is the notion that a function has a "context of definition" and a "runtime context" and a "context can be changed."
First, a chestnut:
1234567891011 |
function fruits() {}
fruits.prototype = {
color:
"red"
,
say:
function
() {
console.log(
"My color is " +
this
.color);
}
}
var apple =
new fruits;
apple.say();
//My color is red
|
But if we have an object banana= {color: "Yellow"}, we don't want to redefine it say method, then we can use call or apply with Apple's say method:
12345 |
banana = { color: "yellow" } apple.say.call(banana); //My color is yellow apple.say.apply(banana); //My color is yellow |
So, you can see that call and apply are to change this dynamically, when an object does not have a method (this pest banana no say method), but the others have (this pest Apple has say method), We can use call or apply to manipulate other object methods.
The difference between apply and call
For both apply and call, the function is exactly the same, except that the parameters are accepted in a different way. For example, there is a function defined as follows:
123 |
var func = function (arg1, arg2) { }; |
You can invoke the following method:
12 |
func.call( this , arg1, arg2); func.apply( this , [arg1, arg2]) |
Where this is the context you want to specify, he can be any JavaScript object (everything in JavaScript), call needs to pass parameters in order, and apply is to put the parameters in the array.
In JavaScript, the number of arguments for a function is not fixed, so if you want to apply the condition, call is used when your parameters are clearly known.
Use apply when unsure, and then pass in the parameter push into the array. When the number of arguments is indeterminate, the function can also traverse all the arguments by arguments the array.
To consolidate your memory, here are some common uses:
1. Append between arrays
1234 |
var array1 = [12 , "foo" , {name "Joe" } , -2458]; var array2 = [ "Doe" , 555 , 100]; Array.prototype.push.apply(array1, array2); /* array1 值为 [12 , "foo" , {name "Joe"} , -2458 , "Doe" , 555 , 100] */ |
2. Get the maximum and minimum values in the array
123 |
var numbers = [5, 458 , 120 , -215 ]; var maxInNumbers = Math.max.apply(Math, numbers), //458 maxInNumbers = Math.max.call(Math,5, 458 , 120 , -215); //458 |
Number itself does not have the Max method, but with Math, we can use call or apply its methods.
3. Verify that it is an array (provided the ToString () method has not been rewritten)
123 |
functionisArray(obj){ returnObject.prototype.toString.call(obj) === ‘[object Array]‘ ; } |
4. Class (pseudo) array using array method
1 |
var domNodes = Array.prototype.slice.call(document.getElementsByTagName( "*" )); |
There is an object structure called a pseudo-array in JavaScript. In particular, arguments objects, as well as calls to getElementsByTagName, document.childnodes and so on, return nodelist objects that are pseudo-arrays. You cannot apply the push, pop, and other methods under the array.
But we can convert the object with the length property to the real array by Array.prototype.slice.call, so that domnodes can apply all the methods under the array.
In-depth understanding of applying apply, call
Below to borrow an interview question, to go deeper to understand the next apply and call.
Define a log method that allows it to proxy the Console.log method, and the common workaround is to:
12345 |
function log(msg) { console.log(msg); } log(1); //1 log(1,2); //1 |
The above method can solve the most basic requirements, but when the number of incoming parameters is not deterministic, the above method is invalid, this time you can consider using apply or call, notice here how many parameters are indeterminate, so using apply is the best, the method is as follows:
12345 |
function log(){ console.log.apply(console, arguments); }; log(1); //1 log(1,2); //1 2 |
The next requirement is to add a "(app)" prefix to each log message, such as:
1 |
log( "hello world" ); //(app)hello world |
What should be more elegant? This time you need to think that the arguments parameter is a pseudo-array, converted to a standard array by Array.prototype.slice.call, and then using the array method Unshift, like this:
123456 |
function log(){ var args = Array.prototype.slice.call(arguments); args.unshift( ‘(app)‘ ); console.log.apply(console, args); }; |
Bind
Finish the Apply and call, and then say bind. The bind () method is similar to apply and call and can also change the direction of this in the function body.
The MDN explanation is that the bind () method creates a new function called a binding function that, when called, binds the binding function to the first parameter of the bind () method as it is created when it is passed into bind () The second and subsequent parameters of the method plus the arguments of the binding function itself are invoked in order as parameters of the original function to invoke the original function.
Take a look directly at how to use it, in common monomer patterns, we usually use _this, that, self, and so on to save this, so that we can continue to reference it after changing the context. Like this:
12345678910 |
var foo = {
bar : 1,
eventBind:
function
(){
var _this =
this
;
$(
‘.someClass‘
).on(
‘click‘
,
function
(event) {
/* Act on the event */
console.log(_this.bar);
//1
});
}
}
|
Due to Javascript-specific mechanisms, the context is transitioning to $ ('. SomeClass ') in Eventbind:function () {}. On (' click ', Function (event) {}) changed, the above using variables to save This is all useful and there is nothing wrong with it. Of course, using bind () can solve this problem more gracefully:
123456789 |
var foo = {
bar : 1,
eventBind:
function
(){
$(
‘.someClass‘
).on(
‘click‘
,
function
(event) {
/* Act on the event */
console.log(
this
.bar);
//1
}.bind(
this
));
}
}
|
In the above code, bind () creates a function that, when the Click event is bound to be called, its this keyword is set to the value passed in (this refers to the parameter passed in when bind () is called). So here we pass in the desired context this (actually foo), into the bind () function. Then, when the callback function is executed, this points to the foo object. One more simple chestnut:
123456789 |
var bar = function () { console.log ( This .x); } var foo = { x:3 } Bar (); //undefined var func = Bar.bind (foo); func (); //3 |
Here we create a new function func, when it is executed by using bind () to create a binding function, it will be set to Foo instead of the global scope as we call Bar ().
The interesting question is, if you have a continuous bind () two times, or a continuous bind () three times, what is the output value? Like this:
1234567891011121314151617 |
var bar =
function
(){
console.log(
this
.x);
}
var foo = {
x:3
}
var sed = {
x:4
}
var func = bar.bind(foo).bind(sed);
func();
//?
var fiv = {
x:5
}
var func = bar.bind(foo).bind(sed).bind(fiv);
func();
//?
|
The answer is that the two will still output 3, not the expected 4 and 5. The reason is that in JavaScript, multiple bind () is not valid. For a deeper reason, the implementation of BIND () is equivalent to using a function to wrap a call/apply inside, and the second bind () is equivalent to wrapping the first bind (), so the second bind is not valid.
Apply, call, bind comparison
So what are the similarities and differences between apply, call, and bind? When to use apply, call, and when to use bind. Simple one of the chestnuts:
12345678910111213 |
var obj = {
x: 81,
};
var foo = {
getX:
function
() {
return this
.x;
}
}
console.log(foo.getX.bind(obj)());
//81
console.log(foo.getX.call(obj));
//81
console.log(foo.getX.apply(obj));
//81
|
All three outputs are 81, but note that with the bind () method, he has more pairs of parentheses behind him.
That is, the difference is that the bind () method is used when you want to change the context and not execute immediately, but rather when the callback executes. The Apply/call executes the function immediately.
Let's summarize:
- Apply, call, and bind are all pointers to the This object that is used to change the function;
- Apply, call, bind the first parameter is the object that this is to point to, that is, the context you want to specify;
- Apply, call, bind three can use the following parameters to pass the parameter;
- Bind is to return the corresponding function, which is convenient to call later; apply, call is called immediately.
(turn) apply, call, bind in JavaScript