js中call与apply的用法小结


Posted in Javascript onDecember 28, 2013

前天去面试,有个gg问了一些js知识,其中有一道call与apply用法的题目,尽管在365天前用过call方法,但当时还是没能答上来,今天深入总结一下

call和apply,它们的作用都是将函数绑定到另外一个对象上去运行

两者的格式和参数定义:

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

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

一、call 的简单用法

首先,我们先看个简单的例子(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>

然后,运行结果如下:

global var
global var
member var
input text
func
func2

测试环境: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模拟继承

测试代码:

<!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浏览器的调试工具,下断点,进行调试,结果发现:

js中call与apply的用法小结

当调用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中的member
 this.showSelfA = function()
 {
  window.alert(this.memberA);    // 显示memberA
 }
}

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

baseA  member
baseB member

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

js中call与apply的用法小结

继承改进(prototype)

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

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

改进举例如下:

<!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
Javascript 相关文章推荐
js模拟滚动条(横向竖向)
Feb 22 Javascript
jQuery实现多按钮单击变色
Nov 27 Javascript
node.js中的fs.appendFileSync方法使用说明
Dec 17 Javascript
jQuery层级选择器实例代码
Feb 06 Javascript
javascript+html5+css3自定义提示窗口
Jun 21 Javascript
Vue.js 动态为img的src赋值方法
Mar 14 Javascript
jQuery阻止事件冒泡实例分析
Jul 03 jQuery
JavaScript作用域、闭包、对象与原型链概念及用法实例总结
Aug 20 Javascript
vue中的watch监听数据变化及watch中各属性的详解
Sep 11 Javascript
jQuery 操作 HTML 元素和属性的方法
Nov 12 jQuery
移动端滑动切换组件封装 vue-swiper-router实例详解
Nov 25 Javascript
解决vue组件中click事件失效的问题
Nov 09 Javascript
SinaEditor使用方法详解
Dec 28 #Javascript
Jqgrid表格随窗口大小改变而改变的简单实例
Dec 28 #Javascript
jqGrid随窗口大小变化自适应大小的示例代码
Dec 28 #Javascript
jQuery对Select的操作大集合(收藏)
Dec 28 #Javascript
Jqgrid设置全选(选择)及获取选择行的值示例代码
Dec 28 #Javascript
jquery改变tr背景色的示例代码
Dec 28 #Javascript
javaScript对文字按照拼音排序实现代码
Dec 27 #Javascript
You might like
php字符串截取中文截取2,单字节截取模式
2007/12/10 PHP
php使用number_format函数截取小数的方法分析
2016/05/27 PHP
js 时间格式与时间戳的相互转换示例代码
2013/12/25 Javascript
浅谈jQuery事件绑定原理
2015/01/02 Javascript
jQuery功能函数详解
2015/02/01 Javascript
JS简单限制textarea内输入字符数量的方法
2015/10/14 Javascript
MVC Ajax Helper或Jquery异步加载部分视图
2015/11/29 Javascript
JS拖拽组件学习使用
2016/01/19 Javascript
Javascript的表单验证-提交表单
2016/03/18 Javascript
jQuery实现的导航动画效果(附demo源码)
2016/04/01 Javascript
简单易懂的天气插件(代码分享)
2017/02/04 Javascript
arcgis for js栅格图层叠加(Raster Layer)问题
2017/11/22 Javascript
javascript关于“时间”的一次探索
2019/07/24 Javascript
关于ligerui子页面关闭后,父页面刷新,重新加载的方法
2019/09/27 Javascript
Python三元运算实现方法
2015/01/12 Python
Python下的Softmax回归函数的实现方法(推荐)
2017/01/26 Python
python装饰器常见使用方法分析
2019/06/26 Python
python scrapy重复执行实现代码详解
2019/12/28 Python
tensorflow 只恢复部分模型参数的实例
2020/01/06 Python
python3中sys.argv的实例用法
2020/04/24 Python
通过代码实例了解Python3编程技巧
2020/10/13 Python
Django如何重置migration的几种情景
2021/02/24 Python
three.js模拟实现太阳系行星体系功能
2019/09/03 HTML / CSS
阿联酋优惠券服务:Living Kool
2019/12/12 全球购物
.NET程序员的数据库面试题
2012/10/10 面试题
大学生预备党员自我评价分享
2013/11/16 职场文书
行政人事专员岗位职责
2014/03/05 职场文书
国际政治学专业推荐信
2014/09/26 职场文书
县级领导干部开展党的群众路线教育实践活动工作汇报
2014/10/25 职场文书
南极大冒险观后感
2015/06/05 职场文书
cf战队宣传语
2015/07/13 职场文书
SQL Server 数据库实验课第五周——常用查询条件
2021/04/05 SQL Server
golang实现一个简单的websocket聊天室功能
2021/10/05 Golang
php将xml转化对象的实例详解
2021/11/17 PHP
Redis基本数据类型哈希Hash常用操作命令
2022/06/01 Redis
win11自动弹出虚拟键盘怎么关闭? Win11关闭虚拟键盘的技巧
2023/01/09 数码科技