• 5.5.4 函数内部属性


      在函数内部,有两个特殊的对象:arguments和this。其中,arguments它是一个类数组对象,包含着传入函数中的所有参数。虽然arguments的主要用途是保存函数参数,但这个对象含所有一个名叫callee的属性,该属性是一个指针,指向拥有这个arguments对象的函数。请看下面这个非常经典的阶乘函数。

    function factorial(num)
    {
        if(num<=1)
        {
            return 1;
        }else
        {
            return num*factorial(num-1);    
        }
    }
    

      定义阶乘函数一般都要用到递归算法;如上面代码所示,在函数有名字,而且名字以后也不会变的情况下,这样定义没有问题,但问题是这个函数的执行与函数名factorial紧紧耦合在了一起,为了消除这种紧紧耦合情况,可以像下面使用arguments.callee。

    function factorial(num)
    {
        if(num<=1)
        {
            return 1;    
        }else
        {
            return num*arguments.callee(num-1);
        }
    }
    

      在这个重写后的factorial()函数的函数体内,没有再引用函数名factorial。这样,无论引用函数时使用的是什么名字,都可以保证正常完成递归调用。例如:

    var trueFactorial=factorial;
    factorial=function()
    {
        return 0;
    };
    
    alert(trueFactorial(5));//120
    alert(factorial(5));//0
    

      在此,变量trueFactorial获得了factorial的值,实际上是另一个位置上保存了一个函数的指针。然后,我们又将一个简单的返回了0的函数赋值给了factorial变量。如果像原来factorial()那样不用使用arguments.callee,调用trueFactorial()就会返回0。可是,在解除了函数体内的代码与函数名的耦合状态之后,trueFactorial()仍然能够正常的计算阶乘;至于factorial(),它现在只是一个返回0的函数。

      函数内部的另一个特殊对象是this,其行为与java和c#中的this大致类似。换句话说,this引用的是函数据以执行的环境对象,或则也可以说是this值(当在网页的全局作用中调用函数时,this对象引用的就是window)。如下例子:

    window.color="red";
    var o={color:"blue"};
    
    function sayColor()
    {
        alert(this.color);
    }
    sayColor();//red
    
    o.sayColor=sayColor;
    o.sayColor();//blue
    

      上面这个函数sayColor()是在全局作用域中定义的,它引用了this对象。由于在调用函数之前,this的值并不明确,因此this可能会在代码执行过程中引用不同的对象。当在全局作用域中调用sayColor()时,this引用的是全局对象window;换句话讲,对this.color求值会转换成对window.color求值,于是结果就返回了“red”。而当把这个函数赋给对象o并调用o.sayColor()时,this引用的对象o,因此对this.color求值会转换成对o.color求值,结果就返回了“blue”。

      注:请牢记,函数的名字仅仅是一个包含指针的变量而已。因此,即使是在不同的环境中执行,全局的sayColor()函数与o.sayColor()指向的仍然是同一个函数。

      ECMAScript 5 也规范了另一个函数对象的属性:caller。除了Opera的早期版本不支持,其他浏览器都支持这个ECMAScript 3 并没有定义的属性。这个属性中保存着调用当前函数的函数的引用,如果是在前全局作用域中调用当前函数,它的值是null。例如:

    function outer()
    {
        inner();
    }
    
    function inner()
    {
        alert(inner.caller);
    }
    
    outer();
    

      以上代码会导致警告框中显示outer()函数的源代码。因为outer()调用了inner(),所以inner.caller就指向outer(),为了实现更松散的耦合,也可以通过arguments.callee.caller来访问相同的信息。

    function outer()
    {
        inner();
    }
    
    function inner()
    {
        alert(arguments.callee.caller);
    }
    
    outer();
    

      IE、FF、Chrome和Safari的所有版本以及Opera9.6都支持caller属性。

      当函数在严格模式下运行时,访问arguments.callee会导致错误。ECMAScript 5还定义了arguments.caller属性,但在严格模式下访问也会导致错误,而在非严格模式下这个属性始终是undefined。定义这个属性是为了分清arguments.caller和函数的caller属性。以上变化都是为了嘉庆这门语言的安全性,这样第三方代码就不能在相同的环境里窥视其他代码了。

      严格模式还有一种限制:不能为函数caller函数赋值,否则会导致错误。

  • 相关阅读:
    Failed to auto-configure a DataSource: 'spring.datasource.url' is not specified and no embedded datasource could be auto-configured.
    Spring NoSuchBeanDefinitionException六大原因总结
    深入分析Spring 与 Spring MVC容器
    MyBatis mapper parameterType
    eclipse下的mybatis插件:MyBatipse
    javax.servlet-api 和 servlet-api 区别
    Spring中ClassPathXmlApplication与FileSystemXmlApplicationContext的区别
    dump总结
    操作系统基础知识
    JMM中的Happens-Before原则
  • 原文地址:https://www.cnblogs.com/yxlove/p/4508689.html
Copyright © 2020-2023  润新知