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

javascript面向?qū)ο笕筇卣髦^承實例詳解

 更新時間:2019年07月24日 09:52:31   作者:Johnny丶me  
這篇文章主要介紹了javascript面向?qū)ο笕筇卣髦^承,簡單描述了繼承的概念、原理,并結(jié)合實例形式詳細分析了繼承的常見實現(xiàn)方法與操作注意事項,需要的朋友可以參考下

本文實例講述了javascript面向?qū)ο笕筇卣髦^承。分享給大家供大家參考,具體如下:

繼承

在JavaScript中的繼承的實質(zhì)就是子代可以擁有父代公開的一些屬性和方法,在js編程時,我們一般將相同的屬性放到父類中,然后在子類定義自己獨特的屬性,這樣的好處是減少代碼重復(fù)。繼承是面向?qū)ο蟮幕A(chǔ),是代碼重用的一種重要機制。

——此文整理自 《jQuery 開發(fā)從入門到精通》 ,這是本好書,講的很詳細,建議購買閱讀。

繼承的作用

實現(xiàn)繼承的主要作用是:

① 子類實例可以共享超類屬性和方法。
② 子類可以覆蓋和擴展超類屬性和方法。

繼承的分類

在JavaScript中是不支持類的概念,使用構(gòu)造器機制來實現(xiàn)類的特性。
JavaScript中類的繼承不止一種,主要包括:類繼承(構(gòu)造函數(shù)繼承),原型繼承,實例繼承,復(fù)制繼承,克隆繼承,混合繼承,多重繼承等。

類繼承

類繼承也叫構(gòu)造函數(shù)繼承,其表現(xiàn)形式是在子類中執(zhí)行父類的構(gòu)造函數(shù)。實現(xiàn)本質(zhì):比如把一個構(gòu)造函數(shù)A的方法賦值為另一個構(gòu)造函數(shù)B,然后調(diào)用該方法,使構(gòu)造函數(shù)A在構(gòu)造函數(shù)B內(nèi)部執(zhí)行,這是構(gòu)造函數(shù)B就擁有了構(gòu)造函數(shù)A中定義的屬性和方法。這就是B類繼承A類。示例如下:

function A(x){
  this.x = x;
  this.say = function() {
   console.log(this.x + ' say');
  }
}
function B(x,y) {
  this.m = A; // 把構(gòu)造函數(shù)A作為一個普通函數(shù)引給臨時方法m()
  this.m(x); // 把當前參數(shù)作為值傳給構(gòu)造函數(shù)A,并且執(zhí)行
  delete this.m; // 清除臨時方法
  this.y = y;
  this.call = function(){
   console.log(this.y);
  }
}
// 測試類繼承
var a = new A(1);
var b = new B(2,3);
a.say(); // 1 say
b.say(); // 2 say
b.call(); // 3

上面的實現(xiàn)方式很巧妙對吧,但是這種設(shè)計方式太隨意,缺乏嚴密性。嚴禁的設(shè)計模式應(yīng)該考慮到各種可能存在的情況和類繼承關(guān)系中的互相耦合性。所以一般我們盡可能把子類自身的方法放在原型里去實現(xiàn)。下面這種創(chuàng)建方式會更好:

function A(x){
 this.x = x;
 this.say = function() {
  console.log(this.x + ' say');
 }
}
function B(x,y){
 this.y = y;
 A.call(this,x); // 在構(gòu)造函數(shù)B內(nèi)調(diào)用超類A,實現(xiàn)綁定,用call來實現(xiàn)借用
}
B.prototype = new A(); // 設(shè)置原型鏈,建立繼承關(guān)系
B.prototype.constructor = B; // 恢復(fù)B的原型對象的構(gòu)造函數(shù)為B,如果不操作就會指向A
B.prototype.gety = function(){ // 給類B添加新的方法
 return this.y;
}
// 測試 類繼承
var a = new A('A');
var b = new B('Bx','By');
a.say(); // A say
b.say(); // Bx say
console.log(b.gety()); // By
console.log(B.prototype.__proto__ === A.prototype); // true;
console.log(b.constructor === B); // true 這里也可以把B中的 B.prototype.constructor = B; 去除,結(jié)果為false

