亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

徹底理解Javascript中的原型鏈與繼承

ziwenxie / 1711人閱讀

摘要:在節(jié)中,我們學(xué)習(xí)到了通過(guò)構(gòu)造函數(shù)創(chuàng)建對(duì)象的三個(gè)重要步驟,其中的一步是把構(gòu)造函數(shù)的對(duì)象設(shè)置為創(chuàng)建對(duì)象的原型。利用而不是直接用創(chuàng)建一個(gè)實(shí)例對(duì)象的目的是,減少一次調(diào)用父構(gòu)造函數(shù)的執(zhí)行。

JavaScript語(yǔ)言不像面向?qū)ο蟮木幊陶Z(yǔ)言中有類的概念,所以也就沒有類之間直接的繼承,JavaScript中只有對(duì)象,使用函數(shù)模擬類,基于對(duì)象之間的原型鏈來(lái)實(shí)現(xiàn)繼承關(guān)系,
ES6的語(yǔ)法中新增了class關(guān)鍵字,但也只是語(yǔ)法糖,內(nèi)部還是通過(guò)函數(shù)和原型鏈來(lái)對(duì)類和繼承進(jìn)行實(shí)現(xiàn)。

1 原型鏈 1.1 原型鏈定義

JavaScript對(duì)象上都有一個(gè)內(nèi)部指針[[Prototype]],指向它的原型對(duì)象,而原型對(duì)象的內(nèi)部指針[[Prototype]]也指向它的原型對(duì)象,直到原型對(duì)象為null,這樣形成的鏈條就稱為原型鏈。

這樣在訪問(wèn)對(duì)象的屬性時(shí),會(huì)現(xiàn)在自己的屬性中查找,如果不存在則會(huì)到上一層原型對(duì)象中查找。

注意:
根據(jù) ECMAScript 標(biāo)準(zhǔn),someObject.[[Prototype]] 符號(hào)是用于指派 someObject 的原型。這個(gè)等同于 JavaScript 的 proto 屬性(現(xiàn)已棄用)。從 ECMAScript 6 開始, [[Prototype]] 可以用Object.getPrototypeOf()和Object.setPrototypeOf()訪問(wèn)器來(lái)訪問(wèn)。

例如:

var obj2 = {
    height: 170
}
var obj3 = {
    name: "obj3"
}
Object.setPrototypeOf(obj3, obj2);
console.log(obj3.height); // 170
var isproto = Object.getPrototypeOf(obj3) === obj2;
console.log(isproto); // true
1.2 不同方法創(chuàng)建對(duì)象與生成原型鏈 1.2.1 使用 Object.create 創(chuàng)建對(duì)象

ECMAScript 5 中引入了一個(gè)新方法:Object.create()??梢哉{(diào)用這個(gè)方法來(lái)創(chuàng)建一個(gè)新對(duì)象。新對(duì)象的原型就是調(diào)用 create 方法時(shí)傳入的第一個(gè)參數(shù)。

例如:

var a = {a: 1};
// a ---> Object.prototype ---> null
 
var b = Object.create(a);
// b ---> a ---> Object.prototype ---> null
console.log(b.a); // 1 (繼承而來(lái))
 
var c = Object.create(b);
// c ---> b ---> a ---> Object.prototype ---> null
 
var d = Object.create(null);
// d ---> null
console.log(d.hasOwnProperty); // undefined, 因?yàn)閐沒有繼承Object.prototype
1.2.2 使用構(gòu)造函數(shù)創(chuàng)建對(duì)象

在 JavaScript 中,構(gòu)造函數(shù)其實(shí)就是一個(gè)普通的函數(shù),一般函數(shù)名首字母大寫。當(dāng)使用 new 操作符 來(lái)作用這個(gè)函數(shù)時(shí),它就可以被稱為構(gòu)造方法(構(gòu)造函數(shù))。
例如:

function Person (name, age) {
    this.name = name;
    this.age = age;
}
 
Person.prototype = {
    sayName: function () {
        console.log(this.name);
    }
}
var person1 = new Person("yangyiliang", 23);
person1.sayName(); // yangyiliang

使用構(gòu)造函數(shù)創(chuàng)建對(duì)象,經(jīng)歷了如下三個(gè)關(guān)鍵步驟:

var temp = {}; //1  創(chuàng)建空對(duì)象
Person.call(temp, "yangyiliang", 23); //2  以空對(duì)象為this執(zhí)行構(gòu)造函數(shù)
Object.setPrototypeOf(temp, Person.prototype); //3  將構(gòu)造函數(shù)的prototype 設(shè)置為空對(duì)象的原型
return temp;
1.2.3 使用字面量方法創(chuàng)建對(duì)象

使用字面量方法創(chuàng)建的對(duì)象,根據(jù)對(duì)象的類型,他們的原型都會(huì)指向相應(yīng)JavaScript內(nèi)置構(gòu)造函數(shù)的prototype,和直接使用內(nèi)置構(gòu)造函數(shù)創(chuàng)建對(duì)象生成的原型鏈相同,例如:

var o = {a: 1};
 
// o這個(gè)對(duì)象繼承了Object.prototype上面的所有屬性
// 所以可以這樣使用 o.hasOwnProperty("a").
// hasOwnProperty 是Object.prototype的自身屬性。
// Object.prototype的原型為null。
// 原型鏈如下:
// o ---> Object.prototype ---> null
 
var a = ["yo", "whadup", "?"];
 
// 數(shù)組都繼承于Array.prototype
// (indexOf, forEach等方法都是從它繼承而來(lái)).
// 原型鏈如下:
// a ---> Array.prototype ---> Object.prototype ---> null
 
function f(){
  return 2;
}
 
// 函數(shù)都繼承于Function.prototype
// (call, bind等方法都是從它繼承而來(lái)):
// f ---> Function.prototype ---> Object.prototype ---> null
2 繼承

在面向?qū)ο蟮恼Z(yǔ)言當(dāng)中,繼承關(guān)系應(yīng)該指的是父類和子類之間的關(guān)系,子類繼承父類的屬性和方法,在JavaScript當(dāng)中是父構(gòu)造函數(shù)和子構(gòu)造函數(shù)之間的關(guān)系。

