js中call与apply用法

mac2022-06-30  22

js中call与apply用法

前天去面试,有个gg问了一些js知识,其中有一道call与apply用法的题目,尽管在365天前用过call方法,但当时还是没能答上来,今天深入总结一下call和apply,它们的作用都是将函数绑定到另外一个对象上去运行

两者的格式和参数定义:

call( thisArg [,arg1,arg2,… ] );       // 参数列表,arg1,arg2,...

apply(thisArg [,argArray] );                 // 参数数组,argArray

上面两个函数内部的this指针,都会被赋值为thisArg,这可实现将函数作为另外一个对象的方法运行的目的

 

一、call 的简单用法

首先,我们先看个简单的例子(call):

 

[html] view plain copy print ? <!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>   <!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>

 

然后,运行结果如下:

global varglobal varmember varinput textfuncfunc2

测试环境:Google Chrome 10.0.648.45

最后,分析结果

1、全局对象window调用函数gFunc,this指向window对象,因此this.value为global var

2、函数gFunc调用call方法,this默认指向第一个参数window对象,因此this.value也为global var

3、函数gFunc调用call方法,this默认指向第一个参数new mFunc(),即mFunc的对象,因此this.value为mFunc的成员变量member var

4、函数gFunc调用call方法,this默认指向第一个参数input text控件,即id=‘idTxt’的控件,因此this.value为input控件的value值input text

5、函数func2调用call方法,this默认指向第一个参数func函数对象,因此this.value为this.a,即func

6、函数func2调用call方法,第二个参数属于函数对象func2的参数,因此alert(x)为第二个参数func2

 

 

二、call 继承用法与改进

js使用call模拟继承

测试代码:

 

[html] view plain copy print ? <!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>   <!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> 运行结果如下:

 

baseB member

baseB member

测试环境:Google Chrome 10.0.648.45

结果分析:

预期的结果,应该是输出 baseA member 和 baseB member,但实际输出却是 baseB member 和 baseB member

(已在IE9、8、6,Maxthon、Chrome、FF、Opera、Safari、360等浏览器测试过,结果都是后者:baseB member)

至此,机器是不会错的,这就需要我们深入分析

我们可能会很容易想到是this引起的,this两次都指向了baseB对象,但是推测真是这样吗?

为了探究实质,我们借助chrome浏览器的调试工具,下断点,进行调试,结果发现:

当调用extend.showSelfA();时,此时的this指向extendAB(并不是我们推测的两次都指向baseB对象

真实原因是extendAB对象的成员变量member在被baseB.call(this);实例化时,被baseB的成员member覆盖了,即extendAB的成员member由baseA member赋值成了baseB member

当然,我们也可以对上面baseA代码稍作修改,来验证我们调试分析的正确性:

function baseA()// base Class A{this.memberA = "baseA member";   // member改成memberA,以区分baseB中的memberthis.showSelfA = function(){window.alert(this.memberA);    // 显示memberA}}

再次运行chrome等浏览器,结果如下:

baseA  member

baseB member

 

结果和我们的预期相同,同时chrome调试信息也验证了我们的正确性:

 

 

继承改进(prototype)

以上模拟继承方法,仔细分析不是最好的。

因为每次在函数(类)中定义了成员方法,都会导致实例有副本,因此可以借助prototype原型,进行改进

改进举例如下:

 

[html] view plain copy print ? <!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>   <!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> 运行结果如下: obj: man and women   来自:http://blog.csdn.net/sunboy_2050/article/details/6592082

转载于:https://www.cnblogs.com/lidj/p/3171360.html

相关资源:JAVA上百实例源码以及开源项目
最新回复(0)