改善JavaScript程序的188個建議5160_第1頁
改善JavaScript程序的188個建議5160_第2頁
改善JavaScript程序的188個建議5160_第3頁
改善JavaScript程序的188個建議5160_第4頁
改善JavaScript程序的188個建議5160_第5頁
已閱讀5頁,還剩20頁未讀 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、建議51:理解數組長度的有限性和無限性每個數組都有一個length屬性。和大多數其他語言不同,JavaScript數組的length是沒有上限的。如果用大于或等于當前length的數字作為下標來保存一個元素,那么length將增大以容納新元素,不會發生數組邊界錯誤。length屬性的值是這個數組的最大整數屬性名加上1。它不一定等于數組中屬性的個數。例如,下面數組myArray最后長度為10001,但它僅包含一個元素:var myArray = ;myArray.length     / 0myArray10000 = true;myArray.lengt

2、h     / 10001后綴下標運算符將它的表達式轉換成一個字符串,如果該表達式中有toString方法,就使用該方法的值。這個字符串將用做屬性名。如果這個字符串看起來像一個大于或等于這個數組當前的length且小于4 294 967 295的正整數,那么這個數組的length就會被重新設置為新的下標加1。根據ECMAScript 262標準,數組的下標必須是大于或等于0且小于2321的整數。我們可以直接為數組設置length值。當設置更大的length時,也不用向數組分配更多的空間,而當把length設置為小于數組的實際長度時,將導致所有下標大于或等

3、于新length的元素被刪除。var numbers='zero','one','two','three','four','five','six','seven','eight','nine'numbers.length = 3; / numbers = 'zero', 'one', 'two'通過將下標指定為一個數組的當前length,可以附加一個新元素到該數組的尾部。numbersnu

4、mbers.length = 'ten'有時用push方法可以更方便地完成同樣的事情。numbers.push('ten');建議52:建議使用splice刪除數組刪除數組元素的方法有多種,最簡單的方法是利用length屬性來截斷數組,但這種方法比較笨拙,僅能夠截斷尾部元素。在JavaScript中,由于數組其實就是對象,因此使用delete運算符可以從數組中移除元素。var numbers='zero','one','two','three','four','five

5、9;,'six','seven','eight','nine'delete numbers2; / numbers='zero','one',undefined,'three','four','five', 'six','seven','eight','nine'但是,使用這種方式刪除指定下標位置的元素后,會在數組中遺留一個空洞。這是因為排在被刪除元素之后的元素保留了它們最初的名

6、字(下標位置),而我們通常想要的是遞減后面每個元素的名字(下標)。幸運的是,JavaScript數組有一個splice方法,它可以刪除一些元素并將它們替換為其他的元素。splice方法的第一個參數是數組中的一個序號,第二個參數是要刪除的元素個數。任何額外的參數會在序號那個點的位置被插入數組中。例如:var numbers='zero','one','two','three','four','five','six','seven','eight',

7、9;nine'numbers. splice (2,1) ; / numbers = 'zero', 'one', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine'執行以上代碼之后,元素值為“three”的下標值從4變為3,同理,其后所有元素的下標值都遞減1。因為必須移除被刪除元素后面的每個元素,并且將一個新的鍵值重新插入,因此,這對于大型數組來說效率會更高。建議53:小

8、心使用數組維度在JavaScript中,數組在默認狀態下是不會初始化的。如果使用運算符創建一個新數組,那么此數組將是空的。如果訪問的是數組中不存在的元素,則得到的值將是undefined。因此,在JavaScript程序設計中應該時刻考慮這個問題:在嘗試讀取每個元素之前,都應該預先設置它的值。但是,如果在設計中假設每個元素都從一個已知的值開始(如0),那么就必須預定義這個數組。我們也可以為JavaScript自定義一個靜態函數:Array.dim = function(dimension, initial)     var a = , i;  

9、  for( i = 0; i < dimension; i += 1)         ai = initial;        return a;借助這個工具函數,可以輕松地創建一個初始化數組。例如,創建一個包含100個0的數組:var myArray = Array.dim(100, 0);JavaScript沒有多維數組,但是它支持元素為數組的數組。var matrix =      0, 1, 2,&