在js中實現(xiàn)類繼承,需要設(shè)置3點:

① 在子類構(gòu)造函數(shù)結(jié)構(gòu)體內(nèi),使用函數(shù)call()調(diào)用父類構(gòu)造函數(shù),把子類的參數(shù)傳遞給調(diào)用函數(shù)如上面的例子:A.call(this,x) 這樣子類可以繼承父類的所有屬性和方法。
② 在子類和父類之間建立原型鏈,如上例:B.prototype = new A() 為了實現(xiàn)類的繼承必須保證他們原型鏈上的上下級關(guān)系。即設(shè)置子類的prototype 屬性指向父類的一個實例即可。
③ 恢復(fù)子類原型對象的構(gòu)造函數(shù), 如上例:B.prototype.constructor = B

在類繼承中,call() 和 apply() 方法被頻繁使用,它們之間的功能和用法都是相同的,唯一區(qū)別就是第2個參數(shù)類型不同。如果深入,請看前面的文章:http://www.dbjr.com.cn/article/166093.htm

此處需要提一下,就是類的構(gòu)造函數(shù)中的成員,一般稱之為本地成員,而類的原型成員就是類的原型中的成員,此處我們只考慮原型中的成員繼承。本地成員繼承可以用call 和 apply。下面我們來看下類繼承的原型成員的繼承封裝函數(shù):

在函數(shù)體內(nèi),首先定義一個空函數(shù)F(),用來實現(xiàn)功能中轉(zhuǎn),把它的原型指向父類的原型,把空函數(shù)的實例傳遞給子類的原型,這樣就避免了直接實例化父類引發(fā)的內(nèi)存問題,因為實際開發(fā)中,父類可能很大,實例化后,會占用很大一部分內(nèi)存。

// 定義一個繼承函數(shù)
function extend(Sub,Sup){ // 有兩個入口參數(shù),Sub是子類,Sup是父類
 var F = function(){}; // 建立一個臨時的構(gòu)造函數(shù)
 F.prototype = Sup.prototype; // 把臨時構(gòu)造函數(shù)的原型指向父類的原型
 Sub.prototype = new F(); // 實例化臨時類,此處相當于把子類的原型指向父類的實例
 Sub.prototype.constructor = Sub; // 恢復(fù)子類的構(gòu)造函數(shù)
 Sub.sup = Sup.prototype; // 在子類中定義一個本地屬性存儲超類原型,可避免子類和超類耦合
 if(Sup.prototype.constructor === Object.prototype.constructor) { // 檢測超類構(gòu)造器是否為Object構(gòu)造器
  Sup.prototype.constructor = Sup;
 }
}
// 下面定義兩個類用來測試上面的繼承函數(shù)
function A(x,y) {
 this.x = x;
 this.y = y;
}
A.prototype.add = function() {
 return (this.x-0) + (this.y-0); // 此處-0 的目的是確保字符串類型可轉(zhuǎn)成數(shù)值型
}
A.prototype.minus = function() {
 return this.x - this.y;
}
function B(x,y) {
 A.apply(this,[x,y]);
}
// 開始實現(xiàn)類繼承中的原型成員繼承
extend(B,A);
// 為了不與A類中的代碼耦合可以單獨為B定義一個同名的add
B.prototype.add = function() {
 return B.sup.add.call(this); // 避免代碼耦合
}
// 測試繼承
var b = new B(1,2);
console.log(b.minus()); // -1
console.log(b.add()); // 3

原型繼承

原型繼承是js中最通用的繼承方式,不用實例化對象,通過直接定義對象,并被其他對象引用,這樣形成的一種繼承關(guān)系,其中引用對象被稱為原型對象。

function A(){
 this.color = 'red';
}
function B(){}
function C(){}
B.prototype = new A();
C.prototype = new B();
// 測試原型繼承
var c = new C();
console.log(c.color); // red

