apply 接受两个参数,第一个参数指定了函数体内this 对象的指向,第二个参数为一个带下
标的集合,这个集合可以为数组,也可以为类数组,apply 方法把这个集合中的元素作为参数传
递给被调用的函数:

var func = function( a, b, c ){
alert ( [ a, b, c ] ); // 输出 [ 1, 2, 3 ]
};
func.apply( null, [ 1, 2, 3 ] );

在这段代码中,参数 1、2、3 被放在数组中一起传入func 函数,它们分别对应func 参数列
表中的a、b、c。

call 传入的参数数量不固定,跟apply 相同的是,第一个参数也是代表函数体内的this 指向,
从第二个参数开始往后,每个参数被依次传入函数:

var func = function( a, b, c ){
alert ( [ a, b, c ] ); // 输出 [ 1, 2, 3 ]
};
func.call( null, 1, 2, 3 );

当调用一个函数时,JavaScript 的解释器并不会计较形参和实参在数量、类型以及顺序上的

区别,JavaScript 的参数在内部就是用一个数组来表示的。从这个意义上说,apply 比call 的使用

率更高,我们不必关心具体有多少参数被传入函数,只要用apply 一股脑地推过去就可以了。

call 是包装在apply 上面的一颗语法糖,如果我们明确地知道函数接受多少个参数,而且想

一目了然地表达形参和实参的对应关系,那么也可以用call 来传送参数。

call和apply的用途

1. 改变this 指向
call 和apply 最常见的用途是改变函数内部的this 指向,我们来看个例子:

var obj1 = {
name: 'sven'
};
var obj2 = {
name: 'anne'
};
window.name = 'window';
var getName = function(){
alert ( this.name );
};
getName(); // 输出: window
getName.call( obj1 ); // 输出: sven
getName.call( obj2 ); // 输出: anne

当执行getName.call( obj1 )这句代码时,getName 函数体内的this 就指向obj1 对象,所以
此处的

var getName = function(){
alert ( this.name );
};

实际上相当于:
var getName = function(){
alert ( obj1.name ); // 输出: sven
};

在实际开发中,经常会遇到this 指向被不经意改变的场景,比如有一个div 节点,div 节点
的onclick 事件中的this 本来是指向这个div 的:

document.getElementById( 'div1' ).onclick = function(){
alert( this.id ); // 输出:div1
};

假如该事件函数中有一个内部函数func,在事件内部调用func 函数时,func 函数体内的this
就指向了window,而不是我们预期的div,见如下代码:

document.getElementById( 'div1' ).onclick = function(){
alert( this.id ); // 输出:div1
var func = function(){
alert ( this.id ); // 输出:undefined
}
func();
};

这时候我们用call 来修正func 函数内的this,使其依然指向div:

document.getElementById( 'div1' ).onclick = function(){
var func = function(){
alert ( this.id ); // 输出:div1
}
func.call( this );
};

2. Function.prototype.bind

大部分高级浏览器都实现了内置的Function.prototype.bind,用来指定函数内部的this 指向,
即使没有原生的Function.prototype.bind 实现,我们来模拟一个也不是难事,代码如下:

Function.prototype.bind = function( context ){
var self = this; // 保存原函数
return function(){ // 返回一个新的函数
return self.apply( context, arguments ); // 执行新的函数的时候,会 把之前传入的context
// 当作新函数体内的this
}
};
var obj = {
name: 'sven'
};
var func = function(){
alert ( this.name ); // 输出:sven
}.bind( obj);
func();

我们通过Function.prototype.bind 来“包装”func 函数,并且传入一个对象context 当作参
数,这个context 对象就是我们想修正的this 对象。

在Function.prototype.bind 的内部实现中,我们先把func 函数的引用保存起来,然后返回一
个新的函数。当我们在将来执行func 函数时,实际上先执行的是这个刚刚返回的新函数。在新
函数内部,self.apply( context, arguments )这句代码才是执行原来的func 函数,并且指定context
对象为func 函数体内的this。

这是一个简化版的Function.prototype.bind 实现,通常我们还会把它实现得稍微复杂一点,
使得可以往func 函数中预先填入一些参数:

Function.prototype.bind = function(){
var self = this, // 保存原函数
context = [].shift.call( arguments ), // 需要绑定的this 上下文
args = [].slice.call( arguments ); // 剩余的参数转成数组
return function(){ // 返回一个新的函数
return self.apply( context, [].concat.call( args, [].slice.call( arguments ) ) );
// 执行新的函数的时候,会把之前传入的context 当作新函数体内的this
// 并且组合两次分别传入的参数,作为新函数的参数
}
};
var obj = {
name: 'sven'
};
var func = function( a, b, c, d ){
alert ( this.name ); // 输出:sven
alert ( [ a, b, c, d ] ) // 输出:[ 1, 2, 3, 4 ]
}.bind( obj, 1, 2 );
func( 3, 4 );

