成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

JavaScript · 原型繼承

Profeel / 1211人閱讀

摘要:這樣肯定不行,給添加方法或影響到這種方式有一個(gè)缺點(diǎn),在一個(gè)實(shí)例時(shí)會(huì)調(diào)用兩次構(gòu)造函數(shù)一次是,另一次是,浪費(fèi)效率,且如果構(gòu)造函數(shù)有副作用,重復(fù)調(diào)用可能造成不良后果。

寫在前面

此文只涉及基于原型的繼承,ES6之后基于Class的繼承請(qǐng)參考相關(guān)文獻(xiàn)。

知識(shí)儲(chǔ)備
構(gòu)造函數(shù)的兩種調(diào)用方式(結(jié)果完全不同)

通過(guò)關(guān)鍵字new調(diào)用:

function Person(name) {
    this.name = name;
    this.age = 18;
}
var o = new Person("hx");
console.log(o.name, o.age);
// hx 18
console.log(window.name, window.age);
// "" undefined

直接調(diào)用:

function Person(name) {
    this.name = name;
    this.age = 18;
}
var o = Person("hx");
console.log(o);
// undefined
console.log(window.name, window.age);
// hx 18

由此可見:

構(gòu)造函數(shù)與普通函數(shù)無(wú)異,可直接調(diào)用,無(wú)返回值,this指向Window;

通過(guò)new調(diào)用的話,返回值為一個(gè)對(duì)象,且this指向該對(duì)象

new到底做了什么?

new關(guān)鍵字會(huì)進(jìn)行如下操作:

創(chuàng)建一個(gè)空對(duì)象;

鏈接該對(duì)象到另一個(gè)對(duì)象(即:設(shè)置該對(duì)象的構(gòu)造函數(shù));

將第一步創(chuàng)建的空對(duì)象作為this的上下文(this指向該空對(duì)象);

執(zhí)行構(gòu)造函數(shù)(為對(duì)象添加屬性),并返回該對(duì)象

function Person(name) {
    this.name = name;
    this.age = 18;
}
var o = new Person("hx");

上述代碼對(duì)應(yīng)的四步操作是:

var obj = {};

obj.__proto__ = Person.prototype;

Person.call(obj,"hx");

return obj;

JavaScript實(shí)現(xiàn)繼承的幾種方式

1.原型鏈繼承

function Parent(name) {
    this.name = name;
    this.age = 18;
    this.arr = ["hello","world"]
}
Parent.prototype.sayAge = function() {
    console.log(this.age)
}

function Child(gender) {
    this.gender = gender;
}
Child.prototype = new Parent();

var child1 = new Child("male");
child1.arr.push("js")
console.log(child1.name); // undefined
console.log(child1.age); // 18
console.log(child1.arr); // ["hello","world","js"]
console.log(child1.gender); // male
child1.sayAge(); // 18

var child2 = new Child("female");
console.log(child2.name); // undefined
console.log(child2.age); // 18
console.log(child2.arr); // ["hello","world","js"]
console.log(child2.gender); // female
child2.sayAge(); // 18

優(yōu)點(diǎn):

Parent原型對(duì)象上的方法可以被Child繼承

缺點(diǎn):

Parent的引用類型屬性會(huì)被所有Child實(shí)例共享,互相干擾

Child無(wú)法向Parent傳參

2.構(gòu)造函數(shù)繼承(經(jīng)典繼承)

function Parent(name) {
    this.name = name;
    this.age = 18;
    this.arr = ["hello","world"];
    this.sayName = function() {
        console.log(this.name)
    }
}
Parent.prototype.sayAge = function() {
    console.log(this.age)
}

function Child(name,gender) {
    Parent.call(this,name); // this由Window指向待創(chuàng)建對(duì)象
    this.gender = gender;
}

var child1 = new Child("lala","male");
child1.arr.push("js");
console.log(child1.name); // lala
console.log(child1.age); // 18
console.log(child1.arr); // ["hello","world","js"]
console.log(child1.gender); // male
child1.sayName(); // 18
child1.sayAge(); // Uncaught TypeError: child1.sayAge is not a function

var child2 = new Child("fafa","female");
console.log(child2.name); // fafa
console.log(child2.age); // 18
console.log(child2.arr); // ["hello","world"]
console.log(child2.gender); // female
child2.sayName(); // 18
child2.sayAge(); // Uncaught TypeError: child1.sayAge is not a function

優(yōu)點(diǎn):