原型繼承顯得很簡單,不需要每次構(gòu)造都調(diào)用父類的構(gòu)造函數(shù),也不需要通過復(fù)制屬性的方式就能快速實現(xiàn)繼承。但它也存在一些缺點:

① 每個類型只有一個原型,所以不支持多重繼承
② 不能很好的支持多參數(shù)或動態(tài)參數(shù)的父類,顯得不夠靈活。
③ 占用內(nèi)存多,每次繼承都需要實例化一個父類,這樣會存在內(nèi)存占用過多的問題。

實例繼承

實例化類可創(chuàng)建新的實例對象,這個實例對象將繼承類的所有特征。

function Arr() {
 var a = new Array();
 return a;
}
var arr = new Arr();
arr[0] = 1;
arr[1] = 2;
console.log(arr); // [1,2]
console.log(Array.isArray(arr)); // true
console.log(arr instanceof Array); // true
console.log(arr instanceof Arr); // false

通過構(gòu)造函數(shù)中完成對類的實例化操作,然后返回實例對象,這就是實例繼承的由來。實例繼承可實現(xiàn)對所有對象的繼承,包括自定義類,核心對象和DOM對象。但是也有一些缺點

① 實例繼承無法傳遞動態(tài)參數(shù),它是封閉在函數(shù)體內(nèi)試下你,不能通過call和apply來實現(xiàn)動態(tài)傳參。
② 實例繼承只返回一個對象,不支持多重繼承
③ 實例繼承對象它仍然保持與原對象的實例關(guān)系,無法實現(xiàn)繼承對象是封裝類的實例。如:console.log(arr instanceof Arr); // false

復(fù)制繼承

復(fù)制繼承就是利用for in 遍歷對象成員,逐一復(fù)制給另一個對象。通過這種方式來實現(xiàn)繼承。

function A(){
 this.color = 'red';
}
A.prototype.say = function() {
 console.log(this.color);
}
var a = new A();
var b = {};
// 開始拷貝
for(var item in a) {
 b[item] = a[item];
}
// 開始測試
console.log(b.color); // red
b.say(); // red.

我們把它封裝一下:

Function.prototype.extend = function(obj){
 for(item in obj){
  this.constructor.prototype[item] = obj[item];
 }
}
function A(){
 this.color = 'green';
}
A.prototype.say = function(){
 console.log(this.color);
}
// 測試
var b = function(){};
b.extend(new A());
b.say(); // green

復(fù)制繼承實際上是通過反射機制復(fù)制類對象中的可枚舉屬性和方法來模擬繼承。這種可以實現(xiàn)多繼承。但也有缺點:

① 由于是反射機制,不能繼承非枚舉類型的屬性和方法。對于系統(tǒng)核心對象的只讀方法和屬性也無法繼承。
② 執(zhí)行效率差,這樣的結(jié)構(gòu)越龐大,低效就越明顯。
③ 如果當前類型包含同名成員,這些成員會被父類的動態(tài)復(fù)制給覆蓋。
④ 多重繼承中,復(fù)制繼承不能清晰描述父類和子類的相關(guān)性。
⑤ 在實例化后才能遍歷成員,不夠靈活,也不支持動態(tài)參數(shù)
⑥ 復(fù)制繼承僅僅是簡單的引用賦值,如果父類成員包含引用類型,那么也會帶來很多副作用,如不安全,容易遭受污染等。

克隆繼承

通過對象克隆方式繼承,可以避免賦值對象成員帶來的低效。
為Function對象擴展一個clone方法。該方法可把參數(shù)對象賦值給一個空的構(gòu)造函數(shù)的原型對象,然后返回實例化后的對象,這樣該對象就擁有構(gòu)造哈數(shù)包含的所有成員了。

Function.prototype.clone = function(obj){
 function Temp(){};
 Temp.prototype = obj;
 return new Temp();
}
function A(){
 this.color = 'purple';
}
var o = Function.clone(new A());
console.log(o.color); // purple

