自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

JavaScript入門之基本函數(shù)

開發(fā) 前端
函數(shù),在C語言之類的過程式語言中,是頂級(jí)的實(shí)體,而在Java/C++之類的面向?qū)ο蟮恼Z言中,則被對象包裝起來,一般稱為對象的方法。而在JavaScript中,函數(shù)本身與其他任何的內(nèi)置對象在低位上是沒有任何區(qū)別的,也就是說,函數(shù)本身也是對象。

系列專題:JavaScript入門

總的來說,函數(shù)在JavaScript中可以:

◆ 被賦值給一個(gè)變量

◆ 被賦值為對象的屬性

◆ 作為參數(shù)被傳入別的函數(shù)

◆ 作為函數(shù)的結(jié)果被返回

◆ 用字面量來創(chuàng)建

函數(shù)對象

1.1 創(chuàng)建函數(shù)

創(chuàng)建JavaScript函數(shù)的一種不長用的方式(幾乎沒有人用)是通過new操作符來作用于Function“構(gòu)造器”:

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

參數(shù)列表中可以有任意多的參數(shù),然后緊跟著是函數(shù)體,比如:

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

將會(huì)打印結(jié)果:

6

但是,誰會(huì)用如此難用的方式來創(chuàng)建一個(gè)函數(shù)呢?如果函數(shù)體比較復(fù)雜,那拼接這個(gè)String要花費(fèi)很大的力氣,所以JavaScript提供了一種語法糖,即通過字面量來創(chuàng)建函數(shù):

  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> 

事實(shí)上,這樣的語法糖更容易使傳統(tǒng)領(lǐng)域的程序員產(chǎn)生誤解,function關(guān)鍵字會(huì)調(diào)用Function來new一個(gè)對象,并將參數(shù)表和函數(shù)體準(zhǔn)確的傳遞給Function的構(gòu)造器。

通常來說,在全局作用域(作用域?qū)⒃谙乱还?jié)詳細(xì)介紹)內(nèi)聲明一個(gè)對象,只不過是對一個(gè)屬性賦值而已,比如上例中的add函數(shù),事實(shí)上只是為全局對象添加了一個(gè)屬性,屬性名為add,而屬性的值是一個(gè)對象,即function(x, y){return x+y;},理解這一點(diǎn)很重要,這條語句在語法上跟:

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

并無二致。都是給全局對象動(dòng)態(tài)的增加一個(gè)新的屬性,如此而已。

為了說明函數(shù)跟其他的對象一樣,都是作為一個(gè)獨(dú)立的對象而存在于JavaScript的運(yùn)行系統(tǒng),我們不妨看這樣一個(gè)例子:

  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> 

沒有錯(cuò),p雖然引用了一個(gè)匿名函數(shù)(對象),但是同時(shí)又可以擁有屬性,完全跟其他對象一樣,運(yùn)行結(jié)果如下:

function (){
print("invoke p by ()");
}
func:function
invoke p by ()

1.2 函數(shù)的參數(shù)

在JavaScript中,函數(shù)的參數(shù)是比較有意思的,比如,你可以將任意多的參數(shù)傳遞給一個(gè)函數(shù),即使這個(gè)函數(shù)聲明時(shí)并未制定形式參數(shù),比如:

  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> 

函數(shù)adPrint在聲明時(shí)接受三個(gè)形式參數(shù):要打印的串,要打印的長度,是否轉(zhuǎn)換為大小寫的標(biāo)記。但是在調(diào)用的時(shí)候,我們可以按順序傳遞給adPrint一個(gè)參數(shù),兩個(gè)參數(shù),或者三個(gè)參數(shù)(甚至可以傳遞給它多于3個(gè),沒有關(guān)系),運(yùn)行結(jié)果如下:

Hello, world
Hello
hello
HELLO

事實(shí)上,JavaScript在處理函數(shù)的參數(shù)時(shí),與其他編譯型的語言不一樣,解釋器傳遞給函數(shù)的是一個(gè)類似于數(shù)組的內(nèi)部值,叫arguments,這個(gè)在函數(shù)對象生成的時(shí)候就被初始化了。比如我們傳遞給adPrint一個(gè)參數(shù)的情況下,其他兩個(gè)參數(shù)分別為undefined.這樣,我們可以才adPrint函數(shù)內(nèi)部處理那些undefined參數(shù),從而可以向外部公開:我們可以處理任意參數(shù)。

我們通過另一個(gè)例子來討論這個(gè)神奇的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));//《迷失》上那串神奇的數(shù)字  
  17. print(sum("new"));</strong> 

函數(shù)sum沒有顯式的形參,而我們又可以動(dòng)態(tài)的傳遞給其任意多的參數(shù),那么,如何在sum函數(shù)中如何引用這些參數(shù)呢?這里就需要用到arguments這個(gè)偽數(shù)組了,運(yùn)行結(jié)果如下:

150
108
Error: not a number exception

函數(shù)作用域

