天天看點

了解JavaScript中對象的prototype屬性

一、什麼是JavaScript中對象的prototype屬性

  JavaScript中對象的prototype屬性,是用來傳回對象類型原型的引用的。我們使用prototype屬性提供對象的類的一組基本功能。并且對象的新執行個體會”繼承”賦予該對象原型的操作。但是這個prototype到底是怎麼實作和被管理的呢?

對于對象的prototype屬性的說明,JavaScript手冊上如是說:所有 JavaScript内部對象都有隻讀的 prototype 屬性。可以向其原型中動态添加功能(屬性和方法),但該對象不能被賦予不同的原型。然而,使用者定義的對象可以被賦給新的原型。

  在JavaScript中,prototype對象是實作面向對象的一個重要機制。每個函數就是一個對象(Function),函數對象都有一個子對象prototype對象,類是以函數的形式來定義的。prototype表示該函數的原型,也表示一個類的成員的集合。在通過new建立一個類的執行個體對象的時候,prototype對象的成員都成為執行個體化對象的成員。

  1、該對象被類所引用,隻有函數對象才可引用;

  2、在new執行個體化後,其成員被執行個體化,執行個體對象方可調用。

  同時,函數是一個對象,函數對象若直接聲明成員,不用被執行個體化即可調用。

JavaScript通過一種連結機制來支援繼承,而不是通過完全面向對象語言(如Java)所支援的基于類的繼承模型。每個JavaScript對象都有一個内置的屬性,名為prototype。prototype屬性儲存着對另一個JavaScript對象的引用,這個對象作為目前對象的父對象。 

 

 當通過點記法引用對象的一個函數或屬性時,倘若對象上沒有這個函數或屬性,此時就會使用對象的prototype屬性。當出現這種情況時,将檢查對象prototype屬性所引用的對象,檢視是否有所請求的屬性或函數。如果prototype屬性引用的對象也沒有所需的函數或屬性,則會進一步檢查這個對象(prototype屬性引用的對象)的prototype屬性,依次沿着鍊向上查找,直到找到所請求的函數或屬性,或者到達鍊尾,如果已經到達鍊尾還沒有找到,則傳回undefined。從這個意義上講,這種繼承結構更應是一種“has a”關系,而不是“is a”關系

神啊,我什麼也看懂,怎麼辦?看似搞得我很牛,說實話我也看不懂!^_^ ^_^ ^_^

二、prototype屬性應用執行個體

 我們所常見的類包括:數組變量(Array)、邏輯變量(Boolean)、日期變量(Date)、結構變量(Function)、數值變量(Number)、對象變量(Object)、字元串變量(String) 等,而相關的類的方法,也是程式員經常用到的(在這裡要區分一下類的注意和屬性發方法),例如數組的push方法、日期的get系列方法、字元串的split方法等等,

  但是在實際的程式設計過程中不知道有沒有感覺到現有方法的不足?prototype 方法應運而生!下面,将通過執行個體由淺入深講解 prototype 的具體使用方法:

 先看一個很傻的例子:

JavaScript代碼

function func(){   

    func.prototype.name = “prototype of func”;   

}   

var f = new func();          

alert(f.name);  //prototype of func

 先建立一個func對象,設定func對象的name屬性,執行個體化f;

1.幾個簡單的例子:

(1)數字相加:

Number.prototype.add=function(num){   

    return (this+num);//這裡的this指向Number   

};   

alert((3).add(15));//18  

(2) Boolean.rev(): 作用,布爾變量取反

實作方法:Boolean.prototype.rev = function(){return(!this);}

試驗:alert((true).rev()) -> 顯示 false

2、已有方法的實作和增強,初識 prototype:

(1) Array.push(new_element)

  作用:在數組末尾加入一個新的元素

  實作方法:

  Array.prototype.push = function(new_element){

        this[this.length]=new_element;

        return this.length;

    }

  讓我們進一步來增強他,讓他可以一次增加多個元素!

  Array.prototype.pushPro = function() {

        var currentLength = this.length;

        for (var i = 0; i < arguments.length; i++) {

            this[currentLength + i] = arguments[i];

        }

  應該不難看懂吧?以此類推,你可以考慮一下如何通過增強 Array.pop 來實作删除任意位置,任意多個元素(具體代碼就不再細說了)

3、新功能的實作,深入 prototype:在實際程式設計中所用到的肯定不隻是已有方法的增強,更多的實行的功能的要求,下面我就舉兩個用 prototype 解決實際問題的例子:

(1) String.left()

  問題:用過 vb 的應該都知道left函數,從字元串左邊取 n 個字元,但是不足是将全角、半角均視為是一個字元,造成在中英文混排的版面中不能截取等長的字元串

  作用:從字元串左邊截取 n 個字元,并支援全角半角字元的區分

  String.prototype.left = function(num,mode){

        if(!/\d+/.test(num))return(this);

        var str = this.substr(0,num);

        if(!mode) return str;

        var n = str.Tlength() – str.length;

        num = num – parseInt(n/2);

        return this.substr(0,num);

  試驗:alert(“aa啦啦aa”.left(4)) -> 顯示 aa啦啦

     alert(“aa啦啦aa”.left(4,true)) -> 顯示 aa啦

  本方法用到了上面所提到的String.Tlength()方法,自定義方法之間也能組合出一些不錯的新方法呀!

(2) Date.DayDiff()

  作用:計算出兩個日期型變量的間隔時間(年、月、日、周)

  Date.prototype.DayDiff = function(cDate,mode){

        try{

            cDate.getYear();

        }catch(e){

            return(0);

        var base =60*60*24*1000;

        var result = Math.abs(this – cDate);

        switch(mode){

            case “y”:

                result/=base*365;

                break;

            case “m”:

                result/=base*365/12;

            case “w”:

                result/=base*7;

            default:

                result/=base;

        return(Math.floor(result));

  試驗:alert((new Date()).DayDiff((new Date(2002,0,1)))) -> 顯示 329

     alert((new Date()).DayDiff((new Date(2002,0,1)),”m”)) -> 顯示 10

  當然,也可以進一步擴充,得出響應的小時、分鐘,甚至是秒。

(3) Number.fact()

  作用:某一數字的階乘

  Number.prototype.fact=function(){

        var num = Math.floor(this);

        if(num<0)return NaN;

        if(num==0 || num==1)

            return 1;

        else

            return (num*(num-1).fact());

  試驗:alert((4).fact()) -> 顯示 24

  這個方法主要是說明了遞歸的方法在 prototype 方法中也是可行的!

 執行個體:

取數組的最大值:

var oArr=new Array();   

oArr=[100,190,199,189,3000,400,4001];   

Array.prototype.MAX=function(){   

    var i,max=this[0];   

    for(i=1;i<this.length;i++){   

        if(max<this[i]){   

            max=this[i];   

        }   

    }   

    return max;   

alert(oArr.MAX());  

 執行個體為使用者自定義類添加方法:

function TestObject()   

 {   

     this.m_Name = “ffffffffff”;   

 }   

 TestObject.prototype.ShowName = function()   

     alert(this.m_Name);   

 };   

var f=new TestObject();   

f.ShowName();  

更新自定義類的prototype:

function TestObjectA()   

{   

   this.MethodA = function()   

   {   

      alert(‘TestObjectA.MethodA()’);   

   }   

function TestObjectB()   

   this.MethodB = function()   

      alert(‘TestObjectB.MethodB()’);   

TestObjectB.prototype = new TestObjectA();  

聽說這是錯說中的繼承;哦以後慢慢學。

再看一個例子,估計你我都已經瘋掉了:

function RP()   

    RP.PropertyA = 1;   

    RP.MethodA = function()   

    {   

         alert(“RP.MethodA ”);   

    };   

    this.PropertyA = 100;    

    this.MethodA = function()   

         alert(“this.MethodA”);   

RP.prototype.PropertyA = 10;    

RP.prototype.MethodA = function()   

    alert(“RP.prototype.MethodA”);   

//以下執行   

rp = new RP();   

alert(RP.PropertyA);//警告結果為:1   

RP.MethodA();//警告結果為:RP.MethodA   

alert(rp.PropertyA);//警告結果為:100   

rp.MethodA();//警告結果為:this.MethodA   

delete RP.PropertyA;   

alert(RP.PropertyA);//警告結果為:undefined   

delete rp.PropertyA;   

delete rp.MethodA;   

rp.MethodA();//警告結果為:RP.prototype.MethodA  

 再看一個帶有參數的,計算圓的面積:

        <script type=“text/javascript”>   

function Circle(x,y,r){       

  this.x = x;       

  this.y = y;       

  this.r = r;       

  //this.prototype = null ;     /*這句代碼可以看作是隐含存在的,因為javascript 中“類”的定義和函數的定義結構上沒有差異,是以可以說,所有函數都隐藏有這樣一個屬性。*/       

Circle.prototype.area=function(){   

    return this.r*this.r*3.1415926;   

var Circ=new Circle(0,0,5);   

alert(parseInt(Circ.area()));   

        </script>