亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

悟透JavaScript整理版

 更新時間:2008年03月31日 18:47:11   作者:  
編程世界里只存在兩種基本元素,一個是數(shù)據(jù),一個是代碼。編程世界就是在數(shù)據(jù)和代碼千絲萬縷的糾纏中呈現(xiàn)出無限的生機和活力。

    但要注意的是,用構造函數(shù)操作this對象創(chuàng)建出來的每一個對象,不但具有各自的成員數(shù)據(jù),而且還具有各自的方法數(shù)據(jù)。換句話說,方法的代碼體(體現(xiàn)函數(shù)邏輯的數(shù)據(jù))在每一個對象中都存在一個副本。盡管每一個代碼副本的邏輯是相同的,但對象們確實是各自保存了一份代碼體。上例中的最后一句說明了這一實事,這也解釋了JavaScript中的函數(shù)就是對象的概念。

    同一類的對象各自有一份方法代碼顯然是一種浪費。在傳統(tǒng)的對象語言中,方法函數(shù)并不象JavaScript那樣是個對象概念。即使也有象函數(shù)指針、方法指針或委托那樣的變化形式,但其實質也是對同一份代碼的引用。一般的對象語言很難遇到這種情況。

    不過,JavaScript語言有大的靈活性。我們可以先定義一份唯一的方法函數(shù)體,并在構造this對象時使用這唯一的函數(shù)對象作為其方法,就能共享方法邏輯。例如: 

    其中,最后一行的輸出結果表明兩個對象確實共享了一個函數(shù)對象。雖然,這段程序達到了共享了一份方法代碼的目的,但卻不怎么優(yōu)雅。因為,定義SayHello方法時反映不出其與Person類的關系?!皟?yōu)雅”這個詞用來形容代碼,也不知道是誰先提出來的。不過,這個詞反映了程序員已經(jīng)從追求代碼的正確、高效、可靠和易讀等基礎上,向著追求代碼的美觀感覺和藝術境界的層次發(fā)展,程序人生又多了些浪漫色彩。

   顯然,JavaScript早想到了這一問題,她的設計者們?yōu)榇颂峁┝艘粋€有趣的prototype概念。

初看原型

    prototype源自法語,軟件界的標準翻譯為“原型”,代表事物的初始形態(tài),也含有模型和樣板的意義。JavaScript中的prototype概念恰如其分地反映了這個詞的內含,我們不能將其理解為C++的prototype那種預先聲明的概念。

    JavaScript的所有function類型的對象都有一個prototype屬性。這個prototype屬性本身又是一個object類型的對象,因此我們也可以給這個prototype對象添加任意的屬性和方法。既然prototype是對象的“原型”,那么由該函數(shù)構造出來的對象應該都會具有這個“原型”的特性。事實上,在構造函數(shù)的prototype上定義的所有屬性和方法,都是可以通過其構造的對象直接訪問和調用的。也可以這么說,prototype提供了一群同類對象共享屬性和方法的機制。

    我們先來看看下面的代碼: 

    程序運行的結果表明,構造函數(shù)的prototype上定義的方法確實可以通過對象直接調用到,而且代碼是共享的。顯然,把方法設置到prototype的寫法顯得優(yōu)雅多了,盡管調用形式?jīng)]有變,但邏輯上卻體現(xiàn)了方法與類的關系,相對前面的寫法,更容易理解和組織代碼。

    那么,對于多層次類型的構造函數(shù)情況又如何呢?

    我們再來看下面的代碼: 
 
復制代碼 代碼如下:

1     function Person(name)   //基類構造函數(shù) 
 2     { 
 3         this.name = name; 
 4     }; 
 5      
 6     Person.prototype.SayHello = function()  //給基類構造函數(shù)的prototype添加方法 
 7     { 
 8         alert("Hello, I'm " + this.name); 
 9     }; 