10、#160;    3, 4, 5,     6, 7, 8;matrix21 /7為了自動化創建一個二維數組或一個元素為數組的數組,我們不妨這樣做:for( i = 0; i < n; i += 1)     my_arrayi = ;注意,Array.dim(n, )在這里不能工作,如果使用它,每個元素都指向同一個數組的引用,那是非常糟糕的。一個空矩陣的每個單元將擁有一個初始值undefined。如果希望它們有不同的初始值,必須明確地設置它們的值。因此,我們可以單獨為Array

11、定義一個矩陣數組定義函數。Array.matrix = function(m, n, initial)     var a, i, j, mat = ;    for( i = 0; i < m; i += 1)         a = ;        for( j = 0; j < n; j += 1)       

12、60;     aj = initial;                mati = a;        return mat;下面就利用這個矩陣數組定義函數構建一個5×5的矩陣數組,且每個元素的初始值為0。var myMatrix = Array.matrix(5, 5, 0);document.writeln(myMatrix24);

13、0; / 0建議54:增強數組排序的sort功能sort方法不僅按字母順序進行排序,還可以根據其他順序執行操作。這時就必須為方法提供一個比較函數的參數,該函數要比較兩個值,然后返回一個用于說明這兩個值的相對順序的數字。比較函數應該具有兩個參數a和b,其返回值如下:1)如果根據自定義評判標準,a小于b,在排序后的數組中a應該出現在b之前,就返回一個小于0的值。2)如果a等于b,就返回0。3)如果a大于b,就返回一個大于0的值。在下面的示例中,將根據比較函數來比較數組中每個元素的大小,并按從小到大的順序執行排序:function f( a, b )    r

14、eturn ( a - b )var a = 3, 1, 2, 4, 5, 7, 6, 8, 0, 9;   / 定義數組a.sort(f);alert( a );      /0,1,2 ,3,4, 5,6,7 ,8,9如果按從大到小的順序執行排序,則讓返回值取反即可,代碼如下:function f( a, b )    return  -( a - b )var a = 3, 1, 2, 4, 5, 7, 6, 8, 0, 9;a.sort(f);alert( a );  

15、;/9,8,7 ,6,5, 4,3,2 ,1,0(1)根據奇偶性質排列數組sort方法用法比較靈活,但更靈活的是對比較函數的設計。例如,要根據奇偶數順序排列數組,只需要判斷比較函數中兩個參數是否為奇偶數,并決定排列順序,代碼如下:function f( a, b )    var a = a % 2;    var b = b % 2;    if( a = 0 ) return 1;    if( b = 0 ) return -1;var a = 3, 1, 2, 4,

16、5, 7, 6, 8, 0, 9;a.sort( f );alert( a );   /3,1,5,7,9,0,8,6,4,2sort方法在調用比較函數時,將每個元素值傳遞給比較函數,如果元素值為偶數,則保留其位置不動;如果元素值為奇數,則調換參數a和b的顯示順序,從而實現對數組中所有元素執行奇偶排序。如果希望偶數排在前面,奇數排在后面,則只需要取返回值。比較函數如下:function f( a, b )    var a = a % 2;    var b = b % 2;    i

17、f( a  = 0 ) return -1;    if( b  = 0 ) return 1;(2)不區分大小寫排序字符串在正常情況下,對字符串進行排序是區分大小寫的,這是因為每個字母大寫形式和小寫形式在字符編碼表中的順序是不同的,大寫形式排在小寫形式前面,例如:var a = "aB", "Ab", "Ba", "bA"a.sort();alert( a );  /"Ab","Ba","aB"

18、,"bA"也就是說,同一字母大寫形式總是排在左側,而小寫形式總是排在右側。如果讓小寫形式總是排在前面,則可以這樣設計:function f( a, b )    return ( a < b );var a = "aB", "Ab", "Ba", "bA"a.sort( f );alert( a );  /"Ab","Ba","aB","bA"在比較字母大小時,JavaS