避免了引用類型屬性被所有Child實(shí)例共享

Child可以向Parent傳參

缺點(diǎn):

Parent原型對(duì)象上的方法無(wú)法被Child繼承

每次創(chuàng)建Child實(shí)例都會(huì)創(chuàng)建sayName方法,造成內(nèi)存資源的浪費(fèi)

3.組合繼承

function Parent(name,age) {
    this.name = name;
    this.age = age;
    this.arr = ["hello","world"]
}
Parent.prototype.sayName = function() {
    console.log(this.name)
}

function Child(name,age,gender) {
    Parent.call(this,name,age);
    this.gender = gender
}
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constuctor = Child;
Child.prototype.sayAge = function() {
    console.log(this.age)
}

var child1 = new Child("lala",18,"male");
child1.arr.push("js");
child1.name; // "lala"
child1.age; // 18
child1.arr; // ["hello","world","js"]
child1.gender; // "male"
child1.sayName(); // lala
child1.sayAge(); // 18

var child2 = new Child("fafa",28,"female");
child1.name; // "fafa"
child1.age; // 28
child1.arr; // ["hello","world"]
child1.gender; // "female"
child1.sayName(); // fafa
child1.sayAge(); // 28

組合繼承是JavaScript繼承的最佳實(shí)踐

屬性使用構(gòu)造函數(shù)繼承 - 避免了Parent引用屬性被多個(gè)Child實(shí)例影響,同時(shí)支持傳參

方法使用原型鏈繼承 - 支持Child繼承Parent原型對(duì)象方法,避免了多實(shí)例中方法的重復(fù)拷貝

補(bǔ)充 1

對(duì)于組合繼承代碼中的Child.prototype = Object.create(Parent.prototype),還有兩種類型的方法:

Child.prototype = Parent.prototype或者Child.prototype = new Parent()

Child.prototype = Parent.prototype:這樣肯定不行,給Child.prototype添加方法或影響到Parent;

Child.prototype = new Parent():這種方式有一個(gè)缺點(diǎn),在new一個(gè)Child實(shí)例時(shí)會(huì)調(diào)用兩次Parent構(gòu)造函數(shù)(一次是new Parent(),另一次是Parent.call(this,name)),浪費(fèi)效率,且如果Parent構(gòu)造函數(shù)有副作用,重復(fù)調(diào)用可能造成不良后果。

對(duì)于第二種情況,除了使用Object.create(Parent.prototype)這種方法外,還可以借助一個(gè)橋接函數(shù)實(shí)現(xiàn)。實(shí)際上,不管哪種方法,其實(shí)現(xiàn)思路都是調(diào)整原型鏈:

由:
new Child() ----> Child.prototype ----> Object.prototype ----> null

調(diào)整為:
new Child() ----> Child.prototype ----> Parent.prototype ----> Object.prototype ----> null

function Parent(name) {
    this.name = name
}
Parent.prototype.sayName = function() {
    console.log(this.name)
}

function Child(name,age) {
    Parent.call(this,name);
    this.age = age;
}

function F() {
}

F.prototype = Parent.prototype;
Child.prototype = new F();
Child.prototype.constuctor = Child;

Child.prototype.sayAge = function() {
    console.log(this.age)
}

可見,通過(guò)一個(gè)橋接函數(shù)F,實(shí)現(xiàn)了只調(diào)用了一次 Parent 構(gòu)造函數(shù),并且因此避免了在 Parent.prototype 上面創(chuàng)建不必要的、多余的屬性

// 封裝一下上述方法
function object(o) {
    function F() {}
    F.prototype = o;
    return new F();
}

function prototype(child, parent) {
    var prototype = object(parent.prototype);
    child.prototype = prototype;
    prototype.constructor = child;
}

// 當(dāng)我們使用的時(shí)候:
prototype(Child, Parent);
補(bǔ)充 2

什么是最優(yōu)的繼承方式?

其實(shí)不管是改良的組合繼承(使用 Object.create 也好,還是使用 Object.setPrototypeOf 也好),還是所謂的寄生組合繼承(使用橋接函數(shù)F),都不是回答該問(wèn)題的關(guān)鍵。

最優(yōu)的繼承方式體現(xiàn)的是一種設(shè)計(jì)理念:
不分靜態(tài)屬性還是動(dòng)態(tài)屬性,其維度的劃分標(biāo)準(zhǔn)是:是否可共享

