你不知道的JavaScript--Item11 arguments对象

function f(a, b, c){
    alert(arguments.length);   // result: "2"
    a = 100;
    alert(arguments[0]);       // result: "100"
    arguments[0] = "qqyumidi";
    alert(a);                  // result: "qqyumidi"
    alert(c);                  // result: "undefined"
    c = 2012;
    alert(arguments[2]);       // result: "undefined"
}

f(1, 2);

3、永远不要修改arguments对象

函数中声明的参数和arguments之间的联系很脆弱,每个声明的参数实际上只是对arguments对象中对应位置的一个引用。

值得注意的是,在ES5的strict mode中,函数声明的参数并不会引用arguments:

function strict(x) {
 "use strict";
    arguments[0] = "modified";
    return x === arguments[0];
}
function nonstrict(x) {
    arguments[0] = "modified";
    return x === arguments[0];
}
strict("unmodified"); // false
nonstrict("unmodified"); // true

正因为在strict和非strict模式下,函数声明的参数和arguments的关系不一致,所以为了避免出现问题,不去修改arguments对象才是最安全的做法。

如果确实需要修改arguments对象,那么可以首先赋值一份arguments对象:

var args = [].slice.call(arguments);

当slice方法不接受任何参数的时候,就会执行复制操作,得到的args也是一个真正的数组对象。同时,args和函数声明的参数之间也没有任何联系了,对它进行操作是安全的。

4、一个变量来保存arguments的引用

假设需要一个API用来遍历若干元素,像下面这样:

var it = values(1, 4, 1, 4, 2, 1, 3, 5, 6);  
it.next(); // 1 
it.next(); // 4 
it.next(); // 1 

相应的实现可以是:

function values() {  
    var i = 0, n = arguments.length;  
    return {  
        hasNext: function() {  
            return i < n;  
        },  
        next: function() {  
            if (i >= n) {  
                throw new Error("end of iteration");  
            }  
            return arguments[i++]; // wrong arguments 
        }  
    };  
}  

但是执行的实际情况却是:

var it = values(1, 4, 1, 4, 2, 1, 3, 5, 6);  
it.next(); // undefined 
it.next(); // undefined 
it.next(); // undefined 

原因在于:对于arguments对象的赋值是隐式完成的。在next方法内部,使用了arguments,然而此arguments和values方法开始处的arguments并不是一个对象。这里的arguments对象是函数next()的。

解决方法也很简单,就是将需要访问的arguments使用另外一个变量进行引用。然后通过闭包的性质在其嵌套的函数中进行访问就可以了,像下面这样:

function values() {  
    var i = 0, n = arguments.length, a = arguments;  
    return {  
        hasNext: function() {  
            return i < n;  
        },  
        next: function() {  
            if (i >= n) {  
                throw new Error("end of iteration");  
            }  
            return a[i++];  
        }  
    };  
}  
var it = values(1, 4, 1, 4, 2, 1, 3, 5, 6);  
it.next(); // 1 
it.next(); // 4 
it.next(); // 1 

5、arguments对象的callee属性:

arguments的callee属性是用来引用当前正在执行的函数,这对未命名的函数调用自身非常有好处。

首先用命名函数表达式实现递归的函数:

//函数直接量 指定函数名 递归函数
var result = function fact(x){
    if(x<=1) 
        return 1; 
    else 
        return x*fact(x-1);
};

那里面,我提到可以为函数直接量以函数名。这样实现递归可以很方便的调用自己。

现在用arguments的这个callee同样可以简单的实现

//用函数直接量,采用arguments.callee属性实现递归函数
var result = function(x){
    if(x<=1) return 1; 
    return x*arguments.callee(x-1);
};

在最后提醒大家一点,既然这个arguments这么厉害,那么我们就不要为变量命名为arguments了,事实上arguments是javascript的保留字之一。嗯。

最后补充一点:

区别caller

返回一个对函数的引用,该函数调用了当前函数。

  • functionName.caller
  • functionName 对象是所执行函数的名称。
    对于函数来说,caller 属性只有在函数执行时才有定义。如果函数是由顶层调用的,那么 caller 包含的就是 null 。如果在字符串上下文中使用 caller 属性,那么结果和 functionName.toString 一样,也就是说,显示的是函数的反编译文本。
代码

Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->// caller demo {
function callerDemo() {
    if (callerDemo.caller) {
        var a= callerDemo.caller.toString();
        alert(a);
    } else {
        alert("this is a top function");
    }
}
function handleCaller() {
    callerDemo();
}

handleCaller();//弹出handleCaller的定义

系列文章导航:

1、你不知道的JavaScript–Item1 严格模式

2、你不知道的JavaScript–Item2 浮点数精度

3、你不知道的JavaScript–Item3 隐式强制转换

4、你不知道的JavaScript–Item4 基本类型和基本包装类型(引用类型)

5、你不知道的JavaScript–Item5 全局变量

6、你不知道的JavaScript–Item6 var预解析与函数声明提升(hoist )

7、你不知道的JavaScript–Item7 函数和(命名)函数表达式

8、你不知道的JavaScript–Item8 函数,方法,构造函数调用

9、你不知道的JavaScript–Item9 call(),apply(),bind()与回调

10、你不知道的JavaScript–Item10 闭包(closure)

11、你不知道的JavaScript–Item11 arguments对象

12、你不知道的JavaScript–Item12 undefined 与 null

13、你不知道的JavaScript–Item13 理解 prototype, getPrototypeOf 和*_ proto_*

更多面试题

**《350页前端校招面试题精编解析大全》**内容大纲主要包括 HTML,CSS,前端基础,前端核心,前端进阶,移动端开发,计算机基础,算法与数据结构,项目,职业发展等等

ned 与 null]( )

13、你不知道的JavaScript–Item13 理解 prototype, getPrototypeOf 和*_ proto_*

更多面试题

**《350页前端校招面试题精编解析大全》**内容大纲主要包括 HTML,CSS,前端基础,前端核心,前端进阶,移动端开发,计算机基础,算法与数据结构,项目,职业发展等等

[外链图片转存中…(img-dTDSwrQD-1718854323311)]

  • 30
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值