日期:2014-05-16  浏览次数:20341 次

JavaScript 深入理解函数--Function

??? 如果要问JavaScript里面什么最有趣,当属函数了。因为每个函数都是Function类型的实例。

??? JS中Function类型的构造函数,可以接受任意数量的参数,但最后一个参数始终都被看成是函数体。例如下面的定义方式在JS语法里完全合理:???

???

var sum=new Function("num1","num2","return num1+num2");
alert(sum(1,2));//输出3

?但是这种方式除了可以用来理解函数也是对象,函数名是指针之外,就一无是处了。因为这种方法将导致解析ECMAScript两次代码。第一次是常规的解析,第二次是解析函数体内容。所以这种方式并不推荐,忘掉这种方式吧

?? 下面两种方式都是可以的,第一种方式大家都很熟悉:

????

function sum(num1,num2){
   return num1+num2;
}

?

? 第二种方式,姑且可以理解为函数字面量定义法吧,哈哈~

??

var sum=function(num1,num2){
   return num1+num2;
}
//这里声明了一个函数对象,并让指针sum(准确的说是引用对象)指向了这个函数对象

?

理解了“函数是对象,函数名是指针”之后,就不难理解为什么JS里函数没有重载的原因了。请看:

???

function sum(num1){
   return num1+10;
}
function sum(num2){
   return num2+50;
}
alert(sum(10));//输出60

?

这段代码事实上与下面这段代码并没有什么区别:

??

var sum=function(num1){
    return num1+10;
}
sum=function(num2){
    return num2+50;
}
alert(sum(10));

?

?? 通过这段代码大家就可以发现,sum这个引用对象重新指向了新的函数对象,所以就造成了函数没有重载的原因。事实上这个原理也同样可以用来解释为什么Python里也没有函数重载的原因。

?

?? 这里有必要阐述下函数声明与函数表达式声明之间的区别。JS解释器在解析JS代码的时候,首先会读取函数声明,并使其在执行任何代码之前可以访问;至于函数表达式,则必须等到解析器执行到它所在的代码中,才会真正的被执行。

?? 例如:

??

alert(sum(10));//没有问题,可以正确的输出20
function sum(num){
   return num+10;
}

alert(sum(10));//解析错误,报unexpeced identifier(意外标识符错误)
var sum=function(num){
   return num+10;
}

?

?

?? JS的具体解释法则我不是很清楚,不过按照Python的解释法则,貌似可以稍微理解下。

?? 在Python中,解释器首先会解释加载所有顶级无缩进的代码(按照先后顺序),由于在Python中没有var sum=function(){}这样的定义函数的方法,所以在Python中不会有这种函数定义前后顺序的问题。但如果调用一个之后定义的函数,还是会有这个问题。

???? 例如:

????

foo();#解释出错,提示foo变量未定义
def foo():
    print 123;

def foo():
      boo();

def boo():
      print 123;

foo();#没有问题,可以直接输出123
#理由是python解释器在解释执行的时候,
#按照无缩进的代码先后顺序加载,这个过程
#只确保它们可以被访问

?

?? JS函数对象中,有两个特殊的内部属性,分别为arguments和this,下面分别介绍下这两个参数:

??arguments属性用来保存当前函数的参数数组,它事实上也是个对象,它还有个名叫callee的属性,这是一个指针,用来指向拥有这个arguments对象的函数对象。例如:

???在经典的阶乘函数里,Factorial函数可能如下所示:

??

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

?这个函数在大多数情况下可以工作的很好,但它有一个隐性的问题,就是它的递归函数里与函数名(实质是指针)完全耦合在一起。如果以后想让这个函数名指向其他的函数,则这个方法将完全不能工作,解耦它的方式是这样的:

???

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

?

?函数的另外一个属性就是this,它表示函数在执行的时候所处的作用域.如果函数位于全局作用域范围,那么这个时候,可以解析为window。如果函数位于某个对象的声明范围内,那么则解析为当前对象。例如:

??

var color="red";
var my={
    color:"blue"
}
function sayHello(){
    alert(this.color);
}
sayHello();//这时候把this解析为window,相当于访问window.color
my.sayHello=sayHello;
my.sayHello();//这个时候把this解析为this,相当于访问my.color

?

?