成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

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

ziwenxie / 1641人閱讀

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

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

1 原型鏈 1.1 原型鏈定義

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

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

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

例如:

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)建對象與生成原型鏈 1.2.1 使用 Object.create 創(chuàng)建對象

ECMAScript 5 中引入了一個新方法:Object.create()。可以調(diào)用這個方法來創(chuàng)建一個新對象。新對象的原型就是調(diào)用 create 方法時傳入的第一個參數(shù)。

例如:

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

在 JavaScript 中,構(gòu)造函數(shù)其實就是一個普通的函數(shù),一般函數(shù)名首字母大寫。當(dāng)使用 new 操作符 來作用這個函數(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)建對象,經(jīng)歷了如下三個關(guān)鍵步驟:

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

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

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

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

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

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

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

因此我們將父類的實例對象作為子類的prototype即能夠達到繼承的目的,如下圖所示:

繼承的實現(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);
}

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

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

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

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

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

最后上一張js高級程序設(shè)計第三版中的一張源于原型鏈繼承的圖

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

下面利用ES6引入的新語法糖,class、extends關(guān)鍵字對上述實現(xià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 對應(yīng)原來的構(gòu)造函數(shù)

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

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

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

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

后續(xù)

function A() {
}
//函數(shù)默認會有一個prototype對象并且具有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  是同一個對象的__proto__  如果找到就為true

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

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/86638.html

相關(guān)文章

  • JavasScript重難點知識

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

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

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

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

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

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

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

    cfanr 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<