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."
function fruits () {} Fruits.prototype = { color: "Red", say:function () { console.log ("My color is" + this.co LOR);} } 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:
Banana = { color: "Yellow"}apple.say.call (banana); My color is yellowapple.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.
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:
var func = function (Arg1, arg2) { };
You can invoke the following method:
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.
To consolidate your memory, here are some common uses:
Append between apply, call instance array
var array1 = [N, "foo", {name: "Joe"},-2458]; var array2 = ["Doe", 555, 100]; Array.prototype.push.apply (Array1, array2); The Array1 value is
Gets the maximum and minimum values in the array
var numbers = [5, 458, -215], var maxinnumbers = Math.max.apply (Math, numbers), //458 maxinnumbers = M Ath.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.
Verify that the array is not (provided that the ToString () method has not been rewritten)
Functionisarray (obj) { return Object.prototype.toString.call (obj) = = = ' [Object Array] ';}
Class (pseudo) arrays using array methods
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.
Interview questions
Define a log method that allows it to proxy the Console.log method, and the common workaround is to:
function log (msg) { console.log (msg);} Log (1); 1log (up to); 1
The above method can solve the most basic requirements, but when the number of incoming parameters is uncertain, the above method is invalid, this time you can consider using apply or call, note here 传入多少个参数是不确定的
, so use Apply is the best, the method is as follows:
function log () { console.log.apply (console, arguments);}; Log (1); 1log (up to); 1 2
The next requirement is to add a "(app)" prefix to each log message, such as:
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:
function log () { var args = Array.prototype.slice.call (arguments); Args.unshift (' (app) '); Console.log.apply (console, args);};
Bind
Before discussing the bind () method, let's look at a topic:
var altwrite = document.write;altwrite ("Hello");
Results:Uncaught TypeError: Illegal invocation
The Altwrite () function Changes the point of this to the global or Window object, causing the execution to prompt for an illegal call to the exception, and the correct scenario is to use the bind () method:
Altwrite.bind (document) ("Hello")
Of course, you can also use the call () method:
Altwrite.call (document, "Hello")
Binding functions
bind()
The simplest use is to create a function so that the function has the same this value regardless of how it is called. The common mistake is to take the method out of the object, just like the example above, and then call it and want this to point to the original object. If you do not do special processing, you will generally lose the original object. Using the bind () method can be a pretty good solution to this problem:
This.num = 9; var mymodule = { num:81, getnum:function () { console.log (this.num); }}; Mymodule.getnum (); 81var getnum = Mymodule.getnum;getnum (); 9, because in this example, "This" points to the global object var boundgetnum = Getnum.bind (MyModule); Boundgetnum (); 81
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:
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:
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 invoked, 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:
var bar = function () {console.log (this.x);} var foo = {X:3}bar (); Undefinedvar 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 ().
Partial function (partial Functions)
The partial functions is also called the partial applications, which intercepts a definition of the partial function:
Partial application can be described as taking a function this accepts some number of arguments, binding values to one or More than those arguments, and returning a new function that is only accepts the remaining, un-bound arguments.
This is a good feature, using the bind()
predefined parameters of the function that we set, and then passing in other parameters when called:
Function List () { return Array.prototype.slice.call (arguments);} var list1 = list (1, 2, 3); [1, 2, 3]//predefined parameters 37var leadingthirtysevenlist = list.bind (undefined, PNS); var list2 = Leadingthirtysevenlist (); [37]var list3 = Leadingthirtysevenlist (1, 2, 3); [37, 1, 2, 3]
Used with the settimeout
function Bloomer () { this.petalcount = Math.ceil (Math.random () * 12) + 1;} After 1 seconds, call the Declare function Bloomer.prototype.bloom = function () { window.settimeout (This.declare.bind (this), 100);}; Bloomer.prototype.declare = function () { console.log (' I have ' + this.petalcount + ' petals! ');}; var Bloo = new Bloomer (); Bloo.bloom (); I have 5 petals!
Note: The above method can also be used for event handlers and SetInterval methods
Binding functions as constructors
The binding function is also useful for constructing an instance of the target function using the new operator. When using a binding function to construct an instance, note that this is ignored, but the parameters passed in are still available.
function point (x, y) { this.x = x; This.y = y;} Point.prototype.toString = function () { console.log (this.x + ', ' + This.y);}; var p = new Point (1, 2);p. toString (); ' Emptyobj ' var = {};var Yaxispoint = Point.bind (Emptyobj, 0/*x*/);//examples in implementation not supported,//native bind support: var yaxispoint = Point.bi nd (NULL, 0/*x*/), var axispoint = new Yaxispoint (5); axispoint.tostring (); ' 0,5 ' axispoint instanceof point; Trueaxispoint instanceof Yaxispoint; Truenew Point (instanceof) Yaxispoint; True
Shortcut
Bind () can also create shortcuts for functions that require a specific this value.
For example, to convert a class array object to a real array, the possible examples are as follows:
var slice = array.prototype.slice;//... slice.call (arguments);
If used bind()
, the situation becomes simpler:
var unboundslice = Array.prototype.slice;var slice = Function.prototype.call.bind (unboundslice);//... slice (arguments );
Realize
The above sections show that bind () has a lot of usage scenarios, but the bind () function is added to the fifth version of ECMA-262; it may not run on all browsers. This requires that we implement the bind () function ourselves.
First, we can simply implement the bind () method by assigning a scope to the target function:
Function.prototype.bind = function (context) {self = this; Save this, that is, the target function that calls the Bind method return functions () { return self.apply (context,arguments); };};
Given the case of the function curry, we can build a more robust bind ():
Function.prototype.bind = function (context) { var args = Array.prototype.slice.call (arguments, 1), self = this; return function () { var Innerargs = Array.prototype.slice.call (arguments); var Finalargs = Args.concat (Innerargs); Return self.apply (Context,finalargs);};
This time the bind()
method can bind the object, and also support the argument when binding.
Continue, JavaScript functions can also be used as constructors, so when the bound function is called in this way, the situation is more subtle and involves the delivery of the prototype chain:
Function.prototype.bind = function (context) { var args = Array.prototype.slice (arguments, 1), F = function () {}, Self = this, bound = function () { var Innerargs = Array.prototype.slice.call (arguments); var Finalargs = Args.concat (Innerargs); Return Self.apply ((this instanceof F this:context), Finalargs); }; F.prototype = Self.prototype; Bound.prototype = new F (); return bound;};
This is the implementation of BIND () in JavaScript Web application: By setting a transit constructor F, the bound function is on the same prototype chain as the function calling bind (), and the new operator invokes the bound function. The returned object can also use instanceof normally, so this is the most rigorous bind () implementation.
For the ability to support the bind () function in the browser, you only need to modify the above function slightly:
Function.prototype.bind = function (othis) { if (typeof this!== "function") { throw new TypeError ("Function.prot Otype.bind-what is trying to being bound is not callable "); } var Aargs = Array.prototype.slice.call (arguments, 1), ftobind = this, Fnop = function () {}, Fbound = function () { return ftobind.apply (this instanceof fnop && othis? this:othis | | window, aargs.concat (Array . Prototype.slice.call (arguments)) ; }; Fnop.prototype = This.prototype; Fbound.prototype = new Fnop (); return fbound; };
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:
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 = b Ar.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:
var obj = { x:81,}; var foo = { getx:function () { return this.x; }} console.log (Foo.getX.bind (obj) ());
//81console.log (Foo.getX.call (obj)); 81console.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.
JS in the call, apply, bind method detailed