欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JavaScript的繼承實(shí)現(xiàn)小結(jié)

 更新時(shí)間:2017年05月07日 10:35:25   作者:編程老頭  
JavaScript作為面向?qū)ο蟮娜躅愋驼Z言,繼承也是其非常強(qiáng)大的特性之一。那么如何在JS中實(shí)現(xiàn)繼承呢?本文將給大家揭開神秘面紗

最近在忙前端的工作,因?yàn)橹白?net和php的開發(fā)比較多,前端開發(fā)喜歡把庫拿來就用,幾次事實(shí)證明,不懂原理,連改代碼也改不好,所以還是下定決心研究下JavaScript的幾個(gè)技術(shù)難點(diǎn)。

0x1.JavaScript的對(duì)象和構(gòu)造函數(shù)

定義一個(gè)JavaScript對(duì)象可以這么定義

var a = {
	x : 1,
	y : 2,
	add : function () {
		return this.x + this.y;
	},
	mul : function () {
		return this.x * this.y;
	}
}

這樣,你就定義了一個(gè)變量a,這個(gè)變量除了有x和y兩個(gè)公有成員外,還有兩個(gè)add和mul兩個(gè)函數(shù)(公有方法)。但是這樣的定義方法的缺點(diǎn)有2條:

1.批量生成對(duì)象很不方便,如果你var b=a;那么你每次修改b的成員,都會(huì)同時(shí)改掉a的成員,因?yàn)镴avaScript的引用機(jī)制

2.如果每次生成對(duì)象需要自定義一些成員,都要寫出相應(yīng)的賦值操作,增加代碼行數(shù)。

所以,在定義一個(gè)JavaScript對(duì)象之前,我們可以先定義一個(gè)構(gòu)造函數(shù)。

function A(x, y) {
	this.x = x;
	this.y = y;
	this.add = function () {
		return this.x + this.y;
	}
	this.mul = function () {
		return this.x * this.y;
	}
}

然后,定義一個(gè)對(duì)象

a = new A(1, 2);

上面這句代碼看起來簡(jiǎn)單,但是要和C++等面向?qū)ο蟮恼Z言做個(gè)區(qū)分,A并不是嚴(yán)格意義上“類”的概念,因?yàn)镴avaScript是沒有類的,只是調(diào)用了構(gòu)造函數(shù)而已。

現(xiàn)在問題來了,我們?cè)趺磳?shí)現(xiàn)繼承?C++把封裝,繼承,多態(tài)這三個(gè)面向?qū)ο蟮奶卣鲗?shí)現(xiàn)得清清楚楚。但是對(duì)于JavaScript這樣一個(gè)比較浪的語言,沒有一個(gè)很嚴(yán)格的繼承機(jī)制,而是采用以下幾種方式來模擬。

0x2.JavaScript的prototype

為了能夠講清后面的apply或call函數(shù),這里先引入prototype。prototype是只有Function才有的。

要用好繼承,首先要明白為什么要設(shè)計(jì)繼承這個(gè)東西?無非就是“把公共的部分”提取出來,實(shí)現(xiàn)代碼復(fù)用。

所以在JavaScript里,也是把公共部分放在Function的prototype里。

我們來比較兩個(gè)用prototype來實(shí)現(xiàn)繼承的例子

function A(x, y) {
	this.x = x;
	this.y = y;
	this.add = function () {
		return this.x + this.y;
	}
	this.mul = function () {
		return this.x * this.y;
	}
}

function B(x,y){
	
}

B.prototype=new A(1,2);

console.log(new B(3,4).add());  //3

這個(gè)例子中,子類的prototype指向一個(gè)A類對(duì)象

我們?cè)賹?shí)現(xiàn)一個(gè)B繼承A的例子:

function A() {
	
}

A.prototype = {
	x : 1,
	y : 2,
	add : function () {
		return this.x + this.y;
	},
	mul : function () {
		return this.x * this.y;
	}
}
A.prototype.constructor=A;

function B(){
	
}

B.prototype=A.prototype;
B.prototype.constructor=B;

B的prototype對(duì)象引用了A的prototype對(duì)象,因?yàn)槭且?,所以如果修改了B的prototype對(duì)象,A的prototype對(duì)象也隨之修改,因?yàn)楸举|(zhì)上他們都指向一塊內(nèi)存。所以每次改動(dòng)B類型的prototype都要手動(dòng)將constructor改回,防止錯(cuò)亂。相比兩個(gè)例子,上一個(gè)例子因?yàn)闆]有引用,所以不會(huì)發(fā)生這個(gè)問題。

創(chuàng)建一個(gè)B類型的對(duì)象

b=new B();

b對(duì)象具有A類型的一切成員

console.log(b.add());  //3

因?yàn)槊總€(gè)prototype對(duì)象都有兩個(gè)重要成員:constructor和_proto_,constructor本質(zhì)上是一個(gè)函數(shù)指針,所以B.prototype=A.prototype執(zhí)行后,覆蓋掉了constructor,所以后面要讓constructor重新指向B類型的構(gòu)造函數(shù)。

0x3.JavaScript的構(gòu)造函數(shù)綁定

在定義完一個(gè)A類型的構(gòu)造函數(shù)后,再定義一個(gè)B類型,然后在B類型構(gòu)造函數(shù)內(nèi)部,“嵌入執(zhí)行”A類型的構(gòu)造函數(shù)。

function A(x, y) {
	this.x = x;
	this.y = y;
	this.add = function () {
		return this.x + this.y;
	}
	this.mul = function () {
		return this.x * this.y;
	}
}

function B(x, y, z) {
	A.apply(this, arguments);
	this.z = z;
}

console.log(new B(1,2,3));

apply函數(shù)和call函數(shù)基本一樣,可以在B類型構(gòu)造函數(shù)內(nèi)部執(zhí)行A類型構(gòu)造函數(shù)。同時(shí)也可以繼承A的所有成員。

顯示結(jié)果:

這里給個(gè)公式:在B構(gòu)造函數(shù)里寫A.apply(this),可以讓B構(gòu)造出來的對(duì)象可以擁有A構(gòu)造函數(shù)里的所有成員。

談到apply和call,還可以實(shí)現(xiàn)多重繼承

function IA(){
	this.walk=function(){
		console.log("walk");
	}
}

function IB(){
	this.run=function(){
		console.log("run");
	}
}

function Person(){
	IA.apply(this);
	IB.apply(this);
}

var p=new Person();
p.walk();  //walk    
p.run();  //run

 以上就是本文的全部?jī)?nèi)容了,希望大家能夠喜歡

相關(guān)文章

最新評(píng)論