對(duì)于每個(gè)子類都有,但子類實(shí)例相互獨(dú)立的屬性(非共享):應(yīng)該++放到父類的構(gòu)造方法上++,然后通過(guò)子類調(diào)用父類構(gòu)造方法來(lái)實(shí)現(xiàn)初始化;

對(duì)于每個(gè)子類都有,且子類實(shí)例可以共享的屬性(不管是靜態(tài)屬性還是動(dòng)態(tài)屬性):應(yīng)該++放到父類的原型對(duì)象上++,通過(guò)原型鏈獲得;

對(duì)于每個(gè)子類獨(dú)有,且子類實(shí)例相互獨(dú)立的屬性(非共享):應(yīng)該++放到子類的構(gòu)造方法上++實(shí)現(xiàn);

對(duì)于每個(gè)子類獨(dú)有,但子類實(shí)例可以共享的屬性:應(yīng)該++放到子類的原型對(duì)象上++,通過(guò)原型鏈獲得;

從文字上不容易理解,看代碼:

function Man(name,age) {
    // 每個(gè)子類都有,但相互獨(dú)立(非共享)
    this.name = name;
    this.age = age;
}

Man.prototype.say = function() {
    // 每個(gè)子類都有,且共享的動(dòng)態(tài)屬性(共享)
    console.log(`I am ${this.name} and ${this.age} years old.`)
}
// 每個(gè)子類都有,且共享的靜態(tài)屬性(共享)
Man.prototype.isMan = true;

function Swimmer(name,age,weight) {
    Man.call(this,name,age);
    // Swimmer子類獨(dú)有,且各實(shí)例獨(dú)立(非共享)
    this.weight = weight;
}

function BasketBaller(name,age,height) {
    Man.call(this,name,age);
    // BasketBaller子類獨(dú)有,且各實(shí)例獨(dú)立(非共享)
    this.height = height;
}

// 使用ES6直接設(shè)置原型關(guān)系的方法來(lái)構(gòu)建原型鏈
Object.setPrototypeOf(Swimmer.prototype, Man.prototype)
// 等同于 Swimmer.prototype = Object.create(Man.prototype); Swimmer.prototype.constructor = Swimmer;
Object.setPrototypeOf(BasketBaller.prototype, Man.prototype)
// 等同于 BasketBaller.prototype = Object.create(Man.prototype); BasketBaller.prototype.constructor = BasketBaller;

// 繼續(xù)擴(kuò)展子類原型對(duì)象
Swimmer.prototype.getWeight = function() {
    // Swimmer子類獨(dú)有,但共享的動(dòng)態(tài)屬性(共享)
    console.log(this.weight);
}
// Swimmer子類獨(dú)有,但共享的靜態(tài)屬性(共享)
Swimmer.prototype.isSwimmer = true;

var swimmer1 = new Swimmer("swimmer1",11,100);
var swimmer2 = new Swimmer("swimmer2",21,200);

swimmer1; // Swimmer?{name: "swimmer1", age: 11, weight: 100}
swimmer1.isMan; // ture
swimmer1.say(); // I am swimmer1 and 11 years old.
swimmer1.isSwimmer; // ture
swimmer1.getWeight(); // 100

swimmer2; // Swimmer?{name: "swimmer2", age: 21, weight: 200}
swimmer2.isMan; // ture
swimmer2.say(); // I am swimmer2 and 21 years old.
swimmer2.isSwimmer; // ture
swimmer2.getWeight(); // 200

// BasketBaller同理(略)

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/106315.html