10      
11     function Employee(name, salary) //子類構造函數(shù) 
12     { 
13         Person.call(this, name);    //調用基類構造函數(shù) 
14         this.salary = salary; 
15     }; 
16      
17     Employee.prototype = new Person();  //建一個基類的對象作為子類原型的原型,這里很有意思 
18      
19     Employee.prototype.ShowMeTheMoney = function()  //給子類添構造函數(shù)的prototype添加方法 
20     { 
21         alert(this.name + " $" + this.salary); 
22     }; 
23  
24     var BillGates = new Person("Bill Gates");   //創(chuàng)建基類Person的BillGates對象 
25     var SteveJobs = new Employee("Steve Jobs", 1234);   //創(chuàng)建子類Employee的SteveJobs對象 
26  
27     BillGates.SayHello();       //通過對象直接調用到prototype的方法 
28     SteveJobs.SayHello();       //通過子類對象直接調用基類prototype的方法,關注! 
29     SteveJobs.ShowMeTheMoney(); //通過子類對象直接調用子類prototype的方法 
30  
31     alert(BillGates.SayHello == SteveJobs.SayHello); //顯示:true,表明prototype的方法是共享的 
    這段代碼的第17行,構造了一個基類的對象,并將其設為子類構造函數(shù)的prototype,這是很有意思的。這樣做的目的就是為了第28行,通過子類對象也可以直接調用基類prototype的方法。為什么可以這樣呢?

    原來,在JavaScript中,prototype不但能讓對象共享自己財富,而且prototype還有尋根問祖的天性,從而使得先輩們的遺產(chǎn)可以代代相傳。當從一個對象那里讀取屬性或調用方法時,如果該對象自身不存在這樣的屬性或方法,就會去自己關聯(lián)的prototype對象那里尋找;如果prototype沒有,又會去prototype自己關聯(lián)的前輩prototype那里尋找,直到找到或追溯過程結束為止。

    在JavaScript內部,對象的屬性和方法追溯機制是通過所謂的prototype鏈來實現(xiàn)的。當用new操作符構造對象時,也會同時將構造函數(shù)的prototype對象指派給新創(chuàng)建的對象,成為該對象內置的原型對象。對象內置的原型對象應該是對外不可見的,盡管有些瀏覽器(如Firefox)可以讓我們訪問這個內置原型對象,但并不建議這樣做。內置的原型對象本身也是對象,也有自己關聯(lián)的原型對象,這樣就形成了所謂的原型鏈。

    在原型鏈的最末端,就是Object構造函數(shù)prototype屬性指向的那一個原型對象。這個原型對象是所有對象的最老祖先,這個老祖宗實現(xiàn)了諸如toString等所有對象天生就該具有的方法。其他內置構造函數(shù),如Function, Boolean, String, Date和RegExp等的prototype都是從這個老祖宗傳承下來的,但他們各自又定義了自身的屬性和方法,從而他們的子孫就表現(xiàn)出各自宗族的那些特征。

    這不就是“繼承”嗎?是的,這就是“繼承”,是JavaScript特有的“原型繼承”。

    “原型繼承”是慈祥而又嚴厲的。原形對象將自己的屬性和方法無私地貢獻給孩子們使用,也并不強迫孩子們必須遵從,允許一些頑皮孩子按自己的興趣和愛好獨立行事。從這點上看,原型對象是一位慈祥的母親。然而,任何一個孩子雖然可以我行我素,但卻不能動原型對象既有的財產(chǎn),因為那可能會影響到其他孩子的利益。從這一點上看,原型對象又象一位嚴厲的父親。我們來看看下面的代碼就可以理解這個意思了: 
    
復制代碼 代碼如下:

function Person(name) 
    { 
        this.name = name; 
    }; 

    Person.prototype.company = "Microsoft"; //原型的屬性 

    Person.prototype.SayHello = function()  //原型的方法 
    { 
        alert("Hello, I'm " + this.name + " of " + this.company); 
    }; 

    var BillGates = new Person("Bill Gates"); 
    BillGates.SayHello();   //由于繼承了原型的東西,規(guī)規(guī)矩矩輸出:Hello, I'm Bill Gates 

    var SteveJobs = new Person("Steve Jobs"); 
    SteveJobs.company = "Apple";    //設置自己的company屬性,掩蓋了原型的company屬性 
    SteveJobs.SayHello = function() //實現(xiàn)了自己的SayHello方法,掩蓋了原型的SayHello方法 
    { 
        alert("Hi, " + this.name + " like " + this.company + ", ha ha ha "); 
    }; 

    SteveJobs.SayHello();   //都是自己覆蓋的屬性和方法,輸出:Hi, Steve Jobs like Apple, ha ha ha  

    BillGates.SayHello();   //SteveJobs的覆蓋沒有影響原型對象,BillGates還是按老樣子輸出 
    對象可以掩蓋原型對象的那些屬性和方法,一個構造函數(shù)原型對象也可以掩蓋上層構造函數(shù)原型對象既有的屬性和方法。這種掩蓋其實只是在對象自己身上創(chuàng)建了新的屬性和方法,只不過這些屬性和方法與原型對象的那些同名而已。JavaScript就是用這簡單的掩蓋機制實現(xiàn)了對象的“多態(tài)”性,與靜態(tài)對象語言的虛函數(shù)和重載(override)概念不謀而合。

    然而,比靜態(tài)對象語言更神奇的是,我們可以隨時給原型對象動態(tài)添加新的屬性和方法,從而動態(tài)地擴展基類的功能特性。這在靜態(tài)對象語言中是很難想象的。我們來看下面的代碼: 
  
復制代碼 代碼如下:

  function Person(name) 
    { 
        this.name = name; 
    }; 

    Person.prototype.SayHello = function()  //建立對象前定義的方法 
    { 
        alert("Hello, I'm " + this.name); 
    }; 

    var BillGates = new Person("Bill Gates");   //建立對象 

    BillGates.SayHello(); 

    Person.prototype.Retire = function()    //建立對象后再動態(tài)擴展原型的方法 
    { 
        alert("Poor " + this.name + ", bye bye!"); 
    }; 

    BillGates.Retire(); //動態(tài)擴展的方法即可被先前建立的對象立即調用 
    阿彌佗佛,原型繼承竟然可以玩出有這樣的法術!

原型擴展

    想必君的悟性極高,可能你會這樣想:如果在JavaScript內置的那些如Object和Function等函數(shù)的prototype上添加些新的方法和屬性,是不是就能擴展JavaScript的功能呢?

    那么,恭喜你,你得到了!

    在AJAX技術迅猛發(fā)展的今天,許多成功的AJAX項目的JavaScript運行庫都大量擴展了內置函數(shù)的prototype功能。比如微軟的ASP.NET AJAX,就給這些內置函數(shù)及其prototype添加了大量的新特性,從而增強了JavaScript的功能。

    我們來看一段摘自MicrosoftAjax.debug.js中的代碼: 

復制代碼 代碼如下:

String.prototype.trim = function String$trim() { 
    if (arguments.length !== 0) throw Error.parameterCount(); 
    return this.replace(/^\s+|\s+$/g, ''); 


    這段代碼就是給內置String函數(shù)的prototype擴展了一個trim方法,于是所有的String類對象都有了trim方法了。有了這個擴展,今后要去除字符串兩段的空白,就不用再分別處理了,因為任何字符串都有了這個擴展功能,只要調用即可,真的很方便。

    當然,幾乎很少有人去給Object的prototype添加方法,因為那會影響到所有的對象,除非在你的架構中這種方法的確是所有對象都需要的。

    前兩年,微軟在設計AJAX類庫的初期,用了一種被稱為“閉包”(closure)的技術來模擬“類”。其大致模型如下: 
  
復制代碼 代碼如下:

  function Person(firstName, lastName, age) 
    { 
        //私有變量: 
        var _firstName = firstName; 
        var _lastName = lastName; 

        //公共變量: 
        this.age = age; 

        //方法: 
        this.getName = function() 
        { 
            return(firstName + " " + lastName); 
        }; 
        this.SayHello = function() 
        { 
            alert("Hello, I'm " + firstName + " " + lastName); 
        }; 
    }; 

    var BillGates = new Person("Bill", "Gates", 53); 
    var SteveJobs = new Person("Steve", "Jobs", 53); 

    BillGates.SayHello(); 
    SteveJobs.SayHello(); 
    alert(BillGates.getName() + " " + BillGates.age); 
    alert(BillGates.firstName);     //這里不能訪問到私有變量 

    很顯然,這種模型的類描述特別象C#語言的描述形式,在一個構造函數(shù)里依次定義了私有成員、公共屬性和可用的方法,顯得非常優(yōu)雅嘛。特別是“閉包”機制可以模擬對私有成員的保護機制,做得非常漂亮。

    所謂的“閉包”,就是在構造函數(shù)體內定義另外的函數(shù)作為目標對象的方法函數(shù),而這個對象的方法函數(shù)反過來引用外層外層函數(shù)體中的臨時變量。這使得只要目標對象在生存期內始終能保持其方法,就能間接保持原構造函數(shù)體當時用到的臨時變量值。盡管最開始的構造函數(shù)調用已經(jīng)結束,臨時變量的名稱也都消失了,但在目標對象的方法內卻始終能引用到該變量的值,而且該值只能通這種方法來訪問。即使再次調用相同的構造函數(shù),但只會生成新對象和方法,新的臨時變量只是對應新的值,和上次那次調用的是各自獨立的。的確很巧妙!

    但是前面我們說過,給每一個對象設置一份方法是一種很大的浪費。還有,“閉包”這種間接保持變量值的機制,往往會給JavaSript的垃圾回收器制造難題。特別是遇到對象間復雜的循環(huán)引用時,垃圾回收的判斷邏輯非常復雜。無獨有偶,IE瀏覽器早期版本確實存在JavaSript垃圾回收方面的內存泄漏問題。再加上“閉包”模型在性能測試方面的表現(xiàn)不佳,微軟最終放棄了“閉包”模型,而改用“原型”模型。正所謂“有得必有失”嘛。

    原型模型需要一個構造函數(shù)來定義對象的成員,而方法卻依附在該構造函數(shù)的原型上。大致寫法如下: 
    
復制代碼 代碼如下:

//定義構造函數(shù) 
    function Person(name) 
    { 
        this.name = name;   //在構造函數(shù)中定義成員 
    }; 

    //方法定義到構造函數(shù)的prototype上 
    Person.prototype.SayHello = function() 
    { 
        alert("Hello, I'm " + this.name); 
    };     

    //子類構造函數(shù) 
    function Employee(name, salary) 
    { 
        Person.call(this, name);    //調用上層構造函數(shù) 
        this.salary = salary;       //擴展的成員 
    }; 

    //子類構造函數(shù)首先需要用上層構造函數(shù)來建立prototype對象,實現(xiàn)繼承的概念 
    Employee.prototype = new Person()   //只需要其prototype的方法,此對象的成員沒有任何意義! 

    //子類方法也定義到構造函數(shù)之上 
    Employee.prototype.ShowMeTheMoney = function() 
    { 
        alert(this.name + " $" + this.salary); 
    }; 

    var BillGates = new Person("Bill Gates"); 
    BillGates.SayHello();     

    var SteveJobs = new Employee("Steve Jobs", 1234); 
    SteveJobs.SayHello(); 
    SteveJobs.ShowMeTheMoney(); 
    原型類模型雖然不能模擬真正的私有變量,而且也要分兩部分來定義類,顯得不怎么“優(yōu)雅”。不過,對象間的方法是共享的,不會遇到垃圾回收問題,而且性能優(yōu)于“閉包”模型。正所謂“有失必有得”嘛。

    在原型模型中,為了實現(xiàn)類繼承,必須首先將子類構造函數(shù)的prototype設置為一個父類的對象實例。創(chuàng)建這個父類對象實例的目的就是為了構成原型鏈,以起到共享上層原型方法作用。但創(chuàng)建這個實例對象時,上層構造函數(shù)也會給它設置對象成員,這些對象成員對于繼承來說是沒有意義的。雖然,我們也沒有給構造函數(shù)傳遞參數(shù),但確實創(chuàng)建了若干沒有用的成員,盡管其值是undefined,這也是一種浪費啊。

    唉!世界上沒有完美的事情??!

原型真諦

    正當我們感概萬分時,天空中一道紅光閃過,祥云中出現(xiàn)了觀音菩薩。只見她手持玉凈瓶,輕拂翠柳枝,灑下幾滴甘露,頓時讓JavaScript又添新的靈氣。

    觀音灑下的甘露在JavaScript的世界里凝結成塊,成為了一種稱為“語法甘露”的東西。這種語法甘露可以讓我們編寫的代碼看起來更象對象語言。

    要想知道這“語法甘露”為何物,就請君側耳細聽。

    在理解這些語法甘露之前,我們需要重新再回顧一下JavaScript構造對象的過程。

    我們已經(jīng)知道,用 var anObject = new aFunction() 形式創(chuàng)建對象的過程實際上可以分為三步:第一步是建立一個新對象;第二步將該對象內置的原型對象設置為構造函數(shù)prototype引用的那個原型對象;第三步就是將該對象作為this參數(shù)調用構造函數(shù),完成成員設置等初始化工作。對象建立之后,對象上的任何訪問和操作都只與對象自身及其原型鏈上的那串對象有關,與構造函數(shù)再扯不上關系了。換句話說,構造函數(shù)只是在創(chuàng)建對象時起到介紹原型對象和初始化對象兩個作用。

    那么,我們能否自己定義一個對象來當作原型,并在這個原型上描述類,然后將這個原型設置給新創(chuàng)建的對象,將其當作對象的類呢?我們又能否將這個原型中的一個方法當作構造函數(shù),去初始化新建的對象呢?例如,我們定義這樣一個原型對象: 

   
復制代碼 代碼如下:

 var Person =  //定義一個對象來作為原型類 
    { 
        Create: function(name, age)  //這個當構造函數(shù) 
        { 
            this.name = name; 
            this.age = age; 
        }, 
        SayHello: function()  //定義方法 
        { 
            alert("Hello, I'm " + this.name); 
        }, 
        HowOld: function()  //定義方法 
        { 
            alert(this.name + " is " + this.age + " years old."); 
        } 
    }; 
    這個JSON形式的寫法多么象一個C#的類啊!既有構造函數(shù),又有各種方法。如果可以用某種形式來創(chuàng)建對象,并將對象的內置的原型設置為上面這個“類”對象,不就相當于創(chuàng)建該類的對象了嗎?

    但遺憾的是,我們幾乎不能訪問到對象內置的原型屬性!盡管有些瀏覽器可以訪問到對象的內置原型,但這樣做的話就只能限定了用戶必須使用那種瀏覽器。這也幾乎不可行。

    那么,我們可不可以通過一個函數(shù)對象來做媒介,利用該函數(shù)對象的prototype屬性來中轉這個原型,并用new操作符傳遞給新建的對象呢?

    其實,象這樣的代碼就可以實現(xiàn)這一目標:

    function anyfunc(){};           //定義一個函數(shù)軀殼
    anyfunc.prototype = Person;     //將原型對象放到中轉站prototype
    var BillGates = new anyfunc();  //新建對象的內置原型將是我們期望的原型對象
    不過,這個anyfunc函數(shù)只是一個軀殼,在使用過這個軀殼之后它就成了多余的東西了,而且這和直接使用構造函數(shù)來創(chuàng)建對象也沒啥不同,有點不爽。

    可是,如果我們將這些代碼寫成一個通用函數(shù),而那個函數(shù)軀殼也就成了函數(shù)內的函數(shù),這個內部函數(shù)不就可以在外層函數(shù)退出作用域后自動消亡嗎?而且,我們可以將原型對象作為通用函數(shù)的參數(shù),讓通用函數(shù)返回創(chuàng)建的對象。我們需要的就是下面這個形式: 

 
復制代碼 代碼如下:

   function New(aClass, aParams)    //通用創(chuàng)建函數(shù) 
    { 
        function new_()     //定義臨時的中轉函數(shù)殼 
        { 
            aClass.Create.apply(this, aParams);   //調用原型中定義的的構造函數(shù),中轉構造邏輯及構造參數(shù) 
        }; 
        new_.prototype = aClass;    //準備中轉原型對象 
        return new new_();          //返回建立最終建立的對象 
    }; 

    var Person =        //定義的類 
    { 
        Create: function(name, age) 
        { 
            this.name = name; 
            this.age = age; 
        }, 
        SayHello: function() 
        { 
            alert("Hello, I'm " + this.name); 
        }, 
        HowOld: function() 
        { 
            alert(this.name + " is " + this.age + " years old."); 
        } 
    }; 

    var BillGates = New(Person, ["Bill Gates", 53]);  //調用通用函數(shù)創(chuàng)建對象,并以數(shù)組形式傳遞構造參數(shù) 
    BillGates.SayHello(); 
    BillGates.HowOld(); 

    alert(BillGates.constructor == Object);     //輸出:true 

    這里的通用函數(shù)New()就是一個“語法甘露”!這個語法甘露不但中轉了原型對象,還中轉了構造函數(shù)邏輯及構造參數(shù)。

    有趣的是,每次創(chuàng)建完對象退出New函數(shù)作用域時,臨時的new_函數(shù)對象會被自動釋放。由于new_的prototype屬性被設置為新的原型對象,其原來的原型對象和new_之間就已解開了引用鏈,臨時函數(shù)及其原來的原型對象都會被正確回收了。上面代碼的最后一句證明,新創(chuàng)建的對象的constructor屬性返回的是Object函數(shù)。其實新建的對象自己及其原型里沒有constructor屬性,那返回的只是最頂層原型對象的構造函數(shù),即Object。

    有了New這個語法甘露,類的定義就很像C#那些靜態(tài)對象語言的形式了,這樣的代碼顯得多么文靜而優(yōu)雅??!

    當然,這個代碼僅僅展示了“語法甘露”的概念。我們還需要多一些的語法甘露,才能實現(xiàn)用簡潔而優(yōu)雅的代碼書寫類層次及其繼承關系。好了,我們再來看一個更豐富的示例吧: 

 
復制代碼 代碼如下:

   //語法甘露: 
    var object =    //定義小寫的object基本類,用于實現(xiàn)最基礎的方法等 
    { 
        isA: function(aType)   //一個判斷類與類之間以及對象與類之間關系的基礎方法 
        { 
            var self = this; 
            while(self) 
            { 
                if (self == aType) 
                  return true; 
                self = self.Type; 
            }; 
            return false; 
        } 
    }; 

    function Class(aBaseClass, aClassDefine)    //創(chuàng)建類的函數(shù),用于聲明類及繼承關系 
    { 
        function class_()   //創(chuàng)建類的臨時函數(shù)殼 
        { 
            this.Type = aBaseClass;    //我們給每一個類約定一個Type屬性,引用其繼承的類 
            for(var member in aClassDefine) 
                this[member] = aClassDefine[member];    //復制類的全部定義到當前創(chuàng)建的類 
        }; 
        class_.prototype = aBaseClass; 
        return new class_(); 
    }; 

    function New(aClass, aParams)   //創(chuàng)建對象的函數(shù),用于任意類的對象創(chuàng)建 
    { 
        function new_()     //創(chuàng)建對象的臨時函數(shù)殼 
        { 
            this.Type = aClass;    //我們也給每一個對象約定一個Type屬性,據(jù)此可以訪問到對象所屬的類 
            if (aClass.Create) 
              aClass.Create.apply(this, aParams);   //我們約定所有類的構造函數(shù)都叫Create,這和DELPHI比較相似 
        }; 
        new_.prototype = aClass; 
        return new new_(); 
    }; 

    //語法甘露的應用效果:     
    var Person = Class(object,      //派生至object基本類 
    { 
        Create: function(name, age) 
        { 
            this.name = name; 
            this.age = age; 
        }, 
        SayHello: function() 
        { 
            alert("Hello, I'm " + this.name + ", " + this.age + " years old."); 
        } 
    }); 

    var Employee = Class(Person,    //派生至Person類,是不是和一般對象語言很相似? 
    { 
        Create: function(name, age, salary) 
        { 
            Person.Create.call(this, name, age);  //調用基類的構造函數(shù) 
            this.salary = salary; 
        }, 
        ShowMeTheMoney: function() 
        { 
            alert(this.name + " $" + this.salary); 
        } 
    }); 

    var BillGates = New(Person, ["Bill Gates", 53]); 
    var SteveJobs = New(Employee, ["Steve Jobs", 53, 1234]); 
    BillGates.SayHello(); 
    SteveJobs.SayHello(); 
    SteveJobs.ShowMeTheMoney(); 

    var LittleBill = New(BillGates.Type, ["Little Bill", 6]);   //根據(jù)BillGate的類型創(chuàng)建LittleBill 
    LittleBill.SayHello(); 

    alert(BillGates.isA(Person));       //true 
    alert(BillGates.isA(Employee));     //false 
    alert(SteveJobs.isA(Person));       //true 
    alert(Person.isA(Employee));        //false 
    alert(Employee.isA(Person));        //true 

    “語法甘露”不用太多,只要那么一點點,就能改觀整個代碼的易讀性和流暢性,從而讓代碼顯得更優(yōu)雅。有了這些語法甘露,JavaScript就很像一般對象語言了,寫起代碼了感覺也就爽多了!

    令人高興的是,受這些甘露滋養(yǎng)的JavaScript程序效率會更高。因為其原型對象里既沒有了毫無用處的那些對象級的成員,而且還不存在constructor屬性體,少了與構造函數(shù)間的牽連,但依舊保持了方法的共享性。這讓JavaScript在追溯原型鏈和搜索屬性及方法時,少費許多工夫啊。

    我們就把這種形式稱為“甘露模型”吧!其實,這種“甘露模型”的原型用法才是符合prototype概念的本意,才是的JavaScript原型的真諦!

    想必微軟那些設計AJAX架構的工程師看到這個甘露模型時,肯定后悔沒有早點把AJAX部門從美國搬到咱中國的觀音廟來,錯過了觀音菩薩的點化。當然,我們也只能是在代碼的示例中,把Bill Gates當作對象玩玩,真要讓他放棄上帝轉而皈依我佛肯定是不容易的,機緣未到??!如果哪天你在微軟新出的AJAX類庫中看到這種甘露模型,那才是真正的緣分!

編程的快樂

    在軟件工業(yè)迅猛發(fā)展的今天,各式各樣的編程語言層出不窮,新語言的誕生,舊語言的演化,似乎已經(jīng)讓我們眼花繚亂。為了適應面向對象編程的潮流,JavaScript語言也在向完全面向對象的方向發(fā)展,新的JavaScript標準已經(jīng)從語義上擴展了許多面向對象的新元素。與此相反的是,許多靜態(tài)的對象語言也在向JavaScript的那種簡潔而幽雅的方向發(fā)展。例如,新版本的C#語言就吸收了JSON那樣的簡潔表示法,以及一些其他形式的JavaScript特性。

    我們應該看到,隨著RIA(強互聯(lián)應用)的發(fā)展和普及,AJAX技術也將逐漸淡出江湖,JavaScript也將最終消失或演化成其他形式的語言。但不管編程語言如何發(fā)展和演化,編程世界永遠都會在“數(shù)據(jù)”與“代碼”這千絲萬縷的糾纏中保持著無限的生機。只要我們能看透這一點,我們就能很容易地學習和理解軟件世界的各種新事物。不管是已熟悉的過程式編程,還是正在發(fā)展的函數(shù)式編程,以及未來量子糾纏態(tài)的大規(guī)模并行式編程,我們都有足夠的法力來化解一切復雜的難題。

    佛最后淡淡地說:只要我們放下那些表面的“類”,放下那些對象的“自我”,就能達到一種“對象本無根,類型亦無形”的境界,從而將自我融入到整個宇宙的生命輪循環(huán)中。我們將沒有自我,也沒有自私的欲望,你就是我,我就是你,你中有我,我中有你。這時,我們再看這生機勃勃的編程世界時,我們的內心將自然生起無限的慈愛之心,這種慈愛之心不是虛偽而是真誠的。關愛他人就是關愛自己,就是關愛這世界中的一切。那么,我們的心是永遠快樂的,我們的程序是永遠快樂的,我們的類是永遠快樂的,我們的對象也是永遠快樂的。這就是編程的極樂!

    說到這里,在座的比丘都猶如醍醐灌頂,心中豁然開朗??纯醋筮呥@位早已喜不自禁,再看看右邊那位也是心花怒放。

    驀然回首時,唯見君拈花微笑...

原著:李戰(zhàn)(leadzen).深圳 2008-2-23
打包文件下載

相關文章

最新評論