作用域的概念在幾乎所有的主流語言中都有體現(xiàn),在JavaScript中,則有其特殊性:JavaScript中的變量作用域?yàn)楹瘮?shù)體內(nèi)有效,而無塊作用域,我們在Java語言中,可以這樣定義for循環(huán)塊中的下標(biāo)變量:

  1. public void method(){  
  2.     for(int i = 0; i < obj1.length; i++){  
  3.        //do something here;  
  4.     }  
  5.     //此時(shí)的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.     //此時(shí)i仍然有值,及I == array.length  
  6.     print(i);//i == array.length;  
  7. }</strong> 

JavaScript的函數(shù)是在局部作用域內(nèi)運(yùn)行的,在局部作用域內(nèi)運(yùn)行的函數(shù)體可以訪問其外層的(可能是全局作用域)的變量和函數(shù)。JavaScript的作用域?yàn)樵~法作用域,所謂詞法作用域是說,其作用域?yàn)樵诙x時(shí)(詞法分析時(shí))就確定下來的,而并非在執(zhí)行時(shí)確定,如下例:

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

運(yùn)行結(jié)果是什么呢?初學(xué)者很可能得出這樣的答案:

global
local

而正確的結(jié)果應(yīng)該是:

undefined
local

因?yàn)樵诤瘮?shù)scopeTest的定義中,預(yù)先訪問了未聲明的變量str,然后才對str變量進(jìn)行初始化,所以***個(gè)print(str)會(huì)返回undifined錯(cuò)誤。那為什么函數(shù)這個(gè)時(shí)候不去訪問外部的str變量呢?這是因?yàn)椋谠~法分析結(jié)束后,構(gòu)造作用域鏈的時(shí)候,會(huì)將函數(shù)內(nèi)定義的var變量放入該鏈,因此str在整個(gè)函數(shù)scopeTest內(nèi)都是可見的(從函數(shù)體的***行到***一行),由于str變量本身是未定義的,程序順序執(zhí)行,到***行就會(huì)返回未定義,第二行為str賦值,所以第三行的print(str)將返回”local”。

#p#

函數(shù)上下文

在Java或者C/C++等語言中,方法(函數(shù))只能依附于對象而存在,不是獨(dú)立的。而在JavaScript中,函數(shù)也是一種對象,并非其他任何對象的一部分,理解這一點(diǎn)尤為重要,特別是對理解函數(shù)式的JavaScript非常有用,在函數(shù)式編程語言中,函數(shù)被認(rèn)為是一等的。

函數(shù)的上下文是可以變化的,因此,函數(shù)內(nèi)的this也是可以變化的,函數(shù)可以作為一個(gè)對象的方法,也可以同時(shí)作為另一個(gè)對象的方法,總之,函數(shù)本身是獨(dú)立的??梢酝ㄟ^Function對象上的call或者apply函數(shù)來修改函數(shù)的上下文:

call和apply

call和apply通常用來修改函數(shù)的上下文,函數(shù)中的this指針將被替換為call或者apply的***個(gè)參數(shù),我們不妨來看看JavaScript入門之對象與JSON中的例子:

  1. //定義一個(gè)人,名字為jack  
  2. var jack = {  
  3.     name : "jack",  
  4.     age : 26  
  5. }  
  6.    
  7. //定義另一個(gè)人,名字為abruzzi  
  8. var abruzzi = {  
  9.     name : "abruzzi",  
  10.     age : 26  
  11. }  
  12.    
  13. //定義一個(gè)全局的函數(shù)對象  
  14. function printName(){  
  15.     return this.name;  
  16. }  
  17.    
  18. //設(shè)置printName的上下文為jack, 此時(shí)的this為jack  
  19. print(printName.call(jack));  
  20. //設(shè)置printName的上下文為abruzzi,此時(shí)的this為abruzzi  
  21. print(printName.call(abruzzi));  
  22.    
  23. print(printName.apply(jack));  
  24. print(printName.apply(abruzzi)); 

只有一個(gè)參數(shù)的時(shí)候call和apply的使用方式是一樣的,如果有多個(gè)參數(shù):

  1. setName.apply(jack, ["Jack Sept."]);  
  2. print(printName.apply(jack));  
  3.    
  4. setName.call(abruzzi, "John Abruzzi");  
  5. print(printName.call(abruzzi)); 

得到的結(jié)果為:

  1. Jack Sept.  
  2. John Abruzzi 

apply的第二個(gè)參數(shù)為一個(gè)函數(shù)需要的參數(shù)組成的一個(gè)數(shù)組,而call則需要跟若干個(gè)參數(shù),參數(shù)之間以逗號(hào)(,)隔開即可。

使用函數(shù)

前面已經(jīng)提到,在JavaScript中,函數(shù)可以

◆ 被賦值給一個(gè)變量

◆ 被賦值為對象的屬性

◆ 作為參數(shù)被傳入別的函數(shù)

◆ 作為函數(shù)的結(jié)果被返回

