JavaScript 之 面向對象 [ 繼承 ]

繼承

描述

  • 在一個構造函數或對象中定義的屬性或方法,能夠在另外一個構造函數或對象中直接使用,而不須要在去從新定義

原型鏈

  • 一個構造函數或對象的原型指向另外一個構造函數或對象,以此類推造成一條鏈狀結構,這種效果被稱爲原型鏈
  • 這種原型鏈也能夠稱爲 繼承
/* 定義第一個構造函數 */
function A(){
    this.a = 'a';
}
/* 建立對象 */
var a = new A();

/* 定義第二個構造函數 */
function B(){
    this.b = 'b';
}
/* 將B的原型指向對象a */
B.prototype = a;
/* 建立對象 */
var b = new B();

console.log( b.b );// 顯示 b
console.log( b.a );// 顯示 a

/* 定義第三個構造函數 */
function C(){
    this.c = 'c';
}
/* 將C的原型指向對象b */
C.prototype = b;
/* 建立對象 */
var c = new C();

console.log( c.c );// 顯示 c
console.log( c.b );// 顯示 b
console.log( c.a );// 顯示 a

只繼承於原型

  • 一個構造函數的原型指向另外一個構造函數的原型
  • 能夠理解爲原型鏈的一種優化(我的理解)
/* 定義第一個構造函數 */
function A(){
    // 將自有屬性改寫爲原型屬性
    // this.a = 'a';
}
A.prototype.a = 'a';

/* 定義第二個構造函數 */
function B(){
    // this.b = 'b';
}

/* 將B的原型指向A的原型 */
B.prototype = A.prototype;
/*
    將B的自有屬性改寫成原型屬性
     * 要先去執行原型的指向
     * 在去改寫屬性
     * 若是代碼的執行順序反過來會變成對屬性的從新賦值
 */
B.prototype.b = 'b';

/* 定義第三個構造函數 */
function C(){
    this.c = 'c';
}
/* 將C的原型指向B的原型 */
C.prototype = B.prototype;
/* 建立對象 */
var c = new C();
console.log(c.c);// 顯示 c
console.log(c.b);// 顯示 b
console.log(c.a);// 顯示 a

原型式繼承

  • 定義一個函數,在該函數中建立一個構造函數,再將構造函數建立的對象返回,用於實現繼承
/* 定義一個函數 */
function fun( obj, values ) {
    /* 定義一個構造函數 */
    function Fn() {
        /* 遍歷構造函數的屬性和方法 */
        for ( var key in values ) {
            this[key] = values[key];
        }
    }
    /* 將函數的參數當作構造函數的原型 */
    Fn.prototype = obj;
    /* 將構造函數建立的對象作爲函數的返回值 */
    return new Fn();
}
/* 定義一個對象 */
var obj = {
    name : '唐三'
}
/* 調用函數 - 將構造函數的自有屬性或方法以參數傳入 */
var f = fun( obj, {
    nian : 20,
    menpai : function () {
        console.log( '唐門' );
    }
} );
/* 調用屬性和方法 */
console.log( f.name );// 顯示 唐三
console.log( f.nian );// 顯示 20
f.menpai();// 顯示 唐門

Object.create()方法

  • 使用Object.create()方法也能夠實現繼承
/* 定義一個對象 */
var obj1 = {
    name : '融念冰'
}
var s = Object.create( obj1, {
    /* 定義屬性或方法時,值須要以對象的形式表示 */
    nian : {
        value : 20
    }
} );
/* 調用屬性 */
console.log( s.name );// 顯示 融念冰
console.log( s.nian );// 顯示 20

藉助構造函數

  • 可用過在子級的構造函數中調用父級的構造函數,來實現繼承效果
/* 定義父級構造函數 */
function Fun() {
    /* 這裏的this指向調用的參數 */
    this.fuji = '哈哈哈';
}

/* 定義子級構造函數 */
function Fn() {
    /* 在子級構造函數中調用父級構造函數中的屬性 */
    Fun.apply( this );// 這裏的this指向當前構造函數的對象(構造函數Fn)
    /* 這裏的this表示當前調用屬性的對象 */
    this.ziji = '呀呀呀';
}
/* 建立子級對象 */
var ziji = new Fn();
console.log( ziji );// 顯示 Fn { fuji: '哈哈哈', ziji: '呀呀呀' }

組合式繼承

  • 將原型式繼承和藉助構造函數式繼承有效的結合在一塊兒
  • 分開繼承自有屬性和原型屬性
/* 定義父級構造函數 */
function Fun() {
    /* 這裏的this指向調用的參數 */
    this.name = '唐三';
}
/* 添加原型屬性 */
Fun.prototype.nian = 20;

/* 定義子級構造函數 */
function Fn() {
    /* 在子級構造函數中調用父級構造函數中的屬性 - 繼承父級的自有屬性 */
    Fun.apply( this );// 這裏的this指向當前構造函數的對象(構造函數Fn)
    /* 這裏的this表示當前調用屬性的對象 */
    this.menpai = '唐門';
}
/* 繼承父級的原型屬性 */
Fn.prototype = Fun.prototype;

/* 建立子級對象 */
var ziji = new Fn();
/* 調用屬性 */
console.log( ziji.name );// 顯示 唐三
console.log( ziji.nian );// 顯示 20
console.log( ziji.menpai );// 顯示 唐門
相關文章
相關標籤/搜索