標籤:基本 div 存在 修改 影響 function 同名 自訂類 包含
原型對象也不是沒有缺點。首先,它省略了為建構函式傳遞初始化參數這一環節, 結果所有執行個體在預設情況下都將取得相同的屬性值。雖然這會在某種程度上帶來一些不方便, 但還不是原型對象的最大問題。原型對象的最大問題是由其共用的本性所導致的。
原型中所有屬性是被很多執行個體共用的,這種共用對於函數非常合適。對於那些包含基本值的屬性倒也說得過去,畢竟(如前面的例子所示),通過在執行個體上添加個同名屬性, 可以隱藏原型中的對應屬性。然而,對於包含參考型別值的屬性來說,問題就比較突出了。來看下面的例子。
function Person() {}Person.prototype={ constructor: Person, name : "Nicholas" , age : 29, job : "Software Engineer", friends : ["Shelby", "Court"] , sayName : function (){ alert(this.name ) ; }};var person1 = new Person();var person2 = new Person();person1.friends.push("Van");alert(person1.friends); //”Shelby, Court, Van"alert(person2.friends); //”Shelby, Court, Van"alert(person1.friends === person2.friends); //true
在此,Person.prototype對象有一個名為frends的屬性,該屬性包含一個字串數組。然後,建立了Person的兩個執行個體。接著修改了person1.friends引用的數組,向數組中添加了一個字串。由於friends數組存在於Person.prototype而非person1中,所以剛剛的修改也會通過person2.friends(與person1.friends指向同一個數組)反應出來。假如我們的初衷就是像這樣在所有執行個體中共用一個數組,那就沒什麼好說的。可是,執行個體一般都是要有屬於自己的全部屬性的。而這個問題正是我們很少看到有人單獨使用原型的原因。
建立自訂類型的最常見方式,就是組合使用建構函式與原型。建構函式用於定義執行個體屬性,而原型用於定義方法和共用的屬性。結果,每個執行個體都會有自己的一份執行個體屬性的副本,但同時又共用著對方法的引用,最大限度地節省了記憶體。下面的代碼重寫了前面的例子。
function Person(name, age, job) { this.name = name; this.age = age; this.job = job; this.friends = ["Shelby","Court"];}Person.prototype = { constructor : Person, sayName : function() { alert(this.name); }}var person1 = new Person("Nicholas", 29,"Software Engineer");var person2 = new Person("Greg", 27, "Doctor");person1.friends.push ("Van");alert(person1.friends); //"Shelby, Count ,Van"alert(person2.friends); //"She1 by,Count"alert(person1.friends === person2.friends); //falsealert(person1.sayName === person2.sayName); //true
在這個例子中,執行個體屬性都是在建構函式中定義的,而由所有執行個體共用的屬性constructor和方法sayName()則是在原型中定義的。而修改了person1.friends (向其中添加一個新字串),並不會影響到person2.friends,因為它們分別引用了不同的數組。
這種建構函式與原型混成的模式,是目前在ECMAScript中使用最廣泛、認同度最高的一種建立自訂類型的方法。可以說,這是用來定義參考型別的一種預設模式。
JavaScript 原型鏈學習(三)原型對象存在的問題 與 組合使用建構函式和原型