javascript奇异的arguments分析


Posted in Javascript onOctober 20, 2010

在每个函数中,都有个名为 arguments 的变量,它以类似数组的形式保存了当前调用的参数。而它实际上并不是个数组,使用 typeof arguments 语句尝试会返回“object”(对象),所以它不能像 Array 一样使用 push 和 pop 等方法。即便如此,仍然可以使用下标以及长度属性(length)获取它的值。

编写灵活的函数
虽看起来名不经传,但的确 arguments 是非常有用的对象。比如,你可以让函数处理不定数目的参数。在 Dean Edwards 写的 base2 库中,有个叫 format 的函数充分发挥了这一特性:

function format(string) { 
var args = arguments; 
var pattern = new RegExp("%([1-" + arguments.length + "])", "g"); 
return String(string).replace(pattern, function(match, index) { 
return args[index]; 
}); 
};

这个函数实现了模板替换,你可以在要动态替换的地方使用 %1 到 %9 标记,然后其余的参数就会依次替换这些地方。例如:

format("And the %1 want to know whose %2 you %3", "papers", "shirt", "wear");上面的脚本就会返回

"And the papers want to know whose shirt you wear" 。在这里需要注意的是,即便在 format 函数定义中,我们仅定义了个名为 string 的参数。而 Javascript 不管函数自身定义的参数数量,它都允许我们向一个函数传递任意数量的参数,并将这些参数值保存到被调用函数的 arguments 对象中。

转换成实际数组
虽然 arguments 对象并不是真正意义上的 Javascript 数组,但是我们可以使用数组的 slice 方法将其转换成数组,类似下面的代码

var args = Array.prototype.slice.call(arguments);

这样,数组变量 args 包含了所有 arguments 对象包含的值。

创建预置参数的函数
使用 arguments 对象能够简短我们编写的 Javascript 代码量。下面有个名为 makeFunc 的函数,它根据你提供的函数名称以及其他任意数目的参数,然后返回个匿名函数。此匿名函数被调用时,合并的原先被调用的参数,并交给指定的函数运行然后返回其返回值。

function makeFunc() { 
var args = Array.prototype.slice.call(arguments); 
var func = args.shift(); 
return function() { 
return func.apply(null, args.concat(Array.prototype.slice.call(arguments))); 
}; 
}

makeFunc 的第一个参数指定需要调用的函数名称(是的,在这个简单的例子中没有错误检查),获取以后从 args 中删除。makeFunc 返回一个匿名函数,它使用函数对象的(Function Object)apply 方法调用指定的函数。

apply 方法的第一个参数指定了作用域,基本上的作用域是被调用的函数。不过这样在这个例子中看起来会有点复杂,所以我们将其设定成 null ;其第二个参数是个数组,它指定了其调用函数的参数。makeFunc 转换其自身的 arguments 并连接匿名函数的 arguments,然后传递到被调用的函数。

有种情况就是总是要有个输出的模板是相同的,为了节省每次是使用上面提到的 format 函数并指定重复的参数,我们可以使用 makeFunc 这个工具。它将返回一个匿名函数,并自动生成已经指定模板后的内容:

var majorTom = makeFunc(format, "This is Major Tom to ground control. I'm %1.");

你可以像这样重复指定 majorTom 函数:
majorTom("stepping through the door"); 
majorTom("floating in a most peculiar way");

那么当每次调用 majorTom 函数时,它都会使用第一个指定的参数填写已经指定的模板。例如上述的代码返回:
"This is Major Tom to ground control. I'm stepping through the door." 
"This is Major Tom to ground control. I'm floating in a most peculiar way."

自引用的函数
您可能会认为这很酷,先别急着高兴,后面还有个更大的惊喜。它(arguments)还有个其他非常有用的属性:callee 。arguments.callee 包含了当前调用函数的被引用对象。那么我们如何使用这玩意做些的事情?arguments.callee 是个非常有用的调用自身的匿名函数。

下面有个名为 repeat 的函数,它的参数需要个函数引用和两个数字。第一个数字表示运行的次数,而第二个函数定义运行的间隔时间(毫秒为单位)。下面是相关的代码:

function repeat(fn, times, delay) { 
return function() { 
if(times-- > 0) { 
fn.apply(null, arguments); 
var args = Array.prototype.slice.call(arguments); 
var self = arguments.callee; 
setTimeout(function(){self.apply(null,args)}, delay); 
} 
}; 
}

repeat 函数使用 arguments.callee 获得当前引用,保存到 self 变量后,返回个匿名函数重新运行原本被调用的函数。最后使用 setTimeout 以及配合个匿名函数实现延迟执行。

