1.3.4 函数

在很多语言中,函数(Java里面成为方法)和对象时截然不同的两种东西。函数被定义为对象的动作,或者是全局的(像在C++中的main函数一样)。但是在JavaScript中,函数和对象的界限却显得不那么明显。

 

1. 函数的定义

 

JavaScript中有很多种定义函数的方法:

 

Js代码
  1. function  hello() { alert("Hello!" ); }  
  2. var  hello1 = function () { alert("Hello!" ); };  
  3. var  hello2 = new  Function("" , "alert('Hello!');" );  
  4. hello();  
  5. hello1();  
  6. hello2();  

上面给出了三种JavaScript的函数定义语句。第一句是常见的定义,看上去和Java等语言没有太大的不同。这句是定义了一个具名函数,按照上面的例子,这里的函数定义名字为hello。第二句是将一个匿名函数定义好后赋值给一个变量,于是通过这个变量就可以引用这个匿名函数。这两句看上去效果差不多,但是它们是不一样的:第一句定义的是一个具名函数,第二句定义的是一个匿名函数——尽管你可以通过这个变量引用到这个匿名函数,但实际上它还是匿名的。它们的区别可以由下面的看出:

 

Js代码
  1. hello();  
  2. hello1(); // error   
  3. function  hello() { alert("Hello!" ); }  
  4. var  hello1 = function () { alert("Hello!" ); }; 

具名函数的作用范围是全局的:你可以在定义之前使用这个函数。但是匿名函数的定义是后向的,像C/C++一样,必须在定义之后才能使用。这就是为什么hello可以使用,但是hello1就会有错误。然后试想一下这是为什么呢?JavaScript的解释过程和HTML一样是从上到下的。所以,这里的匿名函数就相当于是一个变量的定义,因此在JavaScript解释器解释执行时并不知道这个变量的定义,因此发生错误。但是,对于函数的定义则是扫描全局。

 

第三个语句就很有意思了。它创建了一个Function类的对象。这个构造函数(姑且这么叫吧)具有两个参数,第一个是函数的参数,第二个是函数体。具体来说,下面的两个函数定义是等价的:

 

Js代码
  1. function  sayHelloTo(name) {  
  2.     alert("Hello, "  + name);  
  3. }  
  4. var  sayHelloTo1 = new  Function("name" , "alert('Hello, ' + name)" );  

这种使用Function进行定义的方式并不常见,但是这个语句显示的特性却很有趣:它意味着,你可以使用这种构造函数在运行时动态的构造函数!这是一般的语言没有的特性。

 

2. 函数的参数

 

JavaScript的函数也是相当的灵活,不仅是它的定义方式多种多样,甚至它的参数都有“奇怪”的行为。由于JavaScript是弱类型的语言,因此,它不能对你的函数参数类型做检测,甚至不能保证你传入的参数个数是否和函数定义一致。这就需要有一些特殊的检测。

 

Js代码
  1. function  sum2(a, b) {  
  2.     alert(a + b);  
  3. }  
  4. sum2(1); // NaN   
  5. sum2(1, 2); // 3   
  6. sum2(1, 3, 5); // 4   

看这个例子,仅仅接受两个参数的函数,在调用时可以有任意个参数!但是,它仅取用符合条件的个数,在这里也就是前两个参数。所以,当你传入一个参数时,JavaScript试图将两个数字加起来,结果第二个参数不存在,因此返回值是NaN。第三种情况,实参个数多于形参个数,此时 JavaScript只取前两个参数相加。

 

尽管很不正式,但是可以说,JavaScript的函数参数是不定参数,也就是说,你可以传入任意的参数值。使用JavaScript函数内置的arguments就可以遍历所有传入的参数。比如下面的代码:

 

Js代码
  1. function  sum() {  
  2.     var  total = 0;  
  3.     for (var  i = 0; i < arguments.length; i++) {  
  4.         total += arguments[i];  
  5.     }  
  6.     alert(total);  
  7. }  
  8. sum(1, 2);  
  9. sum(1, 2, 3);  

arguments的行为很像数组,但它并不是数组。可以使用typeof操作符看一下,也可以调用它的constructor属性。

 

这里有一点需要说明,arguments有个callee属性,可以调用arguments自身所在的函数。也就是说,可以通过这个属性递归调用函数自身。所以,即使是匿名函数,也可以实现递归调用。如:

 

Js代码
  1. function  sum(n) {  
  2.     if (n <= 1) {  
  3.         return  1;  
  4.     }  
  5.     return  n + arguments.callee(n - 1); // 递归调用自身   
  6. }  
  7. alert(sum(100));  

我觉得大家都会知道这个著名问题的答案的。

 

3. 函数也是对象

 

回想一下上面的第三个语句,它已经强烈暗示了,函数其实也是对象!那么,作为一个对象,函数应该具有对象的一切特性:添加属性、删除属性、作为返回值等等。是的!JavaScript的函数就是这么样的!

 

Js代码
  1. function  hello() {  
  2.     alert("Hello!" );  
  3. }  
  4. hello.name = "Tom" ; // 添加属性   
  5. alert(hello["name" ]);  
  6. delete  hello.name; // 删除属性   
  7. alert(hello.name);  
  8. // 赋值给变量   
  9. var  hello1 = function () { alert("hello1" ); };  
  10. hello1();  
  11. // 作为数组元素   
  12. function  show(x) { alert(x); }  
  13. var  arr = [show];  
  14. arr[0](5);  
  15. // 作为函数的参数   
  16. function  callFunc(func) {  
  17.     func();  
  18. }  
  19. callFunc(function () {  
  20.     alert("Inner Function." );  
  21. });  
  22. // 作为函数的返回值   
  23. function  show() {  
  24.     return  function (n) {  
  25.         alert("number is "  + n);  
  26.     };  
  27. }  
  28. show()(10);    

瞧!凡是对象可以做到的,函数统统都能做到!JavaScript中的函数就是对象!

 

现在我们已经从数组,逐渐开始到对象和函数。这些都是基本概念,后面,我们将对JavaScript的面向对象特性做进一步的介绍
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值