zoukankan      html  css  js  c++  java
  • 你不知道的JavaScript--Item11 arguments对象

    1、什么是arguments

    arguments 是是JavaScript里的一个内置对象,它很古怪,也经常被人所忽视,但实际上是很重要的。所有主要的js函数库都利用了arguments对象。所以agruments对象对于javascript程序员来说是必需熟悉的。在javascript函数体内,标识符arguments具有特殊含义。它是调用对象的一个特殊属性,用来引用Arguments对象。Arugments对象就数组,注意这里只是像并不是哈。

    javascript函数体内,arguments像数组(并不是真的数组,是一个Arguments对象,再次强调)一样,有length属性,可以代表传给函数的参数的个数。

    javascript中Arguments对象是函数的实际参数,arguments对象的长度是由实参个数而不是形参个数决定的。形参是函数内部重新开辟内存空间存储的变量,但是其与arguments对象内存空间并不重叠。

    js不会主动为你判断你到底给函数传了多少个参数,如果你多传了,多余的部分就没有被使用,如果你少传了,那么没传的参数值就是undefined.所以我们可以借助arguments的length属性来检测调用函数时是否使用了正确数目的实际参数,因为javascript是不会为你做这些事的

    function f(x,y,z)
    {
        //首先检查传递的参数数量是否正确
        if(arguments.length != 3)
        {
            throw new Error("function f called with " + arguments.length + "arguments");
        }
        //下面运行真正的函数
    }

    2、arguments创建可变参数列表函数

    arguments还为我们提供了这样一种可能,就是为一个函数传任意数目的实际参数:

    比如说,我想用一个display()函数来计算每个公司的员工工资总额,对,没错,你传多少参数都行,但是前提是你要传数字,因为我在函数内部懒得判断了。呵。

     function display(){
            var sum=0;  //总额
            for(var i=0;i<arguments.length;i++){
                sum+=arguments[i];
            }
            document.write(sum+'<br>');
        }
    
        //A公司
        display(10000,2000,5000);
        //B公司
        display(1000,2000,5000,8000,10000);

    怎么样?这个方法很巧妙吧?呵呵。

    说明一下arguments与真正传的形式参数是一致的:

    对于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_

    14、你不知道的JavaScript–Item14 使用prototype的几点注意事项

    15、你不知道的JavaScript–Item15 prototype原型和原型链详解

    16、你不知道的JavaScript–Item16 for 循环和for…in 循环的那点事儿

    17、你不知道的JavaScript–Item17 循环与prototype最后的几点小tips

    18、你不知道的JavaScript–Item18 JScript的Bug与内存管理

    19、你不知道的JavaScript–Item19 执行上下文(execution context)

    20、你不知道的JavaScript–Item20 作用域与作用域链(scope chain)

    21、你不知道的JavaScript–Item21 漂移的this


    持续更新中……………….

    版权声明:本文为小平果原创文章,转载请注明:http://blog.csdn.net/i10630226

  • 相关阅读:
    fiddler抓取java系程序的网络通信
    ZOJ 2724 Windows Message Queue(优先队列)
    FZU 电动车通行证制度
    Havel定理
    Catch That Cow
    Trie树
    zoj 2876 Phone List
    zoj 2420
    getchar
    zoj 1315 Excuses, Excuses!
  • 原文地址:https://www.cnblogs.com/dingxiaoyue/p/4948214.html
Copyright © 2011-2022 走看看