最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JavaScript中常見的繼承方式總結

 更新時間:2022年11月15日 11:56:45   作者:beckyyyy  
這篇文章主要和大家詳細介紹了JavaScript中常見的幾種繼承方式,文中的示例代碼講解詳細,對我們學習JavaScript有一定幫助,需要的小伙伴可以參考下面文章詳細內容

JS和Java中雖然都有對象的概念,但這兩種對象卻大有不同。Java的對象是基于類創(chuàng)建的,JS的對象卻是基于一個特殊的對象——原型對象——創(chuàng)建的,之前看到一個蓋房子的比喻,在Java中蓋房子是先畫好圖紙再蓋房子,JS中蓋房子卻是先蓋一個樣板房再蓋其他房子,覺得也挺貼切。

所以JS中的繼承和Java中的繼承就大有不同了,是基于原型對象的,如果兩個對象形成繼承關系,那必然是其中一個對象的原型鏈上存在一個指針指向另一個對象。即使JS中的兩個類聲明了繼承關系,也是表現在原型對象上。比如:

class A {
    say() {
        console.log('say: hello!');
    }
}

class B extends A {
    constructor() {
        super();
    }
}

console.log(A.prototype); // {constructor: ?, say: ?}
console.log(B.__proto__); // class A {}
console.log(B.prototype); // A?{constructor: ?}

首先,類是JS中函數的語法糖,并且在JS中函數本身也是對象,也就是說A和B是兩個對象,所以extends操作使得B自身的原型屬性__proto__指向了A,相當于const B = Object.create(A);

其次,類的繼承關系也影響其生成的實例,眾所周知,函數本身存在一個特殊的對象屬性:prototype,函數經過構造調用產生的實例的原型屬性__proto__是指向這個對象的,而extends操作修改了B的prototype對象,所以B實例上的原型屬性__proto__也就被修改了,通過B實例的原型屬性__proto__能找到A的prototype,即在B實例的原型鏈上能找到A的prototype。

const b = new B();
console.log(b.__proto__); // A?{constructor: ?} 即B.prototype
console.log(b.__proto__.__proto__); // {constructor: ?, say: ?} 即A.prototype

在JS中使用字面量定義的對象時,其默認的原型屬性__proto__指向Object的prototype對象,相當于默認繼承自Object,所以字面量對象可以調用Object的實例方法。

可以使用isPrototypeOf來判斷一個對象是否在另一個對象的原型鏈上。

由上述可知,JS中的繼承關系與原型對象密切相關,為了達到繼承的關聯關系(共享某些屬性和方法),就要從原型對象著手:

1.使用Object.create的方式創(chuàng)建對象,使兩個對象直接產生繼承關系

const o1 = {
    name: 'o1',
    age: 18,
    walk() {
        console.log('walking...')
    }
};
const o2 = Object.create(o1);
console.log(o2.__proto__); // {name: 'o1', age: 18}
console.log(o2.walk()); // walking...
console.log(o1.isPrototypeOf(o2)); // true

2.使用new操作創(chuàng)建對象,使產生的實例和類(或函數)的原型對象產生繼承關系

const b = new B();
console.log(B.prototype); // A?{constructor: ?}
console.log(b.__proto__); // A?{constructor: ?} 即B.prototype
console.log(B.prototype.isPrototypeOf(b)); // true

3.使用extends關鍵字使類形成繼承關系,擴展類實例的原型鏈

class A {
    say() {
        console.log('say: hello!');
    }
}

class B extends A {
    constructor() {
        super();
    }
}

console.log(A.prototype); // {constructor: ?, say: ?}
const b = new B();
console.log(b.__proto__.__proto__); // {constructor: ?, say: ?} 即A.prototype
console.log(A.isPrototypeOf(B)); // true
console.log(A.isPrototypeOf(b)); // false
console.log(A.prototype.isPrototypeOf(b)); // true

4.修改函數的prototype屬性使函數形成繼承關系,擴展函數實例的原型鏈

function C() {
    this.name = 'c';
    this.operation = function() { return 'printing...'};
}
function D() {}
D.prototype = new C();
const d = new D();
console.log(d.__proto__.__proto__ === C.prototype); // true
console.log(C.prototype.isPrototypeOf(d)); // true
console.log(D.prototype.isPrototypeOf(d)); // true

這里存在一個問題,就是子類實例化時無法向父類的構造函數傳參

5.盜用父類構造函數

在函數內部通過call或apply調用父類函數(非構造調用),可繼承父類實例自身(非原型對象)的屬性和方法(相當于把子類實例(即this)傳遞進父類函數,對這個this做了一遍操作),雖然可在初始化時傳遞參數給父類,但無法形成原型鏈

function E() {
    C.call(this);
    this.do = function () { return 'do homework'; }
}
const e = new E();
console.log(E.prototype.isPrototypeOf(e)); // true
console.log(C.prototype.isPrototypeOf(e)); // false
console.log(e); // E?{name: 'c', operation: ?, do: ?}
console.log(e.do()); // do homework

子類產生的實例無法對父類及其原型對象應用instanceof和isPrototypeOf方法。

此時如果父類想共享方法給子類,必須把方法直接在定義在函數內部,綁定到實例上,而無法通過父類的prototype對象共享。

6.結合4和5,使得子類實例可繼承父類原型對象的屬性和方法,且能形成原型鏈

function E() {
    C.call(this);
    this.do = function () { return 'do homework'; }
}
E.prototype = new C();
const e = new E();
console.log(E.prototype.isPrototypeOf(e)); // true
console.log(C.prototype.isPrototypeOf(e)); // true
console.log(e); // E?{name: 'c', operation: ?, do: ?}
console.log(e.do()); // do homework

7.用Object.create()替換new父類實例來重寫子類的原型對象

function inheritatePrototype(subT, superT) {
  let proto = Object.create(superT.prototype);
  proto.constructor = subT;
  subT.prototype = proto;
}

inheritatePrototype(E, C);

可以舍去new中不需要的操作

8.通過工廠方式共享屬性和方式

類似工廠函數,但不是用裸的Object,以某種方式取得對象(如new等返回新對象的函數),對此對象加屬性或方法以增強功能,并返回對象。

function createAnother(original) {
  let clone = Object.create(original);
  clone.xx = xxx;
  return clone;
}

適合主要關注對象,而不在乎類型和構造函數的場景

存在的問題: 必須在構造函數中定義方法(屬于實例非原型對象的方法),函數不能重用

到此這篇關于JavaScript中常見的繼承方式總結的文章就介紹到這了,更多相關JavaScript繼承方式內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

最新評論

庐江县| 响水县| 中超| 武冈市| 林州市| 嘉祥县| 平乐县| 南岸区| 璧山县| 庆城县| 武宣县| 稷山县| 白银市| 九江县| 文山县| 监利县| 林西县| 大荔县| 吕梁市| 十堰市| 都昌县| 吐鲁番市| 齐河县| 尼勒克县| 普陀区| 重庆市| 武陟县| 义乌市| 略阳县| 青川县| 卓资县| 宝兴县| 云和县| 镇安县| 东丰县| 廊坊市| 连南| 佛山市| 南安市| 夹江县| 和平县|