JavaScript類(lèi)的繼承操作實(shí)例總結(jié)
本文實(shí)例總結(jié)了JavaScript類(lèi)的繼承操作。分享給大家供大家參考,具體如下:
一、類(lèi)式繼承
首先要做的是創(chuàng)建構(gòu)造函數(shù)。按慣例,其名稱(chēng)就是類(lèi)名,首字母應(yīng)該大寫(xiě)。在構(gòu)造函數(shù)中,創(chuàng)建實(shí)例屬性要用關(guān)鍵字this 。類(lèi)的方法則被添加到prototype對(duì)象中。要?jiǎng)?chuàng)建該類(lèi)的實(shí)例,只需結(jié)合關(guān)鍵字new調(diào)用這構(gòu)造函數(shù)即可。
/* Class Person. */
function Person(name) {
this.name = name;
}
Person.prototype.getName = function() {
return this.name;
}
var reader = new Person('John Smith');
reader.getName();
二、原型鏈
JavaScript的每個(gè)對(duì)象都有一個(gè)名為prototype的屬性,這個(gè)屬性要么指向另一個(gè)對(duì)象,要么是null.在訪問(wèn)對(duì)象的某個(gè)成員時(shí),如果這個(gè)成員未見(jiàn)于當(dāng)前對(duì)象,那么就會(huì)到prototype所指的對(duì)象中去查找。如果還是沒(méi)有找到,那么就會(huì)沿著原型鏈逐一訪問(wèn)每個(gè)原型對(duì)象,直到找到這個(gè)成員。這意味著讓一個(gè)類(lèi)繼承另一個(gè)類(lèi),只需將子類(lèi)的prototype設(shè)置為超類(lèi)的一個(gè)實(shí)例即可。
為了讓Author繼承Person,必須手工將Author的prototype設(shè)置為Person的一個(gè)實(shí)例。最后一步是將prototype的construct屬性重設(shè)為Author(因?yàn)?code>prototype屬性設(shè)置為Person的實(shí)例)時(shí),其construct屬性被抹除了。
function Author(name, books) {
Person.call(this, name); // Call the superclass' constructor in the scope of this.
this.books = books; // Add an attribute to Author.
}
Author.prototype = new Person(); // Set up the prototype chain.
Author.prototype.constructor = Author; // Set the constructor attribute to Author.
Author.prototype.getBooks = function() { // Add a method to Author.
return this.books;
};
var author = [];
author[0] = new Author('Dustin Diaz', ['JavaScript Design Patterns']);
author[1] = new Author('Ross Harmes', ['JavaScript Design Patterns']);
console.log(author[1].getName());
console.log(author[1].getBooks());
三、extend函數(shù)
為了簡(jiǎn)化類(lèi)的聲明,可以把派生子類(lèi)的整個(gè)過(guò)程包裝在一個(gè)名為extend的函數(shù)中。它的作用與其他語(yǔ)言的extend關(guān)鍵字類(lèi)似,即基于一個(gè)給定的類(lèi)的結(jié)構(gòu)創(chuàng)建一個(gè)新的類(lèi):
function extend(subClass, superClass) {
var F = function() {};
F.prototype = superClass.prototype;
subClass.prototype = new F();
subClass.prototype.constructor = subClass;
}
其實(shí)所做的事與之前的是一樣的。它先設(shè)置了prototype,然后再將其constructor重設(shè)為恰當(dāng)?shù)闹?。并且中間利用了一個(gè)空函數(shù),這樣就可以避免創(chuàng)建超類(lèi)的實(shí)例。使用extend繼承的寫(xiě)法:
function Person(name) {
this.name = name;
}
Person.prototype.getName = function() {
return this.name;
}
/* Class Author. */
function Author(name, books) {
Person.call(this, name);
this.books = books;
}
extend(Author, Person);
Author.prototype.getBooks = function() {
return this.books;
};
但上面的存在一個(gè)問(wèn)題就是超類(lèi)Person的名稱(chēng)被固化在Author類(lèi)的聲明當(dāng)中。更普世性的做法應(yīng)該像下面這樣:
/* Extend function, improved. */
function extend(subClass, superClass) {
var F = function() {};
F.prototype = superClass.prototype;
subClass.prototype = new F();
subClass.prototype.constructor = subClass;
subClass.superclass = superClass.prototype;
if(superClass.prototype.constructor == Object.prototype.constructor) {
superClass.prototype.constructor = superClass;
}
}
/* Class Author. */
function Author(name, books) {
Author.superclass.constructor.call(this, name);
this.books = books;
}
extend(Author, Person);
Author.prototype.getBooks = function() {
return this.books;
};
Author.prototype.getName = function() {
var name = Author.superclass.getName.call(this);
return name + ', Author of ' + this.getBooks().join(', ');
};
這個(gè)extend改進(jìn)之后,多了一個(gè)superclass的屬性,這個(gè)屬性可以弱化Author和Person之間的耦合。extend后面三行用來(lái)確保超類(lèi)的construtor已經(jīng)被正確設(shè)置了。有了superclass的屬性,就可以直接調(diào)用超類(lèi)中的方法。這在既要重新定義超類(lèi)的某個(gè)方法而又想訪問(wèn)其在超類(lèi)中的實(shí)現(xiàn)時(shí)可以派上用場(chǎng)。例如,為了用一個(gè)新的getName的方法重新定義Person類(lèi)中的同名方法,你可以先用Author.superclass.getName獲得作者的名字,然后再次基礎(chǔ)上添加新的信息。
四、原型繼承
原型式繼承與類(lèi)式繼承截然不同,我們?cè)趯W(xué)習(xí)他的時(shí)候,最好忘記自己關(guān)于類(lèi)和實(shí)例的一切知識(shí),只從對(duì)象的角度來(lái)思考。使用原型式繼承時(shí),并不需要用類(lèi)來(lái)定義對(duì)象的結(jié)構(gòu),只需直接創(chuàng)建一個(gè)對(duì)像就可以。這個(gè)對(duì)象隨后可以被新的對(duì)象使用,該對(duì)象被稱(chēng)為原型對(duì)象。
下面使用原型對(duì)象來(lái)重新設(shè)計(jì)上面Person和Author:
var Person = {
name: 'default name',
getName: function() {
return this.name;
}
};
var reader = clone(Person);
alert(reader.getName()); // This will output 'default name'.
reader.name = 'John Smith';
alert(reader.getName()); // This will now output 'John Smith'.
clone函數(shù)可以用來(lái)創(chuàng)建新的類(lèi)Person對(duì)象,創(chuàng)建一個(gè)空對(duì)象,并且該對(duì)象的原型對(duì)象被設(shè)置為person。當(dāng)新對(duì)象中找不到某個(gè)方法時(shí)就會(huì)在原型對(duì)象中查找。
你不必去為了創(chuàng)建Author而定義一個(gè)Person子類(lèi),只要執(zhí)行一次克隆就可以:
var Author = clone(Person);
Author.books = []; // Default value.
Author.getBooks = function() {
return this.books;
}
然后你可以重定義該克隆中的方法和屬性??梢孕薷腜erson的默認(rèn)值。也可以添加新的屬性和方法。這樣一來(lái)就創(chuàng)建了一個(gè)新的原型對(duì)象,你可以將其用于創(chuàng)建新的Author對(duì)象:
var author = []; author[0] = clone(Author); author[0].name = 'Dustin Diaz'; author[0].books = ['JavaScript Design Patterns']; author[1] = clone(Author); author[1].name = 'Ross Harmes'; author[1].books = ['JavaScript Design Patterns']; author[1].getName(); author[1].getBooks();
clone函數(shù)的寫(xiě)法:
function clone(object) {
function F() {}
F.prototype = object;
return new F;
}
五、原型繼承和類(lèi)式繼承之間的比較
可以自己去總結(jié)、
從內(nèi)存,適用范圍,優(yōu)缺點(diǎn)等方面去分析
六、摻元類(lèi)
有一種重用代碼的方法不需要用到嚴(yán)格的繼承,如果想把一個(gè)函數(shù)運(yùn)用到多個(gè)類(lèi)當(dāng)中,可以通過(guò)擴(kuò)充的方法讓這些類(lèi)共享函數(shù)。其實(shí)際大體做法就是:先創(chuàng)建一個(gè)包含各種通用的方法類(lèi),然后再擴(kuò)充其他類(lèi),這種包含通用方法類(lèi)稱(chēng)為摻元類(lèi),他們通常不會(huì)被實(shí)例化和直接調(diào)用,其存在的目的是向其他類(lèi)提供自己的方法。
var Mixin = function() {};
Mixin.prototype = {
serialize: function() {
var output = [];
for(key in this) {
output.push(key + ': ' + this[key]);
}
return output.join(', ');
}
};
augment(Author, Mixin);
var author = new Author('Ross Harmes', ['JavaScript Design Patterns']);
var serializedString = author.serialize();
function augment(receivingClass, givingClass) {
for(methodName in givingClass.prototype) {
if(!receivingClass.prototype[methodName]) {
receivingClass.prototype[methodName] = givingClass.prototype[methodName];
}
}
}
但是有時(shí)候你并不需要所有的方法,因此我們還需要提供額外的參數(shù)來(lái)選擇我們所需要的方法。如果不提供,那就全部復(fù)制。
function augment(receivingClass, givingClass) {
if(arguments[2]) { // Only give certain methods.
for(var i = 2, len = arguments.length; i < len; i++) {
receivingClass.prototype[arguments[i]] = givingClass.prototype[arguments[i]];
}
}
else { // Give all methods.
for(methodName in givingClass.prototype) {
if(!receivingClass.prototype[methodName]) {
receivingClass.prototype[methodName] = givingClass.prototype[methodName];
}
}
}
}
更多關(guān)于JavaScript相關(guān)內(nèi)容還可查看本站專(zhuān)題:《javascript面向?qū)ο笕腴T(mén)教程》、《JavaScript錯(cuò)誤與調(diào)試技巧總結(jié)》、《JavaScript數(shù)據(jù)結(jié)構(gòu)與算法技巧總結(jié)》、《JavaScript遍歷算法與技巧總結(jié)》及《JavaScript數(shù)學(xué)運(yùn)算用法總結(jié)》
希望本文所述對(duì)大家JavaScript程序設(shè)計(jì)有所幫助。
相關(guān)文章
微信小程序 頁(yè)面跳轉(zhuǎn)傳值實(shí)現(xiàn)代碼
這篇文章主要介紹了微信小程序 頁(yè)面跳轉(zhuǎn)傳值實(shí)現(xiàn)代碼的相關(guān)資料,這里分析實(shí)現(xiàn)的條件及實(shí)例代碼,需要的朋友可以參考下2017-07-07
比較詳細(xì)的javascript DOM 學(xué)習(xí)筆記
看了很多的js dom學(xué)習(xí)資料,發(fā)現(xiàn)這個(gè)比較詳細(xì),特轉(zhuǎn)載給大家學(xué)習(xí)一下2008-06-06
原生JavaScript實(shí)現(xiàn)幻燈片效果
這篇文章主要為大家詳細(xì)介紹了原生JavaScript實(shí)現(xiàn)幻燈片效果,文中安裝步驟介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-02-02
javascript for循環(huán)設(shè)法提高性能
讓你的for循環(huán)提升性能的寫(xiě)法,需要的朋友可以參考下。2010-02-02
js中將多個(gè)語(yǔ)句寫(xiě)成一個(gè)語(yǔ)句的兩種方法小結(jié)
js中將多個(gè)語(yǔ)句寫(xiě)成一個(gè)語(yǔ)句的兩種方法講述了逗號(hào)運(yùn)算符將多個(gè)語(yǔ)句寫(xiě)成一個(gè)語(yǔ)句以及花括號(hào)寫(xiě)成一個(gè)語(yǔ)句的實(shí)現(xiàn)方法,需要的朋友可以參考一下2007-12-12
js setTimeout()函數(shù)介紹及應(yīng)用以倒計(jì)時(shí)為例
setTimeout() 方法用于在指定的毫秒數(shù)后調(diào)用函數(shù)或計(jì)算表達(dá)式,下面有個(gè)倒計(jì)時(shí)的示例,需要的朋友可以學(xué)習(xí)下2013-12-12
將HTML的左右尖括號(hào)等轉(zhuǎn)義成實(shí)體形式的兩種實(shí)現(xiàn)方式
這篇文章主要介紹了將HTML的左右尖括號(hào)等轉(zhuǎn)義成實(shí)體形式的兩種實(shí)現(xiàn)方式,需要的朋友可以參考下2014-05-05
JS實(shí)現(xiàn)電子時(shí)鐘入門(mén)操作
這篇文章主要為大家詳細(xì)介紹了JS實(shí)現(xiàn)電子時(shí)鐘入門(mén)操作,實(shí)現(xiàn)帶有表盤(pán)的時(shí)鐘,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-06-06

