摘要:在節(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)。
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); // true1.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.prototype1.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 ---> null2 繼承
在面向?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
摘要:忍者級別的函數(shù)操作對于什么是匿名函數(shù),這里就不做過多介紹了。我們需要知道的是,對于而言,匿名函數(shù)是一個很重要且具有邏輯性的特性。通常,匿名函數(shù)的使用情況是創(chuàng)建一個供以后使用的函數(shù)。 JS 中的遞歸 遞歸, 遞歸基礎(chǔ), 斐波那契數(shù)列, 使用遞歸方式深拷貝, 自定義事件添加 這一次,徹底弄懂 JavaScript 執(zhí)行機制 本文的目的就是要保證你徹底弄懂javascript的執(zhí)行機制,如果...
摘要:有了原型鏈,就有了繼承,繼承就是一個對象像繼承遺產(chǎn)一樣繼承從它的構(gòu)造函數(shù)中獲得一些屬性的訪問權(quán)。這里其實就是一個原型鏈與繼承的典型例子,開發(fā)中可能構(gòu)造函數(shù)復(fù)雜一點,屬性定義的多一些,但是原理都是一樣的。 作用域、原型鏈、繼承與閉包詳解 注意:本章講的是在es6之前的原型鏈與繼承。es6引入了類的概念,只是在寫法上有所不同,原理是一樣的。 幾個面試常問的幾個問題,你是否知道 insta...
摘要:有了原型鏈,就有了繼承,繼承就是一個對象像繼承遺產(chǎn)一樣繼承從它的構(gòu)造函數(shù)中獲得一些屬性的訪問權(quán)。這里其實就是一個原型鏈與繼承的典型例子,開發(fā)中可能構(gòu)造函數(shù)復(fù)雜一點,屬性定義的多一些,但是原理都是一樣的。 作用域、原型鏈、繼承與閉包詳解 注意:本章講的是在es6之前的原型鏈與繼承。es6引入了類的概念,只是在寫法上有所不同,原理是一樣的。 幾個面試常問的幾個問題,你是否知道 insta...
摘要:函數(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)生改變的方式。因此,...
閱讀 799·2021-10-09 09:44
閱讀 704·2019-08-30 13:55
閱讀 3162·2019-08-29 15:07
閱讀 3228·2019-08-29 13:09
閱讀 2420·2019-08-29 11:10
閱讀 1297·2019-08-26 14:05
閱讀 3604·2019-08-26 13:57
閱讀 2212·2019-08-23 16:42