JavaScript中的apply和call函数详解


Posted in Javascript onJuly 20, 2014

第一次翻译技术文章,见笑了!

翻译原文:

Function.apply and Function.call in JavaScript

第一段略。

每个JavaScript函数都会有很多附属的(attached)方法,包括toString()、call()以及apply()。听起来,你是否会感到奇怪,一个函数可能会有属于它自己的方法,但是记住,JavaScript中的每个函数都是一个对象。看一下 这篇文章 ,复习一下(refresher)JavaScript特性。你可能还想知道JavaScript中函数和方法的区别。我认为“函数”和“方法”的描述,仅仅是JavaScript的习惯约定而已。函数立足于它们自己(例如:alert()),而方法是函数内部一个对象的属性(dictionary),我们通过对象来调用方法。每个JavaScript对象都有一个toString()方法,下面通过代码举例说明,在一个函数对象中,我们可以使用toString()方法。

function foo(){
 alert('x');
}
alert(foo.toString());

因为函数都是对象,它们有自己的属性和方法。我们可以把它们看作数据(data)。这篇文章,我们只关注两个函数的方法apply()以及call()。

我们从下面的代码开始:

var x = 10;
function f(){
 alert(this.x);
}
f();

我们定义了一个全局函数f()。f()通过this关键字访问变量x,但是需要注意的是,我们不能通过一个对象的实例来调用这个函数。this指向的是什么对象呢?this会指向这个全局对象。我们的变量x就是在这个全局对象中定义的。上面的代码能够正常运行,运行结果会显示一个对话框,对话框中显示10。

我们可以通过this来调用call()和apply()。正如下面的例子展示如何使用call():

var x = 10;
var o = { x : 15};
function f(){
 alert(this.x);
}
f();
f.call(o);

首先调用f()将会显示10的对话框,因为this这个时候指向的是全局对象。然后我们调用f函数的call()方法,传入的参数是o,运行结果显示的是o中x属性的值15。call()方法会用它的第一个参数作为f函数的this指针。也就是说,我们会告诉运行时,f函数中的this指向的是哪个对象。

this跳转听起来有些滑稽,甚至对于C++、Java以及C#程序员来说有些反常。这些都是ECMAScript中有趣的部分。

通过call()也可以给函数传递参数:

var x = 10;
var o = { x : 15};
function f(){
 alert(this.x);
}
f();
f.call(o);

apply()和call()类似的,只是apply()要求第二个参数必须是一个数组。这个数组会作为参数传递给目标函数。

var x = 10;
var o = {x : 15};
function f(message) {
 alert(message);
 alert(this.x);
}
f('invoking f');
f.apply(o, ['invoking f through apply']);

apply()方法是很有用的,因为我们可以创建一个函数而不用去关心目标方法的参数。这个函数可以通过apply()的第二个数组参数来传递额外的参数给方法。

var o = {x : 15};
function f1(message1) {
 alert(message1 + this.x);
}
function f2(message1, message2) {
 alert(message1 + (this.x * this.x) + message2);
}
function g(object, func, args) {
 func.apply(object, args);
}
g(o, f1, ['the value of x = ']);
g(o, f2, ['the value of x squared = ', '. Wow!']);

这样的语法有点问题。为了调用apply()方法,我们强制目标函数使用数组中的参数。幸运的是,有一个方法可以让这种语法更简单。在此之前,我们必须先介绍一个:参数标识符。

在JavaScript中,其实每个函数都有一个可变长度的参数列表。这意味着,即使一个函数只有一个参数的时候,我们也可以传递5个参数给它。下面的代码不会有错误,而且结果显示的是“H”。

function f(message) {
 alert(message);
}
f('H', 'e', 'l', 'l', 'o');

在f()中,如果我们不想去接受其他的参数,我们可以用关键字arguments。arguments代表一个参数对象,它有一个代表长度的属性类似于数组。

function f(message) {
 // message的值和arguments[0]是一样的
 for(var i = 1; i < arguments.length; i++){
  message += arguments[i];
 }
 alert(message);
}
// 结果显示“Hello”
f('H', 'e', 'l', 'l', 'o');

你应该知道,严格来讲,arguments不是一个数组。arguments有一个length属性,但是没有split、push、pop方法。在前面的g()函数中,我们可以从arguments中拷贝需要的参数,组成数组,然后把这个数组传递给apply()。

var o = {x : 15};
function f(message1, message2) {
 alert(message1 + ( this.x * this.x) + message2);
}
function g(object, func) {
 // arguments[0] = object
 // arguments[1] = func
 var args = [];
 for(var i = 2; i < arguments.length; i++) {
  args.push(arguments[i]);
 }
 func.apply(object, args);
}
g(o, f, 'The value of x squared = ', '. Wow!');