19、cript根據字符編碼大小來決定字母的大小,當比較函數的返回值為true時,則返回1;當比較函數的返回值為false時,則返回1。如果不希望區分字母大小,也就是說,大寫字母和小寫字母按相同順序排列,則可以這樣設計:function f( a, b )    var a = a.toLowerCase;    var b = b.toLowerCase;    if( a < b )        return  1;&#

20、160;       else        return -1;    var a = "aB", "Ab", "Ba", "bA" / 定義數組a.sort( f );alert( a );  /"aB", "Ab", "Ba", "bA"如果要調整排序順序,則對返

21、回值取反即可。(3)把浮點數和整數分開排列經常會遇到把浮點數和整數分開排列的情況。當然,借助sort方法實現起來并不是很難,我們可以這樣設計:function f( a, b )    if( a > Math.floor( a ) ) return  1;    if( b > Math.floor( b ) ) return  - 1;var a = 3.55555, 1.23456, 3, 2.11111, 5, 7, 3;a.sort( f );alert( a );  /3,5,7,

22、3,2.11111,1.23456,3.55555如果要調整排序順序,則對返回值取反即可。sort方法的功能是非常強大的,如果比較的元素是對象而不是值類型(如數字和字符串等)這樣簡單的數據時,排序就變得更加有趣了,讀者可以自己動手試一試。建議55:不要拘泥于數字下標數組下標默認為大于或等于0的整數,不過JavaScript允許數組下標可以為任意表達式,甚至為任意類型數據。(1)文本下標為數組下標指定負值:var a = ; / 定義空數組直接量a-1 = 1;  / 為下標為-1的元素賦值很顯然,上面的用法是非法的,因為這不符合語法規范。使用length屬性檢測,返回值為0

23、,說明數組并沒有增加長度,這是正確的,也很正常。但是,使用下面的方法可以讀取該元素的值:alert(a.length);  / 0,說明數組長度沒有增加alert(a-1);  / 1alert(a"-1"); / 1,說明這個值以對象屬性的形式被存儲不僅如此,還可以為數組指定字符串下標,或者布爾值下標,例如:var a = ;atrue = 1;afalse = 0;alert(a.length);  /0,說明數組長度沒有增加alert(atrue);  /1alert(afalse);  /0alert(a0

24、);  /undefinedalert(a1);  /undefined雖然true和false可以被轉換為1和0,但是JavaScript并沒有執行轉換,而是把它們視為對象屬性來看待。如果文本是數字,可以直接使用數字下標來訪問,這時JavaScript又能夠自動轉換它們的類型。例如:a"1" = 1;alert(a1);  /1這種數據存儲格式稱為哈希表。哈希表的數據檢索速度要快于數組迭代檢索,因此,對于下面的操作:var a = "張三",1,"李四",2,"王五",3; 

25、0;/ 二維數組for(var i in a)      / 遍歷二維數組    if(ai0 = "李四") alert(ai1) ;  / 檢索指定元素將數組下標改為文本下標會更為高效。var a = ;  / 定義空數組a"張三" = 1;   / 以文本下標來存儲元素的值a"李四" = 2;a"王五" = 3;alert(a"李四" );  / 快速

26、定位檢索(2)二維數組下標JavaScript不支持定義二維數組的語法,但我們可以模仿其他語言中二維數組的形式來定義數組。例如,下面的寫法雖然不符合語法上的規定,但是JavaScript不會提示編譯錯誤:var a = ;a0,0 = 1;a0,1 = 2;a1,0 = 3;a1,1 = 4;如果調用length屬性,返回值為2,則說明僅有兩個元素,分別讀取元素的值,代碼如下:alert(a.length);  /2,說明僅有兩個元素有效alert(a0);  /3alert(a1);  /3JavaScript把二維數組下標視為一個逗號表達式,其運算的返回值是最

