JS雖然不像是JAVA那種強型別的語言,但也有著與JAVA型別的繼承屬性,那麼JS中的繼承是如何實現的呢?
一、建構函式繼承
1 在建構函式中,同樣屬於兩個新建立的函式,也是不相等的 2 3 function Fn(name){ 4 this.name = name; 5 this.show = function(){ 6 alert(this.name); 7 } 8 } 9 var obj1 = new Fn("AAA"); 10 var obj2 = new Fn("BBB"); 11 console.log(obj1.show==obj2.show); //false 12 13 此時可以看出建構函式的多次建立會產生多個相同函式,造成冗餘太多。 14 15 利用原型prototype解決。首先觀察prototype是什麼東西 16 function Fn(){} 17 console.log(Fn.prototype); 18 //constructor表示當前的函式屬於誰 19 //__proto__ == [[prototype]],書面用語,表示原型指標 20 21 var fn1 = new Fn(); 22 var fn2 = new Fn(); 23 Fn.prototype.show = function(){ 24 alert(1); 25 } 26 console.log(fn1.show==fn2.show); //ture 27 28 此時,任何一個物件的原型上都有了show方法,由此得出,建構函式Fn.prototype身上的新增的方法,相當於新增到了所有的Fn身上。
二、call和applay繼承
1 function Father(skill){ 2 this.skill = skill; 3 this.show = function(){ 4 alert("我會"+this.skill); 5 } 6 } 7 var father = new Father("絕世木匠"); 8 function Son(abc){ 9 //這裡的this指向函式Son的例項化物件 10 //將Father裡面的this改變成指向Son的例項化物件,當相遇將father裡面所有的屬性和方法都複製到了son身上 11 //Father.call(this,abc);//繼承結束,call適合固定引數的繼承 12 //Father.apply(this,arguments);//繼承結束,apply適合不定引數的繼承 13 } 14 father.show() 15 var son = new Son("一般木匠"); 16 son.show();
三、原型鏈繼承(demo)
這個的麼實現一個一個簡單的拖拽,a->b的一個繼承。把a的功能繼承給b。
HTML:
1 <div id="drag1"></div> 2 <div id="drag2"></div>
CSS:
1 *{margin: 0;padding: 0;} 2 #drag1{width: 100px;height: 100px;background: red;position: absolute;} 3 #drag2{width: 100px;height: 100px;background: black;position: absolute;left: 500px;}
JS:
1 function Drag(){} 2 Drag.prototype={ 3 constructor:Drag, 4 init:function(id){ 5 this.ele=document.getElementById(id); 6 this.cliW=document.documentElement.clientWidth||document.body.clientWidth; 7 this.cliH=document.documentElement.clientHeight||document.body.clientHeight; 8 var that=this; 9 this.ele.onmousedown=function(e){ 10 var e=event||window.event; 11 that.disX=e.offsetX; 12 that.disY=e.offsetY; 13 document.onmousemove=function(e){ 14 var e=event||window.event; 15 that.move(e); 16 } 17 that.ele.onmouseup=function(){ 18 document.onmousemove=null; 19 } 20 } 21 }, 22 move:function(e){ 23 this.x=e.clientX-this.disX; 24 this.y=e.clientY-this.disY; 25 this.x=this.x<0?this.x=0:this.x; 26 this.y=this.y<0?this.y=0:this.y; 27 this.x=this.x>this.cliW-this.ele.offsetWidth?this.x=this.cliW-this.ele.offsetWidth:this.x; 28 this.y=this.y>this.cliH-this.ele.offsetHeight?this.y=this.cliH-this.ele.offsetHeight:this.y; 29 this.ele.style.left=this.x+`px`; 30 this.ele.style.top=this.y+`px`; 31 } 32 } 33 new Drag().init(`drag1`) 34 function ChidrenDrag(){} 35 ChidrenDrag.prototype=new Drag() 36 new ChidrenDrag().init(`drag2`)
四、混合繼承
1 function Father(skill,id){ 2 this.skill = skill; 3 this.id = id; 4 } 5 Father.prototype.show = function(){ 6 alert("我是father,這是我的技能"+this.skill); 7 } 8 9 function Son(){ 10 Father.apply(this,arguments); 11 } 12 //如果不做son的原型即成father的原型,此時會報錯:son.show is not a function 13 Son.prototype = Father.prototype; 14 //因為,如果不讓son的原型等於father的原型,son使用apply是繼承不到原型上的方法 15 //但這是一種錯誤的原型繼承示例,如果使用這種方式,會導致修改son原型上的show方法時,會把father身上的show也修改 16 //記憶體的堆和棧機制 17 Son.prototype.show = function(){ 18 alert("我是son,這是我的技能"+this.skill); 19 } 20 var father = new Father("專家級鐵匠","father"); 21 var son = new Son("熟練級鐵匠","son"); 22 father.show(); 23 son.show(); 24 25 上面的示例應該修改成以下形式: 26 以上紅色的程式碼應改成: 27 for(var i in Father.prototype){ 28 Son.prototype[i] = Father.prototype[i]; 29 } 30 //遍歷father的原型身上的所有方法,依次拷貝給son的原型,這種方式稱為深拷貝 31 32 這種繼承方式叫做混合繼承,用到了for-in繼承,cell和apple繼承。
五、Es6的class繼承(demo)
這個demo的功能和原型鏈繼承的demo功能一樣,a->b的繼承
HTML: 1 <div id="drag1"></div> 2 <div id="drag2"></div>
CSS: 1 *{margin: 0;padding: 0;} 2 #drag1{width: 100px;height: 100px;background: red;position: absolute;} 3 #drag2{width: 100px;height: 100px;background: black;position: absolute;left: 500px;}
JS:
1 class Drag{ 2 constructor(id){ 3 this.ele=document.getElementById(id); 4 this.init(); 5 }; 6 init(){ 7 var that=this; 8 this.ele.onmousedown=function(e){ 9 var e=event||window.event; 10 that.disX=e.offsetX; 11 that.disY=e.offsetY; 12 document.onmousemove=function(e){ 13 var e=event||window.event; 14 that.move(e); 15 } 16 that.ele.onmouseup=function(){ 17 document.onmousemove=null; 18 that.ele.onmouseup=null; 19 } 20 } 21 }; 22 move(e){ 23 this.ele.style.left=e.clientX-this.disX+"px"; 24 this.ele.style.top=e.clientY-this.disY+"px"; 25 } 26 } 27 28 new Drag("drag1"); 29 30 class ExtendsDrag extends Drag{ 31 constructor(id){ 32 super(id); 33 } 34 } 35 36 new ExtendsDrag("drag2")
我總結的這幾種繼承方法.兩個demo繼承的方法大家最好在編譯器上跑一下,看看。這樣才能更深刻的去理解。尤其是原型鏈的繼承,js作為一個物件導向的程式語言,還是很常用的。