Call and apply method parsing

Source: Internet
Author: User
Tags access properties

Ecamscript 3 defines two methods for the prototype of a function, which are Function.prototype.call and function. Prototype.apply. The call and apply methods are particularly useful in real-world development, especially in some functional style code writing. In the JavaScript version of the design pattern, the application of these two methods is very extensive, skilled use of these two methods, we really become a JavaScript programmer an important step.

The difference between 1.call and apply

Function.prototype.call and Function.prototype.apply are very common methods. They function exactly the same, except for the difference in the form of incoming parameters.

Apply accepts two parameters, the first parameter specifies the pointer to the this object in the function body, and the second parameter is an indexed collection, which can be an array or a class, and the Apply method passes the elements in the collection as arguments to the called function:

var function  //  Output [1, 2, 3]null

In this code, parameters 1, 2, and 3 are placed in the array with the Func function, which corresponds to a, B, C in the Func parameter list, respectively.

Call the number of parameters passed is not fixed, the same as apply, the first parameter is also representative of the function body of this point, starting from the second parameter, each parameter is passed to the function sequentially:

var function  //  Output [1, 2, 3]null

When invoking a function, the JavaScript interpreter does not care about the difference in the number, type, and order of formal parameters and arguments, and JavaScript's parameters are internally represented by an array. In this sense, apply is higher than the use of call, we do not have to care about how many parameters are passed in the function, as long as apply a brain to push the past.

Call is a syntactic sugar wrapped in apply, and if we know exactly how many parameters the function accepts, and if we want to express the corresponding relationship between the formal parameter and the argument at a glance, you can also use call to transfer the parameters.

When using call or apply, if the first argument we pass in is null, this in the body of the function points to the default host object, which is window in the browser:

var function (A, B, c) {    this = = window);  //   Output Truenull

However, if it is in strict mode, this is still null in the body of the function:

var function (A, B, c) {  "use strict";     This NULL // Output True  Null

Sometimes we use call or apply for the purpose of not specifying this point, but for another purpose, such as the method of borrowing other objects. Then we can pass in NULL instead of a specific object:

NULL //

Use of 2.call and apply

2.1 Change this point

The most common use of call and apply is to change the this point inside the function, let's look at an example:

var obj1 = {   ' Sven '}; var obj2 = {   ' anne '= ' window '; var function () {  this//  output: Window//  output: Sven //

When executing the code for Getname.call (OBJ1), this in the GetName function points to the Obj1 object, so the

var function () {  this

is actually equivalent to:

var function () {  //  output: Sven

In the actual development, often encounter this point to the inadvertently changed scenes, such as a div node, the DIV node onclick event in this is a point to this div:

function () {  this//  output: Div1

If there is an internal function func in the event function, and the Func function is called inside the event, the this in the Func function body points to the window instead of the div we expect, see the following code:

function () {   this//  output: Div1   varfunction() {     This // Output: Undefined

At this point we use call to fix this in the Func function so that it still points to the DIV:

function () {   varfunction() {   this//  output: Div1    This

Use call to fix this scenario, such as correcting the "lost" inside the document.getElementById function, the code is as follows:

document.getElementById = (function(func) {     returnfunction() {          return  func.apply (document, arguments);     }) (document.getElementById); var getId = document.getElementById; var div = getId (' div1 '//

2.2 Function.prototype.bind

Most advanced browsers implement the built-in Function.prototype.bind to specify the this point inside the function, even if there is no native Function.prototype.bind implementation, it is not difficult to simulate one, the code is as follows:

Function.prototype.bind =function(context) {varSelf = This;//Save original function return function(){//returns a new function returnSelf.apply (context, arguments);//when a new function is executed, the previously passed-in context //as this in the new function body }};varobj ={name:' Sven '};varFunc =function() {alert ( This. name);//Output: Sven}.bind (obj); func (); 

We "wrap" the Func function through Function.prototype.bind, and pass in an object context as a parameter, which is the this object we want to fix.

In the internal implementation of Function.prototype.bind, we first save the reference to the Func function and then return a new function. When we execute the Func function in the future, we are actually going to execute the new function that we just returned. Inside the new function, self.apply (context, arguments) is the code that executes the original Func function, and specifies that the context object is this in the body of the Func function.

This is a simplified version of the Function.prototype.bind implementation, usually we will also implement it a little more complex, so that you can pre-fill in the Func function some parameters:

Function.prototype.bind =function(){ varSelf = This,//Save original functioncontext = [].shift.call (arguments),//the this context that needs to be boundargs = [].slice.call (arguments);//remaining parameter to array return function(){//returns a new function returnself.apply (context, [].concat.call (args, [].slice.call (arguments))];//when a new function is executed, the previously passed context is treated as this in the new function body. //and combine two parameters passed in separately as parameters of the new function } };varobj ={name:' Sven '};varFunc =function(A, B, C, D) {alert ( This. name);//Output: SvenAlert ([A, B, C, d])//output: [1, 2, 3, 4]}.bind (obj, 1, 2); Func (3, 4);

2.3 Ways to borrow other objects

We know that the cuckoo neither nests nor hatches, but lays his eggs on other birds, such as larks, to incubate and nurture them on their behalf. Similarly, there is a similar borrowing phenomenon in JavaScript.

The first scenario for borrowing a method is "borrowing a constructor", which enables some similar effects to be inherited:

 var  A = function   this . Name = name;};  var  B = function   () {a.apply ( this   = function   () {  return  this  .name;};  var  b = new  B (' Sven '  //  output: ' Sven '  

The second use scenario of the borrowing method is more closely related to our relationship.

The function's argument list arguments is a class array object, and although it also has "subscript", it is not a real array, so it cannot be sorted like an array or add a new element to the collection. In this case, we will often borrow the method on the Array.prototype object. For example, to add a new element to the arguments, you would typically borrow Array.prototype.push:

(function3//  output [I/O]

When operating arguments, we often find Array.prototype object borrowing methods very frequently.

When you want to turn arguments into a real array, you can borrow the Array.prototype.slice method, or you can borrow the Array.prototype.shift method when you want to intercept the first element in the arguments list. So what is the internal implementation principle of this mechanism? We may as well open the V8 engine source code, take Array.prototype.push as an example, to see the concrete implementation in the V8 engine:

functionArraypush () {varn = To_uint32 ( This. length);//length of the object being push  varm =%_argumentslength ();//number of parameters for push   for(vari = 0; I < m; i++) {        This[i + N] =%_arguments (i);//copying elements (1)  }   This. length = n + M;//fixed the value of the Length property (2)  return  This. length;}; 

As you can see from this code, Array.prototype.push is actually a property copy process, adding parameters to the push object in the following order, and modifying the length property of the object by the way. It does not matter who the modified object is, whether it is an array or an array object of the class.

From this we can infer that we can pass "any" object into Array.prototype.push:

var a =' first '//  output: 1//   First

This code can be executed smoothly in most browsers, but due to differences in the internal implementation of the engine, if executed in a lower version of IE, you must explicitly set the Length property to object A:

var a = {   0

The reason we put the word "arbitrary" in double quotation marks is because the object that can borrow the Array.prototype.push method also satisfies the following two conditions, from the Arraypush function (1) and (2) can also be guessed, this object must satisfy at least:

    • Object itself to be able to access properties
    • The length property of the object can be read and written

For the first condition, the object itself has no problem accessing the property, but what if borrowing the Array.prototype.push method is not an object type of data, but rather a number type of data? We cannot access other data on number, so we can see from the test code below that a number type of data cannot be borrowed to Array.prototype. Push method:

var a = 1' first '//  output: undefined//

For the second condition, the length property of the function is a read-only property that represents the number of formal parameters, and we try to pass a function as this to the Array.prototype.push:

var function  ' first ' ); alert (func.length); //

Call and apply method parsing

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.