javascript面向對象(繼承)

          繼承是面向對象的重要特性,子類繼承了父類,子類就有了父類的屬性和方法。在java中使用extends關鍵字後加父類名就可以實現繼承。但在javascript中沒有這種關鍵字。那麼javascript如何實現繼承呢? 在這裏可以使用原型來實現繼承,原型對象是在每個方法在創建之時就根據一定規則生成的。如果使一個方法原型對象的指針指向一個實例,此時的原型對象將包含指向另一個原型對象的指針,相應的,另一個原型對象將指向另一個構造函數。如果另一個原型對象又指向另一個實例,那麼上述關係依然成立,這樣層層遞進,形成了一個原型鏈。

        function Person(){
	}
	Person.prototype.name = "zhouqi";
	Person.prototype.age = 25;
	Person.prototype.job = "computer scientist";
	Person.prototype.sayHi = function(){
		alert("Hi");
	}
	function Man(){
	}
	Man.prototype = new Person();
	var man1 = new Man();
	alert(man1 instanceof Person);
	alert(man1 instanceof Object);
	man1.sayHi();
如上面例子所示,Man的原型對象指向一個Person實例,那麼原型對象中就有一個指向Person原型的指針_proto_。

但是用原型鏈來實現繼承並不是最好的方法,在使用原型進行對象創建時有同樣的問題,在使用原型創建對象時,不同的實例將共享原型中的屬性,如果屬性是一個引用類型會產生改變一個實例值,其他實例的值也跟着改變的問題。

<script type="text/javascript">
	alert("fuck");
	function Person(){
	}
	Person.prototype.name = "zhouqi";
	Person.prototype.age = 25;
	Person.prototype.friends = new Array("zhangyan", "wangjianfei","peixin");
	function man(){
	}
	man.prototype = new Person();
	man.prototype.sayHi = function(){
		alert("hello");
	}
	var man1 = new man();
	var man2 = new man();
	man1.friends.push("guxin");
	alert(man1.friends);//zhangyan,wangjianfei,peixin,guxin
	alert(man2.friends);//zhangyan,wangjianfei,peixin,guxin
</script>
如上面例子所示,爲man1添加一個朋友,結果也爲man2添加了一個朋友,這樣會產生問題。爲了解決這個問題,可以使用借用構造函數的方式,這種方式十分簡單,可以看下面的例子

<script type="text/javascript">
	function Person(){
		this.friends = new Array("zhouqi","guxin","wangjainfei");
	}
	function Man(){
		Person.call(this);
	}
	var man1 = new Man();
	var man2 = new Man();
	man1.friends.push("xiaoqiaofeng");
	alert(man1.friends);//zhouqi,guxin,wangjainfei,xiaoqiaofeng
	alert(man2.friends);//zhouqi,guxin,wangjainfei
</script>
在子類對象中調用父類對象,會將父類對象的作用域添加到子類對象中,子類對象就可以調用父類對象的屬性和方法,這種方式簡單明瞭。但借用構造函數存在這樣一個問題,所有的方法都在構造函數中定義,那麼函數的複用會成爲一個問題,爲了解決這個問題,可以使用組合繼承方式,即將原型鏈和構造函數方式結合起來。如下面例子所示

<script type="text/javascript">
	function Person(){
		this.friends = ["guxin","zhouqi"]
	}
	Person.prototype.sayHi = function(){
		alert("hello");
	}
	function Man(){
		Person.call(this);
	}
	Man.prototype = new Person();
	var man1 = new Man();
	man1.sayHi();
	man1.friends.push("jianfei");
	var man2 = new Man();
	alert(man1.friends);//guxin,zhouqi,jianfei
	alert(man2.friends);//guxin,zhouqi
</script>
這種繼承方式被稱爲組合繼承,組合繼承結合了原型鏈函數可複用的優點,又避免了原型鏈數據共享的問題,將需要共享的數據放在原型鏈中,將不需共享的內容或因對象而異的內容放在構造函數中。

        除了本文介紹的幾種基礎的構造函數方式,還有原型式繼承,寄生式繼承,寄生組合式繼承等繼承方式,可以參考《javascript 高級語言程序設計》這本書。通過學習javascript面向對象編程這個章節,個人認爲javascript並不是嚴格的面向對象編程語言。不像java,C++,python。但通過javascript的一些語法特點可以實現面向對象編程,但這比java要複雜一些。這一章的關鍵點是構造函數和原型、原型鏈的概念。構造函數內部的屬性和方法每創建一個對象都要創建一次,而原型中的屬性和方法是所有實例共享的。無論是創建對象還是實現繼承單獨使用構造函數和原型都會產生問題,單獨使用構造函數模式會產生函數複用問題,單獨使用原型則會產生共享問題。所以要將兩者結合起來使用。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章