Summary of the usage of call and apply in js

  • 2020-03-30 01:09:42
  • OfStack

The day before yesterday, I went to the interview and a gg asked me some js knowledge. There was a question about the usage of call and apply. Although I used the call method 365 days ago, I still failed to answer it

Call and apply, both of which bind the function to run on another object

Format and parameter definition of both:

Call (thisArg [, arg1, arg2...]);             // argument list, arg1, arg2...
Apply (thisArg [, argArray]);                                 // parameter array, argArray

The this pointer inside the above two functions is assigned to thisArg, which enables the function to be run as a method of another object

1. Simple usage of "call"

First, let's look at a simple example (call) :


<!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 results are as follows:

Global var
Global var
Member var
Input text
func
func2

Test environment: Google Chrome  10.0.648.45

Finally, analyze the results

1. The global object window calls the function gFunc, this points to the window object, so the this.value is global var

2. Function gFunc calls the call method, this by default refers to the first parameter window object, so this.value is also global var

3. Function gFunc calls the call method. By default, this refers to the first parameter new mFunc(), which is the object of mFunc

4. Function gFunc calls the call method. By default, this refers to the input text control with the first parameter, that is, the control with id= 'idTxt'

5. Function func2 calls the call method, this by default refers to the first parameter func function object, so this.value is this.a, namely func

6. Function func2 calls the call method, and the second parameter belongs to the function object func2, so alert(x) is the second parameter func2


Ii. Usage and improvement of call inheritance

Js USES call to simulate inheritance

Test code:


<!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 operation results are as follows:

BaseB member
BaseB member

Test environment: Google Chrome  10.0.648.45

Result analysis:

The expected result should be output baseA member and baseB member, but the actual output is baseB member and baseB member

(has been tested in IE9, 8, 6, Maxthon, Chrome, FF, Opera, Safari, 360 and other browsers, the results are the latter: baseB member)

At this point, the machine is not wrong, which requires further analysis

It might be easy to think of this as causing this, which both points to baseB objects, but is that true?

To get to the heart of the matter, we used chrome's debugging tools to break down breakpoints and debug.

< img Alt = "" border = 0 SRC =" / / img.jbzj.com/file_images/article/201312/20131228100214.png ">

When calling the extend. ShowSelfA (); , this point to extendAB (not pointing to baseB object twice as we speculated)

The real reason is that the member variable of extendAB object is in baseb. call(this); When instantiated, it is overwritten by the member of baseB, that is, the member of extendAB is assigned to baseB member by baseA member

Of course, we can also modify the above baseA code to verify the correctness of our debugging analysis:


function baseA()  // base Class A
{
 this.memberA = "baseA member";   //Change member to memberA to distinguish members in baseB
 this.showSelfA = function()
 {
  window.alert(this.memberA);    //Display memberA
 }
}

Run chrome and other browsers again and the results are as follows:

BaseA  member
BaseB member

The results were the same as we had expected, and the chrome debugging information also confirmed our correctness:

< img Alt = "" border = 0 SRC =" / / img.jbzj.com/file_images/article/201312/20131228100420.png ">

Inheritance and improvement (prototype)

The above simulation inheritance method, careful analysis is not the best.

Because every time a member method is defined in a function (class), it results in a copy of the instance, you can improve on it with the prototype prototype

Examples of improvements are as follows:


<!doctype html>
<html>
 <head>
  <title> call - apply for prototype </title>
 </head>

 <body>
  <script type="text/javascript">
   var Class = {
    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 operation results are as follows:
Obj: man and women


Related articles: