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 相关文章推荐
YUI 读码日记之 YAHOO.util.Dom - Part.1
Mar 22 Javascript
JQuery AJAX实现目录浏览与编辑的代码
Oct 21 Javascript
[原创]js获取数组任意个不重复的随机数组元素
Mar 15 Javascript
JavaScript 保存数组到Cookie的代码
Apr 14 Javascript
javascript实现简单的页面右下角提示信息框
Jul 31 Javascript
基于Jquery easyui 选中特定的tab
Nov 17 Javascript
jQuery视差滚动效果网页实现方法经验总结
Sep 29 Javascript
谈谈JavaScript数组常用方法总结
Jan 24 Javascript
Node.js环境下Koa2添加travis ci持续集成工具的方法
Jun 19 Javascript
jQuery实现的简单前端搜索功能示例
Oct 28 jQuery
vue点击按钮实现简单页面的切换
Sep 08 Javascript
用JS实现飞机大战小游戏
Jun 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
DedeCMS 核心类TypeLink.class.php摘要笔记
2010/04/07 PHP
php实现给图片加灰色半透明效果的方法
2014/10/20 PHP
PHP在innodb引擎下快速代建全文搜索功能简明教程【基于xunsearch】
2016/10/14 PHP
用jquery实现点击栏目背景色改变
2012/12/10 Javascript
javascript 模拟坦克大战游戏(html5版)附源码下载
2014/04/08 Javascript
再分享70+免费的jquery 图片滑块效果插件和教程
2014/12/15 Javascript
js面向对象之公有、私有、静态属性和方法详解
2015/04/17 Javascript
jQuery编写网页版2048小游戏
2017/01/06 Javascript
jQuery实现复选框的全选和反选
2017/02/02 Javascript
jquery实现数字输入框
2017/02/22 Javascript
jQuery中each方法的使用详解
2018/03/18 jQuery
原生JS实现的简单轮播图功能【适合新手】
2018/08/17 Javascript
Vue 第三方字体图标引入 Font Awesome的方法
2018/09/28 Javascript
VuePress 静态网站生成方法步骤
2019/02/14 Javascript
vue element upload实现图片本地预览
2019/08/20 Javascript
深入浅析Python中join 和 split详解(推荐)
2016/06/30 Python
Python中二维列表如何获取子区域元素的组成
2017/01/19 Python
利用python3随机生成中文字符的实现方法
2017/11/24 Python
使用python中的in ,not in来检查元素是不是在列表中的方法
2018/07/06 Python
python实现汽车管理系统
2018/11/30 Python
Python 硬币兑换问题
2019/07/29 Python
Python 调用 Windows API COM 新法
2019/08/22 Python
pytest中文文档之编写断言
2019/09/12 Python
Python中__repr__和__str__区别详解
2019/11/07 Python
Flask和pyecharts实现动态数据可视化
2020/02/26 Python
Python socket连接中的粘包、精确传输问题实例分析
2020/03/24 Python
解决PyCharm IDE环境下,执行unittest不生成测试报告的问题
2020/09/03 Python
Manuka Doctor英国官网:真正的麦卢卡蜂蜜和护肤品
2018/10/26 全球购物
澳大利亚领先的武术用品和健身器材供应商:SMAI
2019/03/24 全球购物
茱莉蔻美国官网:Jurlique美国
2020/11/24 全球购物
小学运动会表扬稿
2014/01/19 职场文书
2014年社区综治工作总结
2014/11/17 职场文书
写给导师的自荐信
2015/03/06 职场文书
2015年前台接待工作总结
2015/05/04 职场文书
Python 内置函数速查表一览
2021/06/02 Python
Python查找算法的实现 (线性、二分,分块、插值查找算法)
2022/04/24 Python