我們就分別來看看這些場景:

賦值給一個(gè)變量:

  1. //聲明一個(gè)函數(shù),接受兩個(gè)參數(shù),返回其和  
  2. function add(x, y){  
  3.     return x + y;  
  4. }  
  5.    
  6. var a = 0;  
  7. a = add;//將函數(shù)賦值給一個(gè)變量  
  8. var b = a(2, 3);//調(diào)用這個(gè)新的函數(shù)a  
  9. print(b); 

這段代碼會(huì)打印”5”,因?yàn)橘x值之后,變量a引用函數(shù)add,也就是說,a的值是一個(gè)函數(shù)對象(一個(gè)可執(zhí)行代碼塊),因此可以使用a(2, 3)這樣的語句來進(jìn)行求和操作。

賦值為對象的屬性:

  1. <strong>var obj = {  
  2.     id : "obj1" 
  3. }  
  4.    
  5. obj.func = add;//賦值為obj對象的屬性  
  6. obj.func(2, 3);//返回5</strong> 

事實(shí)上,這個(gè)例子與上個(gè)例子的本質(zhì)上是一樣的,***個(gè)例子中的a變量,事實(shí)上是全局對象(如果在客戶端環(huán)境中,表示為window對象)的一個(gè)屬性。而第二個(gè)例子則為obj對象,由于我們很少直接的引用全局對象,就分開來描述。

作為參數(shù)傳遞:

  1. //高級(jí)打印函數(shù)的第二個(gè)版本  
  2. function adPrint2(str, handler){  
  3.     print(handler(str));  
  4. }  
  5.    
  6. //將字符串轉(zhuǎn)換為大寫形式,并返回  
  7. function up(str){  
  8.     return str.toUpperCase();  
  9. }  
  10.    
  11. //將字符串轉(zhuǎn)換為小寫形式,并返回  
  12. function low(str){  
  13.     return str.toLowerCase();  
  14. }  
  15.    
  16. adPrint2("Hello, world", up);  
  17. adPrint2("Hello, world", low); 

運(yùn)行此片段,可以得到這樣的結(jié)果:

HELLO, WORLD
hello, world

應(yīng)該注意到,函數(shù)adPrint2的第二個(gè)參數(shù),事實(shí)上是一個(gè)函數(shù),將這個(gè)處理函數(shù)作為參數(shù)傳入,在adPrint2的內(nèi)部,仍然可以調(diào)用這個(gè)函數(shù),這個(gè)特點(diǎn)在很多地方都是有用的,特別是,當(dāng)我們想要處理一些對象,但是又不確定以何種形式來處理,則完全可以將“處理方式”作為一個(gè)抽象的粒度來進(jìn)行包裝(即函數(shù))。

作為函數(shù)的返回值:

先來看一個(gè)最簡單的例子:

  1. <strong>function currying(){  
  2.     return function(){  
  3.        print("curring");  
  4.     }  
  5. }</strong> 

函數(shù)currying返回一個(gè)匿名函數(shù),這個(gè)匿名函數(shù)會(huì)打印”curring”,簡單的調(diào)用currying()會(huì)得到下面的結(jié)果:

  1. <strong>function (){  
  2.     print("curring");  
  3. }</strong> 

如果要調(diào)用currying返回的這個(gè)匿名函數(shù),需要這樣:

  1. currying()(); 

***個(gè)括號(hào)操作,表示調(diào)用currying本身,此時(shí)返回值為函數(shù),第二個(gè)括號(hào)操作符調(diào)用這個(gè)返回值,則會(huì)得到這樣的結(jié)果:

currying

原文:http://abruzzi.iteye.com/blog/646798

【系列文章】

JavaScript入門之對象與JSON

JavaScript概述

JavaScript內(nèi)核之基本概念

責(zé)任編輯:陳貽新 來源: abruzzi的博客
相關(guān)推薦

2011-08-10 17:04:43

JavaScript

2011-07-19 13:44:39

JavaScript

2017-02-20 23:05:14

JavaScript

2016-10-13 19:11:27

JavaScript函數(shù)Web

2011-07-20 10:27:29

JavaScript

2010-06-07 19:48:30

UML

2016-10-28 21:13:33

JavaScript基本包裝類型

2011-08-24 13:56:27

JavaScript

2017-02-28 16:03:46

支付清結(jié)算交易

2011-09-29 09:50:44

JavaScript

2010-07-26 11:09:35

Perl函數(shù)手冊

2019-09-18 18:56:34

JavascriptOOP前端

2018-11-29 08:00:20

JavaScript異步Promise

2009-07-31 14:26:38

JavaScript函C#函數(shù)

2009-08-18 10:34:31

Java入門基本概念

2017-04-12 11:47:32

2020-12-07 08:01:59

JavaScript入門技巧

2011-09-09 19:23:52

Widget

2011-09-08 14:50:51

JavascriptWidget

2010-10-08 15:11:28

JavaScript數(shù)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)