当我们调用g(),we can pass additional arguments as parameters instead of stuffing the arguments into an array。

Javascript 相关文章推荐
JavaScript获取/更改文本框的值的实例代码
Aug 02 Javascript
jQuery中:contains选择器用法实例
Dec 30 Javascript
jQuery中wrapAll()方法用法实例
Jan 16 Javascript
基于Node.js的强大爬虫 能直接发布抓取的文章哦
Jan 10 Javascript
Bootstrap入门书籍之(零)Bootstrap简介
Feb 17 Javascript
Bootstrap创建可折叠的组件
Feb 23 Javascript
Node.js websocket使用socket.io库实现实时聊天室
Feb 20 Javascript
详解angularJS自定义指令间的相互交互
Jul 05 Javascript
Vue-Router2.X多种路由实现方式总结
Feb 09 Javascript
使用elementUI实现将图片上传到本地的示例
Sep 04 Javascript
微信小程序学习笔记之获取位置信息操作图文详解
Mar 29 Javascript
小程序根据手机机型设置自定义底部导航距离
Jun 04 Javascript
一行命令搞定node.js 版本升级
Jul 20 #Javascript
JavaScript中的原型和继承详解(图文)
Jul 18 #Javascript
JavaScript中伪协议 javascript:使用探讨
Jul 18 #Javascript
js清空表单数据的两种方式(遍历+reset)
Jul 18 #Javascript
js使用正则实现ReplaceAll全部替换的方法
Jul 18 #Javascript
javascript原生和jquery库实现iframe自适应高度和宽度
Jul 18 #Javascript
关于javaScript注册click事件传递参数的不成功问题
Jul 18 #Javascript
You might like
PHP中header和session_start前不能有输出原因分析
2013/01/11 PHP
destoon网站转移服务器后搜索汉字出现乱码的解决方法
2014/06/21 PHP
jquery tools 系列 scrollable(2)
2009/09/06 Javascript
js实现双向链表互联网机顶盒实战应用实现
2011/10/28 Javascript
你必须知道的JavaScript 中字符串连接的性能的一些问题
2013/05/07 Javascript
深入探寻seajs的模块化与加载方式
2015/04/14 Javascript
JavaSciprt中处理字符串之sup()方法的使用教程
2015/06/08 Javascript
js实现超简单的展开、折叠目录代码
2015/08/28 Javascript
jquery彩色投票进度条简单实例演示
2020/07/23 Javascript
javascript仿百度输入框提示自动下拉补全
2016/01/07 Javascript
knockoutjs动态加载外部的file作为component中的template数据源的实现方法
2016/09/01 Javascript
概述VUE2.0不可忽视的很多变化
2016/09/25 Javascript
微信小程序开发教程-手势解锁实例
2017/01/06 Javascript
整理关于Bootstrap排版的慕课笔记
2017/03/29 Javascript
Easyui在treegrid添加控件的实现方法
2017/06/23 Javascript
Vue 莹石摄像头直播视频实例代码
2018/08/31 Javascript
JS获取今天是本月第几周、本月共几周、本月有多少天、是今年的第几周、是今年的第几天的示例代码
2018/12/05 Javascript
微信小程序遍历Echarts图表实现多个饼图
2019/04/25 Javascript
[03:38]2014DOTA2西雅图国际邀请赛 VG战队巡礼
2014/07/07 DOTA
[59:32]Liquid vs Fnatic 2019国际邀请赛淘汰赛败者组BO1 8.20.mp4
2020/07/19 DOTA
Python中操作文件之write()方法的使用教程
2015/05/25 Python
Python Unittest自动化单元测试框架详解
2018/04/04 Python
python实现一个简单的udp通信的示例代码
2019/02/01 Python
详解Django定时任务模块设计与实践
2019/07/24 Python
Python面向对象之私有属性和私有方法应用案例分析
2019/12/31 Python
基于python SMTP实现自动发送邮件教程解析
2020/06/02 Python
django restframework serializer 增加自定义字段操作
2020/07/15 Python
python自动提取文本中的时间(包含中文日期)
2020/08/31 Python
pycharm + django跨域无提示的解决方法
2020/12/06 Python
关于打架的检讨书
2014/01/17 职场文书
婚纱摄影师求职信范文
2014/04/17 职场文书
工作总结与自我评价
2014/09/18 职场文书
2015年学校后勤工作总结
2015/04/08 职场文书
总经理年会致辞
2015/07/29 职场文书
2016党员学习心得体会范文
2016/01/23 职场文书
原生JavaScript实现简单五子棋游戏
2021/06/28 Javascript