JavaScript進階程式設計 擴充–關於動態原型

來源:互聯網
上載者:User

但是作者Nicholas C. Zakas在【動態原型】方式建立對象的時候沒有深究可能會存在的問題和解決方案。而僅僅在繼承的時候對【動態原型】的瓶頸作了說明。即在作子類繼承的時候,不能通過動態原型的方式來實現。
  原文大致如下:
繼承機制不能採用動態化的原因是:prototype對象的唯一性。執行個體代碼: 複製代碼 代碼如下:function A (i) {
this.a = i;
if (typeof A._init == 'undefined') {
A.prototype.func = function () {
return 0;
}
A._init = 1;
}
}
function subA (j) {
A.call(this, 1);
this.j = j;
if (typeof subA._init == 'undefined') {
subA.prototype = new A();
subA.prototype.func_sub = function () {
return ++j;
}
subA._init = 1;
}
}
var sub_a = new subA(1);
alert(sub_a.func_sub()); //error: sub_a.func_sub is not a function

Nicholas解釋說在代碼運行前,對象已被執行個體,並與prototype聯絡,在當前對prototype對象替換不會對它產生任何影響,即當前的替換是訪問不到的,只有未來對象的執行個體才會反映出這種改變。於是第一個執行個體對象就會不正確。但第二個及以後的子類執行個體都沒問題。
解決方案就是在建構函式外賦予新的prototype對象: 複製代碼 代碼如下:function A (i) {
this.a = i;
if (typeof A._init == 'undefined') {
A.prototype.func = function () {
return 0;
}
A._init = 1;
}
}
function subA (j) {
A.call(this, 1);
this.j = j;
if (typeof subA._init == 'undefined') {
subA.prototype.func_sub = function () {
return ++j;
}
subA._init = 1;
}
}
subA.prototype = new A();
var sub_a = new subA(1);
alert(sub_a.func_sub()); //2

可惜這違反了我們為什麼使用動態原型的初衷。
使用動態原型的初衷本來就是要讓建構函式能“統一江山”,在視覺上讓人覺得原型方法是類構造的一部分。
  以上是《JavaScript進階程式設計》中對動態原型繼承小節的大概內容。
<! -- ========== 分割線 ============ -->
  可是Nicholas在先前的章節講物件建構的【動態原型】方式中,似乎忘了提這個同樣的問題。我們看看上文中最後一個例子: 複製代碼 代碼如下:var Obj = function (name) {
this.name = name;
this.flag = new Array('A', 'B');
if (typeof Obj._init == 'undefined') {
Obj.prototype = {
showName : function () {
alert(this.name);
}
};
Obj._init = true;
}
}
var obj1 = new Obj('aa');
var obj2 = new Obj('bb');
obj1.showName(); //error: is not a function
obj2.showName(); // bb;

是的,這個問題其實和子類繼承中出現的問題如出一轍,prototype在當前的替換是不會對該對象有任何影響的,只有在未來的執行個體中可見。如果按照Nicholas處理動態原型繼承的方式中說的一樣,那就意味著只能在建構函式外邊重新賦予prototype對象。那麼這不就成了【建構函式/原型混合】方式了嗎?所謂的【動態原型】方式也就不存在了...

  其實我們可以想想,為什麼在【建構函式/原型混合】這種已經基本沒有副作用的構建對象方式後面還要在寫一節【動態原型】方式。作者的意圖無非就是想讓建構函式在視覺上更為統一麼。其實僅僅要視覺上的統一可以不用動態原型的。 複製代碼 代碼如下:var Obj = function () {
function __initialize (name) {
this.name = name;
this.flag = new Array('A', 'B');
}
__initialize.prototype = {
showName : function () {
alert(this.name);
},
showFlag : function () {
alert(this.flag);
}
}
return __initialize;
}();
var obj1 = new Obj('aa');
var obj2 = new Obj('bb');
obj1.showName(); // aa
obj2.showName(); // bb

其實上面的方式就可以算是視覺的統一了,Obj的建構函式內通過__initialize來初始化屬性,通過__initialize.prototype原型初始化方法。只不過稍微有點“小作弊”的感覺,__initialize代理了Obj的初始化...
  下面是來自tangoboy的“構造類”的封裝,其實思路和上面基本一致,唯一不同的是他把屬性也用原型方式建立了,同時把初始化屬性和方法都扔到了建構函式參數對象裡。方便自訂: 複製代碼 代碼如下:/* == form tangoboy == */
window['$Class'] = {
//建立一個類 混合建構函式/原型方式
create: function(config) {
var obj = function(){},config = config||{};
//過濾構造方法和原型方法
obj = obj.prototype.constructor = config["__"]||obj;
delete config["__"];
obj.prototype = config;
return obj;
}
}
/* -- eg -- */
var man = $Class.create({
__ : function (name) {
this.name = name;
},
sex : 'male',
showName : function () {
alert(this.name);
}
});
var me = new man('ru');
me.showName(); //ru

其實如果硬要追求視覺的統一也可以不用動態原型的方式。說到底看看上面的思路,已經回溯到了我們最常用的“類構造”方式: 複製代碼 代碼如下:var Class = {
create : function () {
return function () {
this.initialize.apply(this, arguments);
}
}
}

相信上面這段代碼大家或許都不會陌生,如果細究下去,會發現其實和上面的代碼都一致,用initialize函數作了初始化的代理,從而完成了視覺的統一。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.