類本身是對(duì)象的抽象形式,類的使用價(jià)值最后也是在于通過(guò)它能夠創(chuàng)建對(duì)象,
所以子類能夠繼承父類的屬性和方法的意義,就是通過(guò)子類創(chuàng)建出來(lái)的對(duì)象能夠繼承通過(guò)父類創(chuàng)建出來(lái)的對(duì)象的屬性和方法。

而這種對(duì)象之間的繼承關(guān)系,就是通過(guò)原型鏈實(shí)現(xiàn)。

在1.2.2節(jié)中,我們學(xué)習(xí)到了通過(guò)構(gòu)造函數(shù)創(chuàng)建對(duì)象的三個(gè)重要步驟,其中的一步是把構(gòu)造函數(shù)的prototype對(duì)象設(shè)置為創(chuàng)建對(duì)象的原型。

因此我們將父類的實(shí)例對(duì)象作為子類的prototype即能夠達(dá)到繼承的目的,如下圖所示:

繼承的實(shí)現(xiàn)

function Person (name, age) {
    this.name = name;
    this.age = age
}
 
Person.prototype.sayName = function () {
    console.log("my name is " + this.name);
}
 
function Student (name, age, school) {
    Person.call(this, name, age);
    this.school = school;
}
 
Student.prototype = Object.create(Person.prototype);
 
Student.prototype.saySchool = function () {
    console.log("my school is " + this.school);
}

上面代碼實(shí)現(xiàn)的繼承,遵循了幾個(gè)原則:

1、因?yàn)闃?gòu)造函數(shù)創(chuàng)建的對(duì)象將公用同一個(gè)原型,所以將每個(gè)對(duì)象獨(dú)有的屬性寫在構(gòu)造函數(shù)中,將對(duì)象之間可以公用的方法寫在構(gòu)造函數(shù)的prototype中,也就是對(duì)象的原型中

2、子構(gòu)造函數(shù)繼承父構(gòu)造函數(shù)做了兩個(gè)地方的工作,一是在子構(gòu)造函數(shù)中利用call,調(diào)用父構(gòu)造函數(shù)的方法,二是利用Object.create方法創(chuàng)建一個(gè)以父構(gòu)造函數(shù)的prototype為原型的對(duì)象。

利用Object.create而不是直接用new 創(chuàng)建一個(gè)實(shí)例對(duì)象的目的是,減少一次調(diào)用父構(gòu)造函數(shù)的執(zhí)行。

3、先通過(guò)prototype屬性指向父構(gòu)造函數(shù)的實(shí)例,然后再向prototype添加想要放在原型上的方法。

最后上一張js高級(jí)程序設(shè)計(jì)第三版中的一張?jiān)从谠玩溊^承的圖

利用class實(shí)現(xiàn)繼承

下面利用ES6引入的新語(yǔ)法糖,class、extends關(guān)鍵字對(duì)上述實(shí)現(xiàn)繼承的代碼進(jìn)行改寫:

class Person {
    constructor (name, age) {
        this.name = name;
        this.age = age;
    }
 
    sayName () {
        console.log("my name is " + this.name);
    }
}
 