JavaScript中的call 和apply的用途以及区别的更多相关文章

  1. Javascript中call方法和apply方法用法和区别

    第一次在博客园上面写博客,知识因为看书的时候发现了一些有意思的知识,顺便查了一下资料,就发到博客上来了,希望对大家有点帮助. 连续几天阅读<javascript高级程序设计>这本书了,逐渐 ...

  2. Javascript中call函数和apply函数的使用

    Javascript 中call函数和apply的使用: Javascript中的call函数和apply函数是对执行上下文进行切换,是将一个函数从当前执行的上下文切换到另一个对象中执行,例如: so ...

  3. Javascript 中的 call 和 apply

    发表于 2012年02月1日 by 愚人码头   原文链接:http://www.css88.com/archives/4431 JavaScript 中通过call或者apply用来代替另一个对象调 ...

  4. 从零开始讲解JavaScript中作用域链的概念及用途

    从零开始讲解JavaScript中作用域链的概念及用途 引言 正文 一.执行环境 二.作用域链 三.块级作用域 四.其他情况 五.总结 结束语 引言 先点赞,再看博客,顺手可以点个关注. 微信公众号搜 ...

  5. JavaScript 中定义变量时有无var声明的区别

    关于JavaScript中定义变量时有无var声明的区别 var a=5; //正确 a=5; //正确 在javascript中,以上两种方法都是定义变量的正确方法.微软的Script56.CHM中 ...

  6. JavaScript中querySelector()和getElementById()(getXXXByXX)的区别

    在日常开发中,使用JavaScript获取元素的时候,最常用的方法就是document.getElementById(getXXXByXX)方法.但是最近发现有很多地方使用的是querySelecto ...

  7. 理解JavaScript中的call和apply方法

    call方法 总的来说call()有这几种作用:1.可以借用另一个对象的方法.2.改变this的指向(重要).3.将arguments数组化.下面详细介绍这三种作用: 1.可以借用另一个对象的方法:当 ...

  8. javascript中call函数与apply

    javascript中的call方法使当前对象可以调用另一个对象的方法,即改变this的指向内容 var first_object = { num: 42 }; var second_object = ...

  9. javascript 中caller,callee,call,apply 的概念[转载]

    在提到上述的概念之前,首先想说说javascript中函数的隐含参数:arguments Arguments : 该对象代表正在执行的函数和调用它的函数的参数. [function.]argument ...

随机推荐

  1. ASP.NET 5中的Sake与KoreBuild

    初识ASP.NET 5中的Sake与KoreBuild   从github上签出基于ASP.NET 5的MVC 6的源代码进行编译,发现有2个编译命令: build.cmd是针对Windows的编译命 ...

  2. :link,:visited,:focus,:hover,:active详解

    原文::link,:visited,:focus,:hover,:active详解 CSS 又名 层叠样式表,所谓层叠,就是后面的样式会覆盖前面的样式,所以在样式表中,各样式排列的顺序很有讲究.   ...

  3. 4. SQL Server数据库状态监控 - 作业状态

    原文:4. SQL Server数据库状态监控 - 作业状态 有很多地方可以设置定时任务,比如:Windows的计划任务,Linux下的crontab,各种开发工具里的timer组件.SQL Serv ...

  4. 让Xcode Lua 语法高亮

    本人不太喜欢用code ide 还是喜欢XCODE的风格 1.让Xcode支援Lua语法高亮(Syntax Highlighting) 1. 下载https://github.com/breinhar ...

  5. css Cursor:url()自定义鼠标指针样式为图片

    css自定义鼠标指针样式为图片Cursor:url()的使用,今天在项目中,要用到自定义鼠标样式,格式: css:{cursor:url('绝对路径的图片(格式:cur,ico)'),-moz-zoo ...

  6. 【转】android动画之Tween动画 (渐变、缩放、位移、旋转)

    原文:http://blog.csdn.net/feng88724/article/details/6318430 Android 平台提供了两类动画. 一类是Tween动画,就是对场景里的对象不断的 ...

  7. RPC服务的发布订阅实现Thrift

    Thrift 个人实战--RPC服务的发布订阅实现(基于Zookeeper服务) 前言: Thrift作为Facebook开源的RPC框架, 通过IDL中间语言, 并借助代码生成引擎生成各种主流语言的 ...

  8. SpringMVC源码

    SpringMVC源码分析系列 说到java的mvc框架,struts2和springmvc想必大家都知道,struts2的设计基本上完全脱离了Servlet容器,而springmvc是依托着Serv ...

  9. JS定时跳转URL并输出剩余秒数

    1. [代码][JavaScript]代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <scrip ...

  10. C#程序的157个建议

    编写高质量代码改善C#程序的157个建议——导航开篇   前言 由于最近工作重心的转移,原来和几个同事一起开发的项目也已经上线了,而新项目就是在现有的项目基础上进行优化延伸扩展.打个比方,现在已经上线 ...