作为个简单的说明,比如会在通常的脚本中,编写下面的提供个字符串并弹出个警告框的简单函数:

function comms(s) { 
alert(s); 
}

好了,后来我改变了我的想法。我想编写个“特殊版本”的函数,它会重复三次运行每次间隔两秒。那么使用我的 repeat 函数,就可以像这样做到:
var somethingWrong = repeat(comms, 3, 2000); 
somethingWrong("Can you hear me, major tom?");

结果就犹如预期的那样,弹出了三次警告框每次延时两秒。

最后,arguments 即便不会经常被用到,甚至显得有些诡异,但是它上述的那些惊艳的功能(不仅仅是这些!)值得你去了解它。

Javascript 相关文章推荐
JS 对输入框进行限制(常用的都有)
Jul 30 Javascript
js 设置缓存及获取设置的缓存
May 08 Javascript
jQuery获得document和window对象宽度和高度的方法
Mar 25 Javascript
JavaScript学习小结(一)——JavaScript入门基础
Sep 02 Javascript
浅谈JS函数定义方式的区别
Oct 30 Javascript
node安装--linux下的快速安装教程
Mar 21 Javascript
详解Vue学习笔记入门篇之组件的内容分发(slot)
Jul 17 Javascript
vue单页缓存存在的问题及解决方案(小结)
Sep 25 Javascript
浅谈layer的Icon样式以及一些常用的layer窗口使用方法
Sep 11 Javascript
ES2020 新特性(种草)
Jan 12 Javascript
微信小程序连续签到7天积分获得功能的示例代码
Aug 20 Javascript
JS继承实现方法及优缺点详解
Sep 02 Javascript
超越Jquery_01_isPlainObject分析与重构
Oct 20 #Javascript
理解Javascript_15_作用域分配与变量访问规则,再送个闭包
Oct 20 #Javascript
理解Javascript_14_函数形式参数与arguments
Oct 20 #Javascript
理解Javascript_13_执行模型详解
Oct 20 #Javascript
用jquery与css打造个性化的单选框和复选框
Oct 20 #Javascript
Jquery插件之多图片异步上传
Oct 20 #Javascript
jquery判断checkbox(复选框)是否被选中的代码
Oct 20 #Javascript
You might like
php快速url重写更新版[需php 5.30以上]
2010/04/25 PHP
PHP mysql与mysqli事务使用说明 分享
2013/08/17 PHP
简单的php文件上传(实例)
2013/10/27 PHP
php实现给图片加灰色半透明效果的方法
2014/10/20 PHP
简单了解WordPress开发中update_option()函数的用法
2016/01/11 PHP
Laravel利用gulp如何构建前端资源详解
2018/06/03 PHP
PHP中检查isset()和!empty()函数的必要性
2019/02/13 PHP
使用自定义setTimeout和setInterval使之可以传递参数和对象参数
2009/04/24 Javascript
jquery 插件开发方法小结
2009/10/23 Javascript
JavaScript window.setTimeout() 的详细用法
2009/11/04 Javascript
jQuery 美元符冲突的解决方法
2010/03/28 Javascript
javascript权威指南 学习笔记之javascript数据类型
2011/09/24 Javascript
javascript中call和apply方法浅谈
2013/09/27 Javascript
基于JavaScript实现TAB标签效果
2016/01/12 Javascript
js实现简单排列组合的方法
2016/01/27 Javascript
jQuery基础知识点总结(DOM操作)
2016/06/01 Javascript
一个简单的JavaScript Map实例(分享)
2016/08/03 Javascript
Extjs让combobox写起来简洁又漂亮
2017/01/05 Javascript
详谈jQuery unbind 删除绑定事件 / 移除标签方法
2017/03/02 Javascript
angular学习之ngRoute路由机制
2017/04/12 Javascript
vue如何引用其他组件(css和js)
2017/04/13 Javascript
Angularjs中使用轮播图指令swiper
2017/05/30 Javascript
Javascript Dom元素获取和添加详解
2019/09/24 Javascript
Python中的pass语句使用方法讲解
2015/05/14 Python
Python实现简单登录验证
2016/04/13 Python
Python版名片管理系统
2018/11/30 Python
iPython pylab模式启动方式
2020/04/24 Python
工程业务员工作职责
2013/12/07 职场文书
新学期家长寄语
2014/01/19 职场文书
2014年师德师风学习材料
2014/05/16 职场文书
企业读书活动总结
2014/06/30 职场文书
街道社区活动报告
2015/02/05 职场文书
技术员岗位职责范本
2015/04/11 职场文书
员工表扬信怎么写
2015/05/05 职场文书
2016党校学习心得体会范文
2016/01/07 职场文书
Golang jwt身份认证
2022/04/20 Golang