混合繼承

混合繼承是把多種繼承方式一起使用,發(fā)揮各個優(yōu)勢,來實現(xiàn)各種復(fù)雜的應(yīng)用。最常見的就是把類繼承和原型繼承一起使用。

function A(x,y){
 this.x = x;
 this.y = y;
}
A.prototype.add = function(){
 return (this.x-0) + (this.y-0);
}
function B(x,y){
 A.call(this,x,y);
}
B.prototype = new A();
// 測試
var b = new B(2,1);
console.log(b.x); // 2
console.log(b.add()); // 3

多重繼承

繼承一般包括單向繼承和多向繼承,單向繼承模式較為簡單,每個子類有且僅有一個超類,多重繼承是一個比較復(fù)雜的繼承模式。一個子類可擁有多個超類。JavaScript原型繼承不支持多重繼承,但可通過混合模式來實現(xiàn)多重繼承。下面讓類C來繼承類A和類B:

function A(x){
 this.x = x;
}
A.prototype.hi = function(){
 console.log('hi');
}
function B(y){
 this.y = y;
}
B.prototype.hello = function(){
 console.log('hello');
}
// 給Function增加extend方法
Function.prototype.extend = function(obj) {
 for(var item in obj) {
  this.constructor.prototype[item] = obj[item];
 }
}
// 在類C內(nèi)部實現(xiàn)繼承
function C(x,y){
 A.call(this,x);
 B.call(this,y);
};
C.extend(new A(1));
C.extend(new B(2));
// 通過復(fù)制繼承后,C變成了一個對象,不再是構(gòu)造函數(shù)了,可以直接調(diào)用
C.hi(); // hi
C.hello(); // hello
console.log(C.x); // 1
console.log(C.y); // 2

一個類繼承另一個類會導(dǎo)致他們之間產(chǎn)生耦合,在js中提供多種途徑來避免耦合的發(fā)生如 摻元類

摻元類是一種比較特殊的類,一般不會被實例化或者調(diào)用,定義摻元類的目的只是向其他類提供通用的方法。

// 定義一個摻元類
function F(x,y){
 this.x = x;
 this.y = y;
}
F.prototype = {
 getx:function(){
  return this.x;
 },
 gety:function(){
  return this.y;
 }
}
// 原型拷貝函數(shù)
function extend(Sub,Sup){ // Sub 子類 , Sup 摻元類
 for(var item in Sup.prototype){
  if(!Sub.prototype[item]){ // 如果子類沒有存在同名成員
   Sub.prototype[item] = Sup.prototype[item]; // 那么復(fù)制摻元類成員到子類原型對象中
  }
 }
}
// 定義兩個子類 A,B
function A(x,y){
 F.call(this,x,y);
}
function B(x,y){
 F.call(this,x,y);
}
// 調(diào)用extend函數(shù)實現(xiàn)原型屬性,方法的拷貝
extend(A,F);
extend(B,F);
console.log(A.prototype);
// 測試繼承結(jié)果
var a = new A(2,3);
console.log(a.x); // 2
console.log(a.getx()); // 2
console.log(a.gety()); // 3
var b = new B(1,2);
console.log(b.x); // 1
console.log(b.getx()); // 1
console.log(b.gety()); // 2

通過此種方式把多個子類合并到一個子類中,就實現(xiàn)了多重繼承。

感興趣的朋友可以使用在線HTML/CSS/JavaScript代碼運行工具http://tools.jb51.net/code/HtmlJsRun測試上述代碼運行效果。

更多關(guān)于JavaScript相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《javascript面向?qū)ο笕腴T教程》、《JavaScript錯誤與調(diào)試技巧總結(jié)》、《JavaScript數(shù)據(jù)結(jié)構(gòu)與算法技巧總結(jié)》、《JavaScript遍歷算法與技巧總結(jié)》及《JavaScript數(shù)學(xué)運算用法總結(jié)

希望本文所述對大家JavaScript程序設(shè)計有所幫助。

