资讯专栏INFORMATION COLUMN

细说 Javascript 函数篇(四) : arguments 对象

aristark / 1541人阅读

因为最近有博友反馈我的博文是直接翻译的参考链接内的内容,所以我在这里要说明一下,以免引起不必要的误会。
首先,我很喜欢 segmentfault 的交流和学习的氛围,所以我很愿意在这里跟各位 SFer 交流学习心得,相互学习,共同进步。
第二,我做技术方面的工作不久,所以学习经历也不是很长,但是我发现写博客,总结自己的学习心得是个很好的学习习惯,至少对于我个人而言,我于此收益颇丰,所以我决定坚持一天至少写一篇博客,以督促自己天天学习,吸取知识。
第三,由于我个人能力有限,除了有几篇知识性的总结博文外,其余的博文都是直接翻译的国外教程,在中间间接性地插入自己的一些想法和笔记,其主要目的是为了方便自己回顾记忆。之所以把博文的名字命名为《细说 Javascript xxx 篇》这种格式,是鉴于 segmentfault 暂时还没有个人标签的功能,这样比较适合我个人进行归纳分类。
第四,我每篇博文后面都附有参考链接,由于我个人能力有限,所以有些地方可能自己理解或翻译的不恰当,那么博友们可以点击参考链接直接看原文的内容。
最后,我想说的是,我之所以在 segmentfault 写博客,主要目的就是为了能与大家多多交流,彼此相互学习,我相信大家来 segmentfault 的目的大体都是这样的,所以我希望在 segmentfault 这个优秀的平台获得知识取得进步的同时,也能为 segmentfault 贡献自己的一份力量。

言归真正,接下来我们讨论 Javascriptarguments 对象。
每一个 Javascript 函数都能在自己作用域内访问一个特殊的变量 - arguments。这个变量含有一个传递给函数的所有参数的列表。
arguments 对象不是一个数组。尽管在语法上它跟数组有相同的地方,例如它拥有 length 属性。但它并不是从 Array.prototype 继承而来,实际上,它就是一个对象。
因此,我们不能直接对 arguments 使用一些数组的方法,例如 push, popslice 等。 所以为了使用这些方法,我们就需要将其转换为一个真正的数组。

转化为数组

下面的代码将会返回一个包含 arguments 对象所有元素的数组。

Array.prototype.slice.call(arguments);

由于转化的速度很慢,所以在性能要求严格的程序中不建议这样做。

传递参数

下面是一种比较推荐的方法,将 arguments 对象从一个函数传递到另一个函数。

function foo() {
    bar.apply(null, arguments);
}
function bar(a, b, c) {
    // do stuff here
}

另外还有一个比较巧妙的方法,就是同时使用 callapply 快速创建一个解绑的外层方法。

function Foo() {}

Foo.prototype.method = function(a, b, c) {
    console.log(this, a, b, c);
};

// Create an unbound version of "method" 
// It takes the parameters: this, arg1, arg2...argN
Foo.method = function() {

    // Result: Foo.prototype.method.call(this, arg1, arg2... argN)
    Function.call.apply(Foo.prototype.method, arguments);
};
函数形参和 arguments 属性的关系

arguments 对象为它自身属性和函数的形参都创建了 gettersetter 方法。
因此,修改函数的形参会影响对应的 arguments 对象的属性值,反之亦然。

function foo(a, b, c) {
    arguments[0] = 2;
    a; // 2

    b = 4;
    arguments[1]; // 4

    var d = c;
    d = 9;
    c; // 3
}
foo(1, 2, 3);
性能问题

arguments 只在两种情况下不会被创建,一是在函数内部被声明为局部变量,二是当做函数的形参。其他情况,arguments 对象总是会被创建。
由于 gettersetter 方法总是会随着 arguments 对象的创建而创建,因此使用 arguments 对性能本身几乎没有影响。
然而,有一种情形会严重影响 Javascript 的性能,那就是使用 arguments.callee

function foo() {
    arguments.callee; // do something with this function object
    arguments.callee.caller; // and the calling function object
}

function bigLoop() {
    for(var i = 0; i < 100000; i++) {
        foo(); // Would normally be inlined...
    }
}

在上述代码中,foo 函数不再是一个简单的内联扩展,因为它需要知道它自身以及它的调用者(caller)。这不仅抵消了内联扩展所带来的性能提升,同时也破坏了函数的封装性,因为函数本身可能需要依赖于一个特定的调用背景。
因此,建议大家尽量不要使用 arguments.callee

参考

http://bonsaiden.github.io/JavaScript-Garden/#function.arguments

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/87514.html

相关文章

  • 细说 Javascript 类型(二) : typeof 操作符

    摘要:操作符还有可能是设计中最大缺陷,因为它几乎是完全破损的。由于用法与调用函数的语法相似,因此常被误以为是函数调用,实际上并不存在名为的函数,只是一个操作符而已。而列则表示对象内部的属性。属性文档中明确地给出了获得属性的途径,就是使用。 typeof 操作符(还有 instanceof)可能是 Javascript 设计中最大缺陷,因为它几乎是完全破损的。由于 typeof 用法与调用函数...

    PAMPANG 评论0 收藏0
  • 细说 Javascript 类型) : 类型转换

    摘要:因为是弱类型语言,所以它会在任何可能的情形下对变量进行强制类型转换。内置类型的构造函数调用内置类型的构造函数时,是否使用关键字将表现得大不相同。传递字面值或非对象值也会造成强制类型转换的现象。最好的方法就是显示地将值转换为,或三种类型之一。 因为 Javascript 是弱类型语言,所以它会在任何可能的情形下对变量进行强制类型转换。 // These are true new Num...

    chengtao1633 评论0 收藏0
  • 浅谈细说 JS 函数(call,apply,重载)

    摘要:什么是函数引用的原话函数是一组可以随时随地运行的语句。函数是由这样的方式进行声明的关键字函数名一组参数,以及置于括号中的待执行代码。 什么是函数? 引用 W3School 的原话: 函数是一组可以随时随地运行的语句。 函数是 ECMAScript 的核心。 函数是由这样的方式进行声明的:关键字 function、函数名、一组参数,以及置于括号中的待执行代码。 函数的基本语法是这样的:...

    U2FsdGVkX1x 评论0 收藏0
  • 细说 Javascript 对象) : for in 循环

    摘要:第二是,由于会遍历整个原型链,所以当原型链过长时,会对性能造成影响。总结建议养成过滤属性的好习惯,不要对运行环境做任何假设,也无论原生的原型对象是否被扩展。 如同 in 运算符一样,使用 for in 循环遍历对象属性时,也将往上遍历整个原型链。 // Poisoning Object.prototype Object.prototype.bar = 1; var foo = {m...

    Kross 评论0 收藏0
  • 细说 Javascript 对象(二) : 原型对象

    摘要:并没有类继承模型,而是使用原型对象进行原型式继承。我们举例说明原型链查找机制当访问一个对象的属性时,会从对象本身开始往上遍历整个原型链,直到找到对应属性为止。原始类型有以下五种型。此外,试图查找一个不存在属性时将会遍历整个原型链。 Javascript 并没有类继承模型,而是使用原型对象 prototype 进行原型式继承。 尽管人们经常将此看做是 Javascript 的一个缺点,然...

    lansheng228 评论0 收藏0

发表评论

0条评论

aristark

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<