js面向物件 繼承
阿新 • • 發佈:2018-12-26
1、類的宣告
2、生成例項
3、如何實現繼承
4、繼承的幾種方式
缺點:這個建構函式是有自己的原型鏈的,也就是有自己的prototype屬性,雖然說Parent1的屬性指向了Child1這個例項,但是他的prototype並沒有被Child1所繼承。比如說
2)
<script type="text/javascript"> //類的宣告 function Animal() { this.name = 'name' } // es6中的class的宣告 class Animal2 { constructor() { this.name = name } } </script>
2、怎麼例項化這個物件
console.log(new Animal(), newAnimal2());
3、js有幾種繼承方式 1)
/** * 藉助建構函式實現繼承 */ function Parent1() { this.name = 'parent1' } function Child1() { Parent1.call(this); this.type = 'child1'; } console.log(new Child1());這樣就實現了一個繼承了。重點看這個Parent1.call,他改變了js執行的上下文,通過這個呼叫,改變了Parent1的this指向。也就是父類的所有屬性都指向了子類的這個例項
function Parent1() { this.name = 'parent1' } Parent1.prototype.say = function(){};看下,是沒有say方法的,說明不會繼承父類的原型鏈,所以說,這種繼承只是部分繼承,如果父類還有一些方法,就拿不到
function Child1() { Parent1.call(this); this.type = 'child1'; } console.log(new Child1());
/** * 藉助原型鏈實現即成 */ function Parent2() { this.name = "parent2"; } function Child2() { this.type = "child2" } Child2.prototype = new Parent2(); console.log(new Child2());這個方法彌補第一種方式的不足,我們說任何一個建構函式都有一個prototype這個屬性的,這個屬性的作用是訪問他的例項能訪問到原型物件上。 如圖,我們看到Child2的__proto__指向的是Parent2的原型物件,prototype是Child2的一個屬性,這個屬性是個物件,將new Parent2()這個物件賦值給了Child2,那麼new一個Child2後,訪問Child2.name,在Child2裡面沒有找到,就會去__proto__找,也就是prototype找,也就是Parent2這個例項找,這樣就實現了繼承
這個繼承方式的缺點:在Parent2裡面新增,this.play = [1,2,3];,然後new多個Child2的例項,發現他們都指向了同一個play。當s1改變了play,第二個物件跟著被改變了 比如
/** * 藉助原型鏈實現即成 */ function Parent2() { this.name = "parent2"; this.play = [1,2,3] } function Child2() { this.type = "child2" } Child2.prototype = new Parent2(); var s1 = new Child2(); var s2 = new Child2(); s1.play.push(4); console.log(s1.play,s2.play);
3)
/** * 組合方式(結合建構函式 和 原型鏈的優點) */ function Parent3 () { this.name = 'parent3'; } function Child3 () { Parent3.call(this); this.type = 'child3' } Child3.prototype = new Parent3();
我們再加上方法,看看是否能避免上面的問題呢
/** * 組合方式(結合建構函式 和 原型鏈的優點) */ function Parent3 () { this.name = 'parent3'; this.play = [1,2,3]; } function Child3 () { Parent3.call(this); this.type = 'child3' }
Child3.prototype = new Parent3(); var s3 = new Child3(); var s4 = new Child3(); s3.play.push(4); console.log(s3.play,s4.play);
這個時候發現就不一樣了,避免了eg2的缺點,這種組合方式結合了優點,彌補了缺點,這是通常實現繼承的方式
缺點:執行了兩次父類的原型鏈,第一次Parent2.call()。第二次 new Parent3()
4)
/** * 組合繼承的優化 */ function Parent4 () { this.name = 'parent4'; this.play = [1,2,3]; } function Child4 () { Parent4.call(this); this.type = 'child4' } Child4.prototype = Parent4.prototype; var s5 = new Child4(); var s6 = new Child4();
這樣父類的原型鏈只執行了一次,但是還剩下一個問題,s5,s6都是父類的例項,沒有自己的例項,prototype裡面有個contron指明是哪個的例項,而子類的prototype拿的直接是父類的prototype,所以當然拿的是父類的建構函式
/** * 組合繼承的優化2 */ function Parent5 () { this.name = 'parent5'; this.play = [1,2,3]; } function Child5 () { Parent5.call(this); this.type = 'child5' } Child5.prototype = Object.create(Parent5.prototype); Child5.prototype.constructor = Child5;
Object.create方法建立原型物件,Parent5.prototype就是create方法的一個引數,一層一層往上找實現了繼承,同時完成了繼承,這個就是實現繼承的完美方式