class Student extends Person {
    constructor (name, age, school) {
        super(name, age);
        this.school = school;
    }
 
    saySchool () {
        console.log("my school is " + this.school);
    }
}

class里的constructor 對(duì)應(yīng)原來(lái)的構(gòu)造函數(shù)

class里面的其他方法都是寫在原來(lái)構(gòu)造函數(shù)的prototype中的

子類直接通過(guò)extends 關(guān)鍵字進(jìn)行繼承

子類中可以通過(guò)super來(lái)調(diào)用父類中的方法

本文部分內(nèi)容來(lái)自 https://developer.mozilla.org...

后續(xù)

function A() {
}
//函數(shù)默認(rèn)會(huì)有一個(gè)prototype對(duì)象并且具有constructor屬性指向他本身

var a = new A()

a instanceof A


function A() {
}

function B() {
}

var proto = {}

B.prototype = proto

A.prototype = proto
var a = new A()
a instanceof B //true
a instanceof Object //true

instanceof  是遍歷a 的原型鏈 尋找是否有和 B.prototype  是同一個(gè)對(duì)象的__proto__  如果找到就為true

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/86638.html

相關(guān)文章

  • JavasScript重難點(diǎn)知識(shí)

    摘要:忍者級(jí)別的函數(shù)操作對(duì)于什么是匿名函數(shù),這里就不做過(guò)多介紹了。我們需要知道的是,對(duì)于而言,匿名函數(shù)是一個(gè)很重要且具有邏輯性的特性。通常,匿名函數(shù)的使用情況是創(chuàng)建一個(gè)供以后使用的函數(shù)。 JS 中的遞歸 遞歸, 遞歸基礎(chǔ), 斐波那契數(shù)列, 使用遞歸方式深拷貝, 自定義事件添加 這一次,徹底弄懂 JavaScript 執(zhí)行機(jī)制 本文的目的就是要保證你徹底弄懂javascript的執(zhí)行機(jī)制,如果...

    forsigner 評(píng)論0 收藏0
  • Js基礎(chǔ)知識(shí)(二) - 原型鏈與繼承精彩的講解

    摘要:有了原型鏈,就有了繼承,繼承就是一個(gè)對(duì)象像繼承遺產(chǎn)一樣繼承從它的構(gòu)造函數(shù)中獲得一些屬性的訪問(wèn)權(quán)。這里其實(shí)就是一個(gè)原型鏈與繼承的典型例子,開發(fā)中可能構(gòu)造函數(shù)復(fù)雜一點(diǎn),屬性定義的多一些,但是原理都是一樣的。 作用域、原型鏈、繼承與閉包詳解 注意:本章講的是在es6之前的原型鏈與繼承。es6引入了類的概念,只是在寫法上有所不同,原理是一樣的。 幾個(gè)面試常問(wèn)的幾個(gè)問(wèn)題,你是否知道 insta...

    mrcode 評(píng)論0 收藏0
  • Js基礎(chǔ)知識(shí)(二) - 原型鏈與繼承精彩的講解

    摘要:有了原型鏈,就有了繼承,繼承就是一個(gè)對(duì)象像繼承遺產(chǎn)一樣繼承從它的構(gòu)造函數(shù)中獲得一些屬性的訪問(wèn)權(quán)。這里其實(shí)就是一個(gè)原型鏈與繼承的典型例子,開發(fā)中可能構(gòu)造函數(shù)復(fù)雜一點(diǎn),屬性定義的多一些,但是原理都是一樣的。 作用域、原型鏈、繼承與閉包詳解 注意:本章講的是在es6之前的原型鏈與繼承。es6引入了類的概念,只是在寫法上有所不同,原理是一樣的。 幾個(gè)面試常問(wèn)的幾個(gè)問(wèn)題,你是否知道 insta...

    lingdududu 評(píng)論0 收藏0
  • JavaScript系列(四) - 收藏集 - 掘金

    摘要:函數(shù)式編程前端掘金引言面向?qū)ο缶幊桃恢币詠?lái)都是中的主導(dǎo)范式。函數(shù)式編程是一種強(qiáng)調(diào)減少對(duì)程序外部狀態(tài)產(chǎn)生改變的方式。 JavaScript 函數(shù)式編程 - 前端 - 掘金引言 面向?qū)ο缶幊桃恢币詠?lái)都是JavaScript中的主導(dǎo)范式。JavaScript作為一門多范式編程語(yǔ)言,然而,近幾年,函數(shù)式編程越來(lái)越多得受到開發(fā)者的青睞。函數(shù)式編程是一種強(qiáng)調(diào)減少對(duì)程序外部狀態(tài)產(chǎn)生改變的方式。因此,...

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

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

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<