相關(guān)文章

  • 理解JavaScript的核心知識(shí)點(diǎn):原型

    摘要:首先,需要來(lái)理清一些基礎(chǔ)的計(jì)算機(jī)編程概念編程哲學(xué)與設(shè)計(jì)模式計(jì)算機(jī)編程理念源自于對(duì)現(xiàn)實(shí)抽象的哲學(xué)思考,面向?qū)ο缶幊淌瞧湟环N思維方式,與它并駕齊驅(qū)的是另外兩種思路過(guò)程式和函數(shù)式編程。 JavaScript 中的原型機(jī)制一直以來(lái)都被眾多開發(fā)者(包括本人)低估甚至忽視了,這是因?yàn)榻^大多數(shù)人沒有想要深刻理解這個(gè)機(jī)制的內(nèi)涵,以及越來(lái)越多的開發(fā)者缺乏計(jì)算機(jī)編程相關(guān)的基礎(chǔ)知識(shí)。對(duì)于這樣的開發(fā)者來(lái)說(shuō) J...

    iKcamp 評(píng)論0 收藏0
  • 白話解釋 Javascript 原型繼承(prototype inheritance)

    摘要:我們有了構(gòu)造函數(shù)之后,第二步開始使用它構(gòu)造一個(gè)函數(shù)。來(lái)個(gè)例子這種方式很簡(jiǎn)單也很直接,你在構(gòu)造函數(shù)的原型上定義方法,那么用該構(gòu)造函數(shù)實(shí)例化出來(lái)的對(duì)象都可以通過(guò)原型繼承鏈訪問(wèn)到定義在構(gòu)造函數(shù)原型上的方法。 來(lái)源: 個(gè)人博客 白話解釋 Javascript 原型繼承(prototype inheritance) 什么是繼承? 學(xué)過(guò)面向?qū)ο蟮耐瑢W(xué)們是否還記得,老師整天掛在嘴邊的面向?qū)ο笕筇?..

    kid143 評(píng)論0 收藏0
  • 徹底搞懂JavaScript中的繼承

    摘要:這正是我們想要的太棒了毫不意外的,這種繼承的方式被稱為構(gòu)造函數(shù)繼承,在中是一種關(guān)鍵的實(shí)現(xiàn)的繼承方法,相信你已經(jīng)很好的掌握了。 你應(yīng)該知道,JavaScript是一門基于原型鏈的語(yǔ)言,而我們今天的主題 -- 繼承就和原型鏈這一概念息息相關(guān)。甚至可以說(shuō),所謂的原型鏈就是一條繼承鏈。有些困惑了嗎?接著看下去吧。 一、構(gòu)造函數(shù),原型屬性與實(shí)例對(duì)象 要搞清楚如何在JavaScript中實(shí)現(xiàn)繼承,...

    _ivan 評(píng)論0 收藏0
  • [譯] 為什么原型繼承很重要

    摘要:使用構(gòu)造函數(shù)的原型繼承相比使用原型的原型繼承更加復(fù)雜,我們先看看使用原型的原型繼承上面的代碼很容易理解。相反的,使用構(gòu)造函數(shù)的原型繼承像下面這樣當(dāng)然,構(gòu)造函數(shù)的方式更簡(jiǎn)單。 五天之前我寫了一個(gè)關(guān)于ES6標(biāo)準(zhǔn)中Class的文章。在里面我介紹了如何用現(xiàn)有的Javascript來(lái)模擬類并且介紹了ES6中類的用法,其實(shí)它只是一個(gè)語(yǔ)法糖。感謝Om Shakar以及Javascript Room中...

    xiao7cn 評(píng)論0 收藏0
  • JavaScript繼承方式及優(yōu)缺點(diǎn)

    摘要:繼承簡(jiǎn)介在的中的面向?qū)ο缶幊?,繼承是給構(gòu)造函數(shù)之間建立關(guān)系非常重要的方式,根據(jù)原型鏈的特點(diǎn),其實(shí)繼承就是更改原本默認(rèn)的原型鏈,形成新的原型鏈的過(guò)程。 showImg(https://segmentfault.com/img/remote/1460000018998684); 閱讀原文 前言 JavaScript 原本不是純粹的 OOP 語(yǔ)言,因?yàn)樵?ES5 規(guī)范中沒有類的概念,在 ...

    nanchen2251 評(píng)論0 收藏0
  • Javascript 設(shè)計(jì)模式讀書筆記(三)——繼承

    摘要:的繼承方式屬于原型式繼承,非常靈活。當(dāng)使用關(guān)鍵字執(zhí)行類的構(gòu)造函數(shù)時(shí),系統(tǒng)首先創(chuàng)建一個(gè)新對(duì)象,這個(gè)對(duì)象會(huì)繼承自構(gòu)造函數(shù)的原型對(duì)象新對(duì)象的原型就是構(gòu)造函數(shù)的屬性。也就是說(shuō),構(gòu)造函數(shù)用來(lái)對(duì)生成的新對(duì)象進(jìn)行一些處理,使這個(gè)新對(duì)象具有某些特定的屬性。 繼承這個(gè)東西在Javascript中尤其復(fù)雜,我掌握得也不好,找工作面試的時(shí)候在這個(gè)問(wèn)題上栽過(guò)跟頭。Javascript的繼承方式屬于原型式繼承,...

    cangck_X 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<