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 相关文章推荐
javascript 表单的友好用户体现
Jan 07 Javascript
jQuery基础知识filter()和find()实例说明
Jul 06 Javascript
JQuery小知识
Oct 15 Javascript
基于jQuery的遍历同id元素 并响应事件的代码
Jun 14 Javascript
利用jquery包将字符串生成二维码图片
Sep 12 Javascript
JS实现仿Windows7风格的网页右键菜单效果代码
Sep 11 Javascript
Bootstrap Chart组件使用教程
Apr 28 Javascript
一个仿微博登陆邮箱提示框js开发案例
Jul 28 Javascript
基于substring()和substr()的使用以及区别(实例讲解)
Dec 28 Javascript
vue项目中axios请求网络接口封装的示例代码
Dec 18 Javascript
vue+iview 兼容IE11浏览器的实现方法
Jan 07 Javascript
vue cli3.0打包上线静态资源找不到路径的解决操作
Aug 03 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在多维数组中根据键名快速查询其父键以及父键值的代码
2011/05/07 PHP
php导出csv数据在浏览器中输出提供下载或保存到文件的示例
2014/04/24 PHP
总结PHP中DateTime的常用方法
2016/08/11 PHP
遍历jquery对象的代码分享
2011/11/02 Javascript
用js通过url传参把数据从一个页面传到另一个页面
2014/09/01 Javascript
JQuery的Ajax中Post方法传递中文出现乱码的解决方法
2014/10/21 Javascript
原生JS实现-星级评分系统的简单实例
2016/08/21 Javascript
js中toString()和String()区别详解
2017/03/23 Javascript
jQuery实现 RadioButton做必选校验功能
2017/06/15 jQuery
JS实现移动端按首字母检索城市列表附源码下载
2017/07/05 Javascript
原生JS实现$.param() 函数的方法
2018/08/10 Javascript
Angular6 Filter实现页面搜索的示例代码
2018/12/02 Javascript
深入分析element ScrollBar滚动组件源码
2019/01/22 Javascript
vue iview多张图片大图预览、缩放翻转
2019/07/13 Javascript
Layui数据表格跳转到指定页的实现方法
2019/09/05 Javascript
[10:14]2018DOTA2国际邀请赛寻真——paiN Gaming不仅为自己而战
2018/08/14 DOTA
Python两个内置函数 locals 和globals(学习笔记)
2016/08/28 Python
python生成圆形图片的方法
2020/03/25 Python
python 将字符串转换成字典dict的各种方式总结
2018/03/23 Python
python抓取网页内容并进行语音播报的方法
2018/12/24 Python
Python collections.defaultdict模块用法详解
2020/06/18 Python
五款漂亮的纯CSS3动画按钮的实例教程
2014/11/21 HTML / CSS
CSS3实现内凹圆角的实例代码
2017/05/04 HTML / CSS
什么是触发器(trigger)? 触发器有什么作用?
2013/09/18 面试题
linux面试题参考答案(2)
2015/12/06 面试题
Linux开机引导的步骤是什么
2015/10/19 面试题
Java程序员面试题
2016/09/27 面试题
金属材料工程毕业生个人的自我评价
2013/11/28 职场文书
高中班长自我鉴定
2013/12/20 职场文书
一份创业计划书范文
2014/02/08 职场文书
税务会计岗位职责
2014/02/18 职场文书
中国好声音广告词
2014/03/18 职场文书
租房协议书怎么写
2014/04/10 职场文书
助残日活动总结
2014/08/27 职场文书
简单通用的简历自我评价
2014/09/21 职场文书
复兴之路纪录片观后感
2015/06/02 职场文书