JavaScript入门之基本函数(1)


系列专题:JavaScript入门


总的来说,函数在JavaScript中可以:


◆ 被赋值给一个变量


◆ 被赋值为对象的属性


◆ 作为参数被传入别的函数


◆ 作为函数的结果被返回


◆ 用字面量来创建


函数对象


1.1 创建函数


创建JavaScript函数的一种不长用的方式(几乎没有人用)是通过new操作符来作用于Function“构造器”:


  1. <strong>var funcName = new Function( [argname1, [... argnameN,]] body );</strong> 

参数列表中可以有任意多的参数,然后紧跟着是函数体,比如:


  1. <strong>var add = new Function("x""y""return(x+y)");  
  2. print(add(2, 4));</strong> 

将会打印结果:


6


但是,谁会用如此难用的方式来创建一个函数呢?如果函数体比较复杂,那拼接这个String要花费很大的力气,所以JavaScript提供了一种语法糖,即通过字面量来创建函数:


  1. <strong>function add(x, y){  
  2.     return x + y;  
  3. }</strong> 

或:


  1. <strong>var add = function(x, y){  
  2.     return x + y;  
  3. }</strong> 

事实上,这样的语法糖更容易使传统领域的程序员产生误解,function关键字会调用Function来new一个对象,并将参数表和函数体准确的传递给Function的构造器。


通常来说,在全局作用域(作用域将在下一节详细介绍)内声明一个对象,只不过是对一个属性赋值而已,比如上例中的add函数,事实上只是为全局对象添加了一个属性,属性名为add,而属性的值是一个对象,即function(x, y){return x+y;},理解这一点很重要,这条语句在语法上跟:


  1. <strong>var str = "This is a string";</strong> 

并无二致。都是给全局对象动态的增加一个新的属性,如此而已。


为了说明函数跟其他的对象一样,都是作为一个独立的对象而存在于JavaScript的运行系统,我们不妨看这样一个例子:


  1. <strong>function p(){  
  2.     print("invoke p by ()");  
  3. }  
  4.    
  5. p.id = "func";  
  6. p.type = "function";  
  7.    
  8. print(p);  
  9. print(p.id+":"+p.type);  
  10. print(p());</strong> 

没有错,p虽然引用了一个匿名函数(对象),但是同时又可以拥有属性,完全跟其他对象一样,运行结果如下:


function (){

print("invoke p by ()");

}

func:function

invoke p by ()


1.2 函数的参数


在JavaScript中,函数的参数是比较有意思的,比如,你可以将任意多的参数传递给一个函数,即使这个函数声明时并未制定形式参数,比如:


  1. <strong>function adPrint(str, len, option){  
  2.     var s = str || "default";  
  3.     var l = len || s.length;  
  4.     var o = option || "i";  
  5.      
  6.     s = s.substring(0, l);  
  7.     switch(o){  
  8.        case "u":  
  9.            s = s.toUpperCase();  
  10.            break;  
  11.        case "l":  
  12.            s = s.toLowerCase();  
  13.            break;  
  14.        default:  
  15.            break;  
  16.     }  
  17.      
  18.     print(s);  
  19. }  
  20.    
  21. adPrint("Hello, world");  
  22. adPrint("Hello, world", 5);  
  23. adPrint("Hello, world", 5, "l");//lower case  
  24. adPrint("Hello, world", 5, "u");//upper case</strong> 

函数adPrint在声明时接受三个形式参数:要打印的串,要打印的长度,是否转换为大小写的标记。但是在调用的时候,我们可以按顺序传递给adPrint一个参数,两个参数,或者三个参数(甚至可以传递给它多于3个,没有关系),运行结果如下:


Hello, world

Hello

hello

HELLO


事实上,JavaScript在处理函数的参数时,与其他编译型的语言不一样,解释器传递给函数的是一个类似于数组的内部值,叫arguments,这个在函数对象生成的时候就被初始化了。比如我们传递给adPrint一个参数的情况下,其他两个参数分别为undefined.这样,我们可以才adPrint函数内部处理那些undefined参数,从而可以向外部公开:我们可以处理任意参数。


我们通过另一个例子来讨论这个神奇的arguments:


  1. <strong>function sum(){  
  2.     var result = 0;  
  3.     for(var i = 0, len = arguments.length; i < len; i++){  
  4.        var current = arguments[i];  
  5.        if(isNaN(current)){  
  6.            throw new Error("not a number exception");  
  7.        }else{  
  8.            result += current;  
  9.        }  
  10.     }  
  11.      
  12.     return result;  
  13. }  
  14.    
  15. print(sum(10, 20, 30, 40, 50));  
  16. print(sum(4, 8, 15, 16, 23, 42));//《迷失》上那串神奇的数字  
  17. print(sum("new"));</strong> 

函数sum没有显式的形参,而我们又可以动态的传递给其任意多的参数,那么,如何在sum函数中如何引用这些参数呢?这里就需要用到arguments这个伪数组了,运行结果如下:


150

108

Error: not a number exception


函数作用域


作用域的概念在几乎所有的主流语言中都有体现,在JavaScript中,则有其特殊性:JavaScript中的变量作用域为函数体内有效,而无块作用域,我们在Java语言中,可以这样定义for循环块中的下标变量:


  1. public void method(){  
  2.     for(int i = 0; i < obj1.length; i++){  
  3.        //do something here;  
  4.     }  
  5.     //此时的i为未定义  
  6.     for(int i = 0; i < obj2.length; i++){  
  7.        //do something else;  
  8.     }    

而在JavaScript中:


  1. <strong>function func(){  
  2.     for(var i = 0; i < array.length; i++){  
  3.        //do something here.  
  4.     }  
  5.     //此时i仍然有值,及I == array.length  
  6.     print(i);//i == array.length;  
  7. }</strong> 

JavaScript的函数是在局部作用域内运行的,在局部作用域内运行的函数体可以访问其外层的(可能是全局作用域)的变量和函数。JavaScript的作用域为词法作用域,所谓词法作用域是说,其作用域为在定义时(词法分析时)就确定下来的,而并非在执行时确定,如下例:


  1. <strong>var str = "global";  
  2. function scopeTest(){  
  3.     print(str);  
  4.     var str = "local";  
  5.     print(str);  
  6. }  
  7.    
  8. scopeTest();</strong> 

运行结果是什么呢?初学者很可能得出这样的答案:


global

local


而正确的结果应该是:


undefined

local


因为在函数scopeTest的定义中,预先访问了未声明的变量str,然后才对str变量进行初始化,所以第一个print(str)会返回undifined错误。那为什么函数这个时候不去访问外部的str变量呢?这是因为,在词法分析结束后,构造作用域链的时候,会将函数内定义的var变量放入该链,因此str在整个函数scopeTest内都是可见的(从函数体的第一行到最后一行),由于str变量本身是未定义的,程序顺序执行,到第一行就会返回未定义,第二行为str赋值,所以第三行的print(str)将返回”local”。





标签:
Warning: Invalid argument supplied for foreach() in C:\zl\webjia\view.php on line 50

友情链接
轻松育儿世界奇观
苏ICP备16066217号-2