相關(guān)文章

  • 70+漂亮且極具親和力的導(dǎo)航菜單設(shè)計國外網(wǎng)站推薦

    70+漂亮且極具親和力的導(dǎo)航菜單設(shè)計國外網(wǎng)站推薦

    網(wǎng)站可用性是任何網(wǎng)站的基本要素,而可用的導(dǎo)航更是網(wǎng)站所必需的要素之一。導(dǎo)航?jīng)Q定了用戶如何與網(wǎng)站進行交互。如果沒有了可用的導(dǎo)航,那么網(wǎng)站內(nèi)容就會變得毫無用處。
    2011-09-09
  • 值得分享和收藏的Bootstrap學(xué)習(xí)教程

    值得分享和收藏的Bootstrap學(xué)習(xí)教程

    這絕對是一套值得分享和大家收藏的Bootstrap學(xué)習(xí)教程,完整的知識體系,系統(tǒng)的學(xué)習(xí)資料,幫助大家開啟Bootstrap學(xué)習(xí)之旅,享受Bootstrap帶給大家的奇妙樂趣
    2016-05-05
  • 實現(xiàn)網(wǎng)頁內(nèi)容水平或垂直滾動的Javascript代碼

    實現(xiàn)網(wǎng)頁內(nèi)容水平或垂直滾動的Javascript代碼

    用Javascript實現(xiàn)新聞內(nèi)容的水平或垂直滾動,主要的優(yōu)點是我們可以實現(xiàn)自定義滾動風(fēng)格或特效,應(yīng)用效果比起傳統(tǒng)的marquee更加具有特色,方法也比較簡單
    2012-10-10
  • js代碼驗證手機號碼和電話號碼是否合法

    js代碼驗證手機號碼和電話號碼是否合法

    這篇文章主要介紹了js代碼驗證手機號碼和電話號碼是否合法,手機號碼和電話號碼在某些網(wǎng)站都是必填項,為了提高用戶體驗度,一般要進行合法性校驗的,需要的朋友可以參考下
    2015-07-07
  • javascript中UMD規(guī)范的代碼推演

    javascript中UMD規(guī)范的代碼推演

    這篇文章給大家分享了javascript中UMD規(guī)范的代碼推演的相關(guān)的知識點內(nèi)容,有興趣的朋友們學(xué)習(xí)下。
    2018-08-08
  • 微信小程序?qū)崿F(xiàn)頁面跳轉(zhuǎn)傳遞參數(shù)(實體,對象)

    微信小程序?qū)崿F(xiàn)頁面跳轉(zhuǎn)傳遞參數(shù)(實體,對象)

    這篇文章主要介紹了微信小程序?qū)崿F(xiàn)頁面跳轉(zhuǎn)傳遞參數(shù)(實體,對象),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • Javascript中正則表達式的全局匹配模式分析

    Javascript中正則表達式的全局匹配模式分析

    先看一道JavaScript題目,據(jù)說是國內(nèi)某知名互聯(lián)網(wǎng)企業(yè)的JavaScript筆試題,如果對正則的全局匹配模式不了解的話可能會對下面的輸出結(jié)果感到疑惑。
    2011-04-04
  • webpack 模塊熱替換原理

    webpack 模塊熱替換原理

    這篇文章主要介紹了webpack 模塊熱替換原理,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-04-04
  • 談一談javascript中繼承的多種方式

    談一談javascript中繼承的多種方式

    本文就和大家談一談javascript中的繼承,什么是繼承,繼承的作用,以及js繼承的實現(xiàn)代碼,感興趣的小伙伴們可以參考一下
    2016-02-02
  • js模仿html5 placeholder適應(yīng)于不支持的瀏覽器

    js模仿html5 placeholder適應(yīng)于不支持的瀏覽器

    html5原生支持placeholder,對于不支持的瀏覽器(ie)可用js模擬實現(xiàn),不要走開,接下來為您詳細介紹實現(xiàn)方法
    2013-01-01

最新評論