27、后一個值。前面兩行代碼賦值就被后面兩行代碼賦值覆蓋了。因此,如果經過計算之后才確定下標值,之后再進行存取操作,則可以按如下方式進行設計:var a = , i = 1;  / 初始化變量while( i < 10 )   / 指定循環次數    ai *= 2 , i = i;  / 指定下標為2的指數時才進行賦值alert( a.length );  /17alert( a );   /,2, 4, 8, 16(3)對象下標對象也可以作為數組下標。JavaScript會試圖把對

28、象轉換為數值,如果不行,則把它轉換為字符串,然后以文本下標的形式進行操作。例如:var a = ;  / 數組直接量var b = function() / 函數直接量    return 2;ab = 1;    / 把對象作為數組下標alert( a.length );  /長度為0alert( ab );   /1可以這樣讀取元素值:var s =b.toString(); / 獲取對象的字符串alert( as );   / 利用文本下標

29、讀取元素的值還可以這樣設計下標:ab() = 1;  / 在下標處調用函數,則返回值為2alert( a2 );  / 因此可以使用2來讀取該元素值建議56:使用arguments模擬重載在JavaScript中,每個函數內部可以使用arguments對象,該對象包含了函數被調用時的實際參數值。arguments對象雖然在功能上與數組有些類似,但它不是數組。 arguments 對象與數組的類似體現在它有一個 length 屬性,同時實際參數的值可以通過操作符來獲取,但arguments對象并沒有數組可以使用的push、pop、splice等方法。其原因是arguments

30、對象的prototype指向的是Ototype,而不是Atotype。Java和C+語言都支持方法重載,即允許出現名稱相同而形式參數不同的方法,但JavaScript并不支持這種方式的重載。這是因為JavaScript中的function對象也是以屬性的形式出現的,在一個對象中增加與已有function 同名的新function時,舊的function對象會被覆蓋。不過可以通過使用arguments來模擬重載,其實現機制是通過判斷arguments中實際參數的個數和類型來執行不同的邏輯。function sayHello()    

31、; switch (arguments.length)         case 0:            return "Hello"        case 1:            return "H

32、ello, " + arguments0;        case 2:            return (arguments1 = "cn" ? " 你好," : "Hello, ") + arguments0;    ;sayHello();  /"Hello"sayHe

33、llo("Alex");  / "Hello, Alex"sayHello("Alex", "cn"); / " 你好,Alex"callee是arguments對象的一個屬性,其值是當前正在執行的function對象。它的作用是使匿名 function可以被遞歸調用。下面以一段計算斐波那契序列中第N個數的值的過程來演示arguments.callee的使用。function fibonacci(num)     return (fun

34、ction(num)         if( typeof num != "number")            return -1;        num = parseInt(num);        if(num < 1)  

35、          return -1;        if(num = 1 | num = 2)            return 1;        return arguments.callee(num - 1) + arguments.callee(

36、num - 2);    )(num);fibonacci(100);第3章 函數式編程概述JavaScript是一門優美的語言,具有動態性、弱類型,具有C和 LISP的雙重語法。JavaScript雖然是基于對象編程,但是對象不是第一型的,而函數是第一型的。函數式編程思想的源頭可以追溯到20世紀30年代阿朗佐·丘奇進行的一項關于問題的可計算性的研究,也就是后來的lambda演算。lambda演算的本質就是一切皆函數,函數可以作為另外一個函數的輸出或輸入,一系列的函數使用最終會形成一個表達式鏈,通過這個表達式鏈可以最終求得一個值,而這個過程即為計算的本質

37、。在函數式編程中,會發現代碼中存在大量的連續運算。函數式編程已經在實際應用中發揮了巨大作用,更有越來越多的語言不斷地加入對諸如閉包、匿名函數等的支持,從某種程度上來講,函數式編程正在逐步同化命令式編程。建議57:禁用Function構造函數定義函數的方法包括3種:function語句、Function構造函數和函數直接量。不管用哪種方法定義函數,它們都是Function對象的實例,并將繼承Function對象所有默認或自定義的方法和屬性。/ 使用function語句編寫函數function f(x)    return x;/ 使用Function()構造函數克隆

