標籤:拷貝 大神 好處 cto www 文章 bridge 地址 func
上一篇隨筆講了封裝,這一篇我們說說繼承,還是那上一篇貓和狗說事兒
function Dog(name,s){ this.name=name; this.sex=s;}Dog.prototype.type="犬科";Dog.prototype.spack==function(){ alert("汪汪。。。");} function Cat(name,s){ this.name=name; this.sex=s;}Cat.prototype.type="貓科";Cat.prototype.spack=function(){ alert("喵喵。。。");}
當然貓和狗都是動物,那他們就有動物的屬性,比如需要吃東西,需要呼吸,喝水等等。
現在我們封裝一個動物對象:
function Animal(){ this.eat="true"; this.breath="true";
this.name="動物"; }Animal.prototype.drink=function(){
alert("喝水");
};
現在我們需要讓貓的對象繼承於動物對象的一些屬性呢,我們只需要將父物件的屬性綁定到子物件上就能讓子物件享受父物件的屬性和方法,代碼如下:
function Dog(name,s){ Animal.apply(this, arguments); this.name=name; this.sex=s;}function Cat(name,s){ Animal.apply(this, arguments); this.name=name; this.sex=s;}
當然這種方法也是最簡單的,還有別的方法:我們可以用prototype來實現,代碼如下
function Dog(name,s){ this.name=name; this.sex=s;}Dog.prototype = new Animal();
Dog.prototype.constructor = Dog;Dog.prototype.type="犬科";Dog.prototype.spack==function(){ alert("汪汪。。。");}
這樣就讓貓和狗都繼承了動物的屬性和方法了,讓我們仔細剖析一下這種方式,在將new Animal()賦給Cat.prototype後,
function Cat(name,s){ this.name=name; this.sex=s;}Cat.prototype = new Animal();console.log(Cat.prototype);Cat.prototype.type="貓科";Cat.prototype.spack=function(){ alert("喵喵。。。");}
控制台輸出
Animal { breath:"true" eat:"true" spack:function () type:"貓科" __proto__:Object}
開啟—proto—,我們看到:
__proto__:Object drink:function () constructor:function Animal() arguments:null caller:null length:0 name:"Animal" prototype:Object __proto__:function () [[FunctionLocation]]:test1.html:6 [[Scopes]]:Scopes[1] __proto__:Objec
我們在代碼裡輸出一下:
alert(cat1.constructor == Animal); // true
我們很明顯發現constructor指向的是Animal(),在程式中它本應該指向Cat();當我們加入Cat.prototype.constructor = Cat,開啟constructor再看時發現
constructor:function Cat(name,s)
有人會說我沒家這句話難道不行嗎,我沒加上述代碼程式照樣繼承了父物件的屬性和方法,當然在這種小案例中有可能會行,但是在大項目中這樣寫代碼會在造成繼承紊亂,造成不可預知的錯誤,所以我麼需要手動調整Cat.prototype.constructor的值,所以我們在程式中如果給prototype賦值,那麼下一步必須是將對象.prototype.constructor的值重新指回到原對建構函式。
當然我們也可以讓子建構函式直接繼承父建構函式的prototype,代碼如下:
function Cat(name,s){ this.name=name; this.sex=s;}Cat.prototype = Animal.prototype;console.log(Cat.prototype);Cat.prototype.type="貓科";Cat.prototype.spack=function(){ alert("喵喵。。。");}
這種方法好處是高效,不需要重新在建立一個對象,當然缺點也很明顯,此刻Animate.prototype和Cat.prototype指向同意資料來源,不加Cat.prototype.constructor = Cat時Cat.prototype輸出Animal(),加了之後Cat.prototype輸出Cat(),貌似對了,可是Animal.prototype此刻居然也輸出Cat(),原因是此刻Animate.prototype和Cat.prototype指向同意資料來源,當Cat.prototype做出修改時事實上該的是它倆的資料來源,所以,這種方法不可取。
當然我們還可以通過中間量的思路解決這個問題,代碼如下:
function Bridge(){}bridge.prototype=Animal.prototype;Cat.prototype=new Bridge();Cat.prototype.constructor = Cat;
此刻Bridgr沒有添加新的方法和屬性,所以它幾乎不佔記憶體,而同時我們對prototype進行修改也不會影響其父級對象的prototype
我們將上述代碼封裝成一個函數,以備使用:
function brideg(p,s){ var F=function(){}; F.prototype=p.prototype; s.prototype = new F(); s.pprototype.constructor= s; s.uber= p.prototype; }
此處uper為子物件添加一個屬性,這個屬性直接指向父物件的prototype,這等於在子物件上開啟一條通道,可以直接調用父物件的方法。
extend(Cat,Animal);var cat1 = new Cat("咪咪","雄");alert(cat1.name); // 動物
還有一種繼承思路,就是將父物件的所有屬性全部拷貝給子屬性,那麼就相當於子物件繼承於父物件了
代碼如下
function extend(p,s){ var p1=p.prototype; var s1=s.prototype; for(var i in p1){ s1[i]=p1[i]; } s1.uper=p1; }
調用如下:
extend2(,Animal, Cat);var cat1 = new Cat("咪咪","雄");alert(cat1.name); // 動物
--------------------------------------------------------我是分割線-------------------------------------------------------------
本文參考阮大神文章,地址:
http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance.html
js物件導向(二)——繼承