函数的内部属性-读书笔记

函数内部,有两个特殊的对象:arguments和this。

一、arguments

arguments的作用是保存传入函数中的所有参数,而且这个arguments有一个名叫callee的属性,这个属性是一个指针,指向拥有arguments对象的函数。

举个递归算法---阶乘函数的例子:

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

上面的代码,在函数有名字,而且名字以后也不会变的情况下,这样定义没有啥问题。不过,这样这个函数的执行与函数名紧紧耦合在一起了。所以为了消除这种紧密耦合,我们可以使用arguments.callee。

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

这样,无论引用函数时使用什么名字,都可以保证正常完成递归调用。举个例子:

var trueFactorial = factorial;
factorial = function(){
  return 0;  
}
console.log(trueFactorial(5));      //120
console.log(factorial(5));          //0

变量trueFactorial获得了factorial的值,实际上是在另一个位置上保存了一个函数的指针。然后我们又把一个返回0的函数赋值给factorial变量。如果像原来的factorial()不使用arguments.callee,那么调用trueFactorial()就会返回0。但是,在解除了耦合之后,trueFactorial()依然能够正常的计算阶乘。而再次被赋值的factorial(),只能按照重新赋给的值进行计算。

严格模式下,不能通过脚本访问arguments.callee,可以使用命名函数表达式来达成相同的结果,栗如:

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

以上代码创建了一个名为f()的命名函数表达式,然后将它赋值给变量factorial。即便把函数赋值给了另一个变量,函数的名字f依然有效。这种方式在严格模式和非严格模式下都行得通。

二、this

this引用的是函数执行的环境对象,当在网页的全局作用域中调用函数时,this对象引用的就是window。

window.color = "red";
var o = { color: "blue"};
function sayColor(){
  console.log(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()指向的仍然是同一个函数。

 

参考资料

《javascript高级程序设计(第3版)》第5章 引用类型

 

posted @ 2017-04-13 10:01  winteronlyme  阅读(425)  评论(0编辑  收藏  举报