上一篇介紹了對象建立的幾種基本方式,今天咱們看分析下對象的繼承。javascript
function Obj1() { this.name1 = "張三"; } function Obj2() { } Obj2.prototype = new Obj1(); var t2 = new Obj2(); alert(t2.name1);
這裏有個明顯的缺點就是:(若是父類的屬性是引用類型,那麼咱們在對象實例修改屬性的時候會把原型中的屬性修改,這樣會在每一個實例對象中改變數據,而這不是咱們想要的效果)html
function Obj1() { this.arr = ["張三"]; } function Obj2() { } Obj2.prototype = new Obj1(); var t2 = new Obj2(); alert(t2.arr);//打印「張三」 t2.arr[t2.arr.length] = "李四"; var t1 = new Obj2(); alert(t1.arr);//打印「張三,李四」
例:java
函數
那咱們怎樣規避這種問題呢?接着往下看。學習
function Obj1() { this.arr = ["張三"]; } function Obj2() { Obj1.call(this);//【1.新增】 } //Obj2.prototype = new Obj1();【2.註釋這行】 var t2 = new Obj2(); alert(t2.arr);//打印「張三」 t2.arr[t2.arr.length] = "李四"; var t1 = new Obj2(); alert(t1.arr);//打印「張三,李四」
咱們看到上面代碼,就註釋了一行,新增了之後。打印出來的效果徹底不同了。如今的arr屬性是每一個實例對象獨有的了。(以前是定義到原型上的,而原型的屬性對每一個實例都是共享的)this
例:spa
.net
一樣,單純的這種方式也是有問題的。由於咱們這樣就沒法繼承對象的方法了。如:prototype
function Obj1() { this.arr = ["張三"]; } Obj1.prototype.sayHi = function () { alert(this.arr); }////【1.新增】 function Obj2() { Obj1.call(this); } var t2 = new Obj2(); //t2裏面是沒有sayHi方法的
咱們可使用原型和構造的混用來解決,以下:code
function Obj1() { this.arr = ["張三"]; } Obj1.prototype.sayHi = function () { alert(this.arr); } function Obj2() { Obj1.call(this); } Obj2.prototype = new Obj1();//【1.新增】 var t2 = new Obj2(); t2.sayHi();
如上,經過構造函數中的 Obj1.call(this); 和設置原型屬性 Obj2.prototype = new Obj1(); 結合使用,完美解決問題。
這裏須要注意一個地方,若是把 Obj2.prototype = new Obj1(); 改爲 Obj2.prototype = Obj1.prototype ; 的話,會有你想不到的問題。如:
function Obj1() { this.arr = ["張三"]; } Obj1.prototype.sayHi = function () { alert(this.arr); } function Obj2() { Obj1.call(this); } Obj2.prototype = Obj1.prototype;//【1.新增】 var t2 = new Obj2(); t2.constructor.prototype.sayHi = function () { alert("test") };//修改Obj2中的原型的方法 var t1 = new Obj1(); t1.sayHi(); //影響到了Obj1中的原型的方法。由於 Obj2.prototype = Obj1.prototype;讓兩個對象的原型指向了同一處。 //因此仍是隻能用Obj2.prototype = new Obj1();
例:
如:
//*************Obj1**** function Obj1() { this.arr = ["張三"]; } Obj1.prototype.sayHi = function () { alert(this.arr); } //*************Obj2**** function Obj2() { Obj1.call(this); this.name = "張三"; } Obj2.prototype = new Obj1(); Obj2.prototype.sayHi2 = function () { alert(this.name); }; //*************Obj3**** function Obj3() { Obj2.call(this); } Obj3.prototype = new Obj2(); Obj3.prototype.sayHi3 = function () { }; //******************* var t3 = new Obj3(); t3.sayHi();
Obj3繼承Obj2,Obj2繼承Obj1。咱們的Obj3的實例對象訪問sayHi的時候,會先去Obj3的實例對象中找sayHi方法(沒找到),而後去Obj3的原型中找(沒找到),而後去父類Obj2的原型中找(沒找到),而後去Obj1的原型中找(找到了)。這個找的路徑就是原型鏈。
(補充分割線20151230)
以上,咱們在說繼承的時候,咱們都是 obj2.prototype = new obj1(); 原型指向父類構造函數。其實這樣有一個問題。如:
function obj1() { this.name2 = "張三"; } obj1.prototype.sayhi = function () { alert(this.name2); } function obj2() { obj1.call(this);//繼承屬性 } obj2.prototype = new obj1(); var obj = new obj2();
咱們看到name2這個屬性,並非咱們想要在prototype中的prototype.name2中繼承過來的。(感受不是那麼幹淨)
然而,咱們能夠:
function obj1() { this.name2 = "張三"; } obj1.prototype.sayhi = function () { alert(this.name2); } function obj2() { obj1.call(this);//繼承屬性 } //obj2.prototype = new obj1(); obj2.prototype = Object.create(obj1.prototype);//繼承原型中的方法【E5中才有的一種新的對象建立方式】 var obj = new obj2();
這是學習記錄,不是教程。文中錯誤不免,您能夠指出錯誤,但請不要言辭刻薄。
原文連接:http://haojima.net/zhaopei/517.html
本文已同步至目錄索引:一步步學習javascript
歡迎上海「程序猿/媛」、"攻城獅"入羣:【滬猿】229082941 入羣須知
歡迎對我的博客感興趣的道友加入羣:【嗨-博客】469075305 入羣須知
若是您以爲文章對您有那麼一點點幫助,那麼麻煩您輕輕的點個贊,以資鼓勵。