38、函數var f = new Function("x", "return x;");/ 使用函數直接量直接生成函數var f = function(x)    return x;雖然這些方法定義函數的結構體相同,函數的效果相近,但是也存在很多差異,詳細比較見表3.1。表3.1函數定義方法比較 使用function語句 使用Function構造函數 使用函數直接量兼容 完全 JavaScript 1.1及以上 JavaScript 1.2及以上形式 句子

39、60;表達式 表達式名稱 有名 匿名 匿名主體 標準語法 字符串 標準語法性質 靜態 動態 靜態解析 以命令的形式構造一個函數對象 解析函數體,能夠動態創建一個新的函數對象 以表達式的形式構造一個函數對象(1)作用域比較使用Function構造函數創建的函數具有頂級作用域,JavaScript解釋器也總是把它作為頂級函數來編譯,而function語句和函數直接量定義的函數都有自己的作用域(即局部作用域,或稱為函數作用域)。例如:var n = 1;function

40、f()    var n = 2;    function e()        return n;        return e;alert(f()(); /2在上面示例中,分別在函數體外和函數體內聲明并初始化變量n,然后在函數體內使用function語句定義一個函數e,定義該函數返回變量n的值。最后在函數體外調用函數的返回函數。通過結果可以發現,返回值為局部變量n的值(即為2),也就是說,f

41、unction語句定義的函數擁有自己的作用域。同理,如果使用函數直接量定義函數e,當調用該返回函數時,返回值是2,而不是1,那么也說明函數直接量定義的函數擁有自己的作用域。但是,如果使用Function構造函數定義函數e,則調用該返回函數時,返回的值是1,而不再是2了,看來Function構造函數定義的函數作用域需要動態確定,而不是在定義函數時確定的,代碼如下:var n = 1;function f()    var n = 2;    var e = new Function("return n;");

42、0;   return e;alert(f()(); /1(2)解析效率比較JavaScript解釋器在解析代碼時,并非一行行地分析和執行程序,而是一段段地分析執行。在同一段代碼中,使用function語句和函數直接量定義的函數結構總會被提取出來優先執行。只有在函數被解析和執行完畢之后,才會按順序執行其他代碼行。但是使用Function構造函數定義的函數并非提前運行,而是在運行時動態地被執行,這也是Function構造函數定義的函數具有頂級作用域的根本原因。從時間角度審視,function語句和函數直接量定義的函數具有靜態的特性,而Function構造函數定義的函

43、數具有動態的特性。這種解析機制的不同,必然帶來不同的執行效率,這種差異性可以通過將一個循環結構放大來比較得出。在下面這個示例中,分別把function語句定義的空函數和Function構造函數定義的空函數放在一個循環體內,讓它們空轉十萬次,這樣就會明顯感到使用function語句定義的空函數運行效率更高。/ 測試function語句定義的空函數執行效率var a = new Date();var x = a.getTime();for(var i=0;i<100000;i+)    function()   /使用functio

44、n語句定義的空函數        ;    var b = new Date();var y = b.getTime();alert(y-x);    /62,不同環境和瀏覽器會存在差異/ 測試Function構造函數定義的空函數執行效率var a = new Date();var x = a.getTime();for(var i=0;i<100000;i+)    new Function();  /使用F

45、unction構造函數定義的空函數var b = new Date();var y = b.getTime();alert(y-x);    /2390JavaScript解釋器首先把function語句定義的函數提取出來進行編譯,這樣每次循環執行該函數時,就不再從頭開始重新編譯該函數對象了,而Function構造函數定義的函數每次循環時都需要動態編譯一次,這樣效率就非常低了。(3)兼容性比較從兼容角度考慮,使用function語句定義函數不用考慮JavaScript版本問題,所有版本都支持這種方法。而Function構造函數只能在JavaScript 1.1及其

46、以上版本中使用,函數直接量僅在JavaScript 1.2及其以上版本中有效。當然,版本問題現在已經不是問題了。Function構造函數和函數直接量定義函數方法有點相似,它們都是使用表達式來創建的,而不是通過語句創建的,這樣帶來了很大的靈活性。對于僅使用一次的函數,非常適合使用表達式的方法來創建。由于Function構造函數和函數直接量定義函數不需要額外的變量,它們直接在表達式中參與運算,所以節省了資源,克服了使用function語句定義函數占用內存的弊端,也就是說,這些函數運行完畢即被釋放而不再占用內存空間。對于Function構造函數來說,由于定義函數的主體必須以字符串的形式來表示,使用這

47、種方法定義復雜的函數就顯得有點笨拙,很容易出現語法錯誤。但函數直接量的主體使用標準的JavaScript語法,這樣看來使用函數直接量是一種比較快捷的方法。通過function語句定義的函數稱為命名式函數、聲明式函數或函數常量,而通過匿名方式定義的函數稱為引用式函數或函數表達式,而把賦值給變量的匿名函數稱為函數對象,把該變量稱為函數引用。建立58:靈活使用ArgumentsJavaScript函數的參數是不固定的,調用函數時傳遞給它的實參也很隨意,為了有效管理參數,JavaScript支持Arguments機制。Arguments是一個偽數組,可以通過數組下標的形式獲取該集合中傳遞給函數的參數值

48、。例如,在下面這個函數中,沒有指定形參,但在函數體內通過Arguments對象可以獲取傳遞給該函數的每個實參值。function f()    for(var i = 0; i < arguments.length; i + )        alert(argumentsi);    f(3, 3, 6);Arguments對象僅能夠在函數體內使用,它僅作為函數體的一個私有成員而存在,因此可以通過點號運算符來指定Arguments對象所屬的函數。由于Argu

49、ments對象在函數體內是唯一的和可指向的,因此一般會省略前置路徑,直接引用Arguments對象的調用標識符arguments。通過數組的形式來引用Arguments對象包含的實參值,如argumentsi,其中arguments表示對Arguments對象的實際引用,變量i是Arguments對象集合的下標值,從0開始,直到arguments.length(其中length是Arguments對象的一個屬性,表示Arguments對象包含的實參的個數)。由于Arguments不是Array的實例,因此不能夠直接調用數組的方法,但通過call或apply方法能夠間接實現調用數組的部分方法。A

50、rguments對象中的每個元素實際上就是一個變量,這些變量用來存儲調用函數時傳遞的實參值。通過arguments數組和已經命名的形參可以引用這些變量的值。使用Arguments對象可以隨時改變實參的值。例如,在下面這個示例中把循環變量的值傳遞給Arguments對象元素,以實現動態改變實參的值。function f()    for(var i = 0; i < arguments.length; i + )        argumentsi =i;   

51、     alert(argumentsi);   f(3, 3, 6);  /提示1、2、3,而不是3、3、6通過修改Arguments對象的length屬性值,可以達到改變函數實參個數的目的。當length屬性值增大時,增加的實參值為undefined,當length屬性值減小時,則會丟棄arguments數據集合后面對應個數的元素。Arguments在實際開發中具有重要的價值,使用它可以監測用戶在調用函數時所傳遞的參數是否符合要求,增強函數的容錯能力,同時還可以開發出很多功能強大的函數。如果要定義的函數參數個數不確定,

52、或者參數個數很多,又不想為每個參數都定義一個變量,此時定義函數可以保留參數列表為空,在函數內部使用Arguments對象來訪問調用函數時傳遞的所有參數。下面這個示例就是利用Arguments對象來計算函數任意多個參數的平均值。function avg()    var num = 0, l = 0;    for(var i = 0; i < arguments.length; i + )        if(typeof argumentsi != &quo

53、t;number")            continue;        num += argumentsi;        l + ;        num /= l;    return num;alert(avg(1, 2, 3, 4);

54、  /2.5alert(avg(1, 2, "3", 4);  /2.3333333333333335表單驗證是頁面設計中經常要完成的任務,下面的示例驗證所輸入的值是否符合郵箱地址格式。function isEmail()    if(arguments.length>1) throw new Error("只能夠傳遞一個參數");    var regexp = /w+(-w+)|(.w+)*A-Za-z0-9+(.|-)A-Za-z0-9+)*.A-Za-

55、z0-9+$/;    if (arguments0.search(regexp)!= -1)        return true;    else        return false;var email = ""alert(isEmail(email);  /trueArguments對象包含一個callee屬性,它能夠返回當前Arguments對象所屬的函數

56、引用,這相當于在函數體內調用函數自身。在匿名函數中,callee屬性比較有用,通過它在函數內部引用函數自身。在下面這個示例中,通過arguments.callee獲取對當前匿名函數的引用,然后通過函數的length屬性確定它的形參個數。最后,通過實參和形參數目的比較來確定傳遞的參數是否合法。function f(x, y, z)    var a = arguments.length;    var b = arguments.callee.length;    if (a != b) 

57、0;      throw new Error("傳遞的參數不匹配");        else        return x + y + z;    alert(f(3, 4, 5);  /值為12Function對象的length屬性返回的是函數的形參個數,而Arguments對象的length屬性返回的是函數的實參個數。如果函數不是匿名函數,則arg

58、uments.callee等價于函數名。建議59:推薦動態調用函數調用函數更便捷的方式是使用Function對象的call和apply方法。apply與call方法在本質上沒有太大區別,只不過它們傳遞給函數的參數方式不同, apply是以數組形式進行參數傳遞,而call方法可以同時傳遞多個值。如果某個函數僅能夠接收多個參數列表,而現在希望把一個數組的所有元素作為參數進行傳遞,那么使用apply方法就顯得非常便利。function max()    var m = Number.NEGATIVE_INFINITY; / 聲明一個負無窮大的數值 &

59、#160;  for( var i = 0; i < arguments.length; i + )        if( argumentsi > m )        m = argumentsi;        return m;var a = 23, 45, 2, 46, 62, 45, 56, 63;var m = max.apply( Object, a );al

60、ert( m );    /63在上面的示例中,首先定義一個函數來計算所傳遞實參的最大值。由于該函數僅能夠接收多個數值參數,所以通過apply方法動態調用max()函數,然后把它綁定為Object對象的一個方法,并借機把一個數組傳遞給它,最后返回此函數的運行值。如果沒有apply方法,想使用max()函數來計算數組中最大元素值,就需要把數組的所有元素讀取出來,然后再傳遞給函數,顯然這種做法是費力不討好的。實際上,也可以把數組元素通過apply方法傳遞給系統對象Math的max方法來計算數組的最大元素值。var a = 23, 45, 2, 46, 62,

61、 45, 56, 63; / 聲明并初始化數組var m = Math.max.apply( Object, a );  / 調用系統函數maxalert( m );  /63使用call和apply方法可以把一個函數轉換為方法傳遞給某個對象。這種行為只是臨時的,函數最終并沒有作為對象的方法而存在,當函數被調用后,該對象方法會自動被注銷。下面的示例具體地說明了這種行為。function f()f.call( Object );Object.f();call和apply方法能夠更改對象的內部指針,即改變對象的this指向的內容,這在面向對象的編程過程中是非常有用的。

62、var x = "o"function a()    this.x = "a"function b()    this.x = "b"function c()    alert( x );function f()    alert( this.x );f(); /字符o,即全局變量x的值。this此時指向window對象f.call( window ); f.call( new a() ); &#

63、160; /字符a,即函數a內部的局部變量x的值。this此時指向函數af.call( new b() );  /字符b,即函數b內部的局部變量x的值。this此時指向函數bf.call( c );  /*undefined,即函數c內部的局部變量x的值,但是該函數并沒有定義x變量,所以返回沒有定義。this此時指向函數c*/通過上面示例的比較,能夠很直觀地發現,函數f內部的this關鍵字會隨著所綁定的對象不同而指向不同的對象。因此,利用call或apply方法能夠改變函數內部指針指向所綁定的對象,從而實現屬性或方法繼承。function f() 

64、60;  this.a ="a"    this.b = function()        alert("b");    function e()    f.call(this);    alert(a);e()   /字符串a上面的示例說明,如果在函數體內使用call和apply方法動態調用外部函數,并把call和apply

65、方法的第一個參數值設置為關鍵字this,那么當前函數e將繼承函數f的所有成員。使用call和apply方法能夠復制調用函數的內部變量給當前函數體,更改了函數f的內部關鍵字this指向函數e,這樣函數e就可以引用函數f的內部成員。最后,再看一個比較復雜的示例。在這個示例中將演示如何使用apply方法循環更改當前指針,從而實現循環更改函數的結構。function r( x )    return ( x );function f( x )    x0 = x0 + ">"    re

66、turn x;function o()    var temp = r;    r = function()        return temp.apply( this, f( arguments ) );    function a()    o();    alert( r( "=" ) );for( var i = 0 ; i < 10; i

67、+ )    a();執行上面代碼后會看到,提示信息框中的提示信息不斷變化。該示例的核心就在于函數o的設計。在這個函數中,首先使用一個臨時變量存儲函數r。然后修改函數r的結構,在修改的函數r的結構中,通過調用apply方法修改原來函數r的指針指向當前對象,同時執行原函數r,并把執行函數f的值傳遞給它,從而實現修改函數r的return語句的后半部分信息,即為返回值增加一個前綴字符“=”。這樣每次調用函數o時,都會為其增加一個前綴字符“=”,從而形成一種動態的變化效果。當然,call和apply方法的應用是非常靈活的,在大型JavaScript技術框架中經常會用到它們

68、,利用它們可以實現動態更改對象的指針,從而實現各種復雜的功能。建議60:比較函數調用模式在JavaScript中,函數就是對象,對象是“名/值”對的集合,并擁有一個到原型對象的隱藏連接。對象字面量產生的對象連接到totype,函數對象連接到Ftotype,該原型對象本身連接到totype。每個函數在創建時都有兩個附加的隱藏屬性:函數的上下文和實現函數行為的代碼。每個函數對象在創建時也隨之帶一個prototype屬性,它的值是一個擁有constructor屬性且constructor屬性值為該函數的對象。這和隱藏連接到Function

69、. prototype完全不同。這個令人費解的構造過程的意義將會在后面的章節中揭示。作為對象,函數與其他值一樣可以在任何變量的位置使用。函數可以作為數組元素,可以作為函數的返回值,可以作為對象的成員值,也可以作為表達式參與運算,同時函數也可以擁有自己的方法。調用一個函數將暫停當前函數的執行,傳遞控制權和參數給新函數。除了聲明時定義的形式參數,每個函數接收兩個附加的參數:this和arguments。參數this在面向對象編程中非常重要,它的值取決于調用的模式。在JavaScript中一共有4種調用模式:方法調用模式、函數調用模式、構造器調用模式和apply調用模式。這些模式在如何初始化關鍵參數

70、this上存在差異。調用運算符是跟在任何產生一個函數值的表達式之后的一對圓括號,圓括號內可以包含零個或多個用逗號隔開的表達式。每個表達式產生一個參數值。每個參數值被賦予函數聲明時定義的形式參數名。當實際參數(arguments)的個數與形式參數(parameters)的個數不匹配時不會導致運行時錯誤。如果實際參數值過多,那么超出的參數值將被忽略。如果實際參數值過少,那么缺失的值將會被替換為undefined。不會對參數值進行類型檢查,任何類型的值都可以傳遞給參數。(1)方法調用模式當一個函數被保存為對象的一個屬性時,將稱為一個方法。當一個方法被調用時,this被綁定到該對象。如果一個調用表達式

71、包含一個屬性存取表達式(即一個點表達式或subscript下標表達式),那么它被當做一個方法來調用。var obj =     value : 0,    increment : function(inc)         this.value += typeof inc = 'number' ? inc : 1;    obj.increment();document.writeln(obj.value);  / 1obj.increment(2);document.writeln(obj.value); / 3在上面代碼中創建了obj對象,它有一個v

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論