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

因为近来有博友反应我的博文是直接翻译的参考链接内的内容,所以我在这里要申明一下,以避免引发不必要的误解。
起首,我很喜欢 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

    原文作者:StephenLee
    原文地址: https://segmentfault.com/a/1190000000486306
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