溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

再談javascriptjs原型與原型鏈及繼承相關(guān)問(wèn)題

發(fā)布時(shí)間:2020-06-27 04:43:44 來(lái)源:網(wǎng)絡(luò) 閱讀:234 作者:周陸軍 欄目:web開發(fā)

什么是原型語(yǔ)言 

  1. 只有對(duì)象,沒(méi)有類;對(duì)象繼承對(duì)象,而不是類繼承類。 

  2. “原型對(duì)象”是核心概念。原型對(duì)象是新對(duì)象的模板,它將自身的屬性共享給新對(duì)象。一個(gè)對(duì)象不但可以享有自己創(chuàng)建時(shí)和運(yùn)行時(shí)定義的屬性,而且可以享有原型對(duì)象的屬性。 

  3. 每一個(gè)對(duì)象都有自己的原型對(duì)象,所有對(duì)象構(gòu)成一個(gè)樹狀的層級(jí)系統(tǒng)。root節(jié)點(diǎn)的頂層對(duì)象是一個(gè)語(yǔ)言原生的對(duì)象,只有它沒(méi)有原型對(duì)象,其他所有對(duì)象都直接或間接繼承它的屬性。 

原型語(yǔ)言創(chuàng)建有兩個(gè)步驟 

  1. 使用”原型對(duì)象”作為”模板”生成新對(duì)象 :這個(gè)步驟是必要的,這是每個(gè)對(duì)象出生的唯一方式。以原型為模板創(chuàng)建對(duì)象,這也是”原型”(prototype)的原意。 

  2. 初始化內(nèi)部屬性 :這一步驟不是必要的。通俗點(diǎn)說(shuō),就是,對(duì)”復(fù)制品”不滿意,我們可以”再加工”,使之獲得不同于”模板”的”個(gè)性”。 

所以在JavaScript的世界里,萬(wàn)物皆對(duì)象這個(gè)概念從一而終。

js高級(jí)---本地對(duì)象、內(nèi)置對(duì)象、宿主對(duì)象



全局對(duì)象:一般全局對(duì)象會(huì)有兩個(gè),一個(gè)是ecma提供的Global對(duì)象,一個(gè)是宿主提供。如在瀏覽器中是window、在nodejs中是global。【所以啊,在瀏覽器中全局對(duì)象Global+window】

通常情況下ecma提供的Global對(duì)象對(duì)是不存在的,沒(méi)有具體的對(duì)象

宿主對(duì)象-h(huán)ost object:即由 ECMAScript 實(shí)現(xiàn)的宿主環(huán)境提供的對(duì)象,包含兩大類,一個(gè)是宿主提供,一個(gè)是自定義類對(duì)象,ECMAScript官方未定義的對(duì)象都屬于宿主對(duì)象,所有非本地對(duì)象都是宿主對(duì)象。宿主提供對(duì)象原理--->由宿主框架通過(guò)某種機(jī)制注冊(cè)到ECscript引擎中的對(duì)象,如宿主瀏覽器(以遠(yuǎn)景為參考)會(huì)向ECscript注入window對(duì)象,構(gòu)建其實(shí)現(xiàn)javascript。

內(nèi)置對(duì)象-Build-in object:由 ECMAScript 實(shí)現(xiàn)提供的、獨(dú)立于宿主環(huán)境的所有對(duì)象,在 ECMAScript 程序開始執(zhí)行時(shí)出現(xiàn),即在引擎初始化階段就被創(chuàng)建好的對(duì)象。這意味著開發(fā)者不必明確實(shí)例化內(nèi)置對(duì)象,它已被實(shí)例化了Global(全局對(duì)象)、Math、JSON

基本包裝類型對(duì)象:ECMAScript還提供了3個(gè)特殊的引用類型: Boolean、Number、String。這些類型與其他內(nèi)置對(duì)象類型相似,但同時(shí)具有各自的基本類型相應(yīng)的特殊行為。實(shí)際上,每當(dāng)讀取一個(gè)基本類型值得時(shí)候,后臺(tái)就會(huì)創(chuàng)建一個(gè)對(duì)應(yīng)的基本包裝類型的對(duì)象,從而讓我們能夠調(diào)用一些方法來(lái)操作這些數(shù)據(jù) 包裝類型,是一個(gè)專門封裝原始類型的值,并提供對(duì)原始類型的值執(zhí)行操作的API對(duì)象

其他內(nèi)置對(duì)象與基本包裝類型對(duì)象的區(qū)別?

普通的內(nèi)置對(duì)象與基本包裝類型的主要區(qū)別就是對(duì)象的生命期,使用new操作符創(chuàng)建的引用類型的實(shí)例,在執(zhí)行流離開當(dāng)前作用域之前都一直保存在內(nèi)存中,而自動(dòng)創(chuàng)建的基本包裝類型的對(duì)象,則只是存在于一行代碼的執(zhí)行瞬間,然后立即被立即銷毀。這意味著我們不能再運(yùn)行時(shí)為基本包裝類型值添加屬性和方法。

var s1="some text"; s1.color="red"; var s2=new String("some text"); s2.color="red"; console.log(s1.color);//undefined console.log(s2.color);//red console.log(s1==s2);//true console.log(s1===s2);//false

在第二行為s1添加一個(gè)color屬性,第三行代碼執(zhí)行時(shí),再次訪問(wèn)s1,結(jié)果s1的color屬性被銷毀了。詳情推薦閱讀《JavaScript內(nèi)置對(duì)象--基本包裝類型(Boolean、Number、String)詳解》

原生對(duì)象-native object:也叫內(nèi)部對(duì)象、本地對(duì)象。獨(dú)立于宿主環(huán)境的ECMAScript實(shí)現(xiàn)提供的對(duì)象。與宿主無(wú)關(guān),在javascript(遠(yuǎn)景瀏覽器)、nodejs(node平臺(tái))、jscript(ie瀏覽器)、typescript(微軟平臺(tái))等等中均有這些對(duì)象。簡(jiǎn)單來(lái)說(shuō),本地對(duì)象就是 ECMA-262 定義的類(引用類型)。

Object、Function、Array、String、Boolean、Number、Date、RegExp、Error、EvalError、RangeError、ReferenceError、SyntaxError、TypeError、URIError、Global

在運(yùn)行過(guò)程中動(dòng)態(tài)創(chuàng)建的對(duì)象,需要new,以Number為例:

var n1=Number('1'); var n2=1; n2.xxx=2;console.log(n2); //undefined console.log(n1===n2)//false console.log(n1.toString()===n2.toString())//true console.log(n1.__proto__===Number)//false console.log(n2.__proto__===Number)//false console.log(n1.__proto__===n2.__proto__)//true

n1和n2雖然數(shù)值都是1,但n2的類型屬于'object',n1則為'number',身為基本類型number的n1直接指向了數(shù)字1,而n2指向了一個(gè)地址,這個(gè)地址中存放了數(shù)值1,這就是對(duì)象和基本類型的區(qū)別。

再談javascriptjs原型與原型鏈及繼承相關(guān)問(wèn)題

但是原型對(duì)象只存在于函數(shù)對(duì)象。也就是本質(zhì)上只要是通過(guò)new Function創(chuàng)建的函數(shù)對(duì)象會(huì)有一個(gè)原型對(duì)象。

而對(duì)于其他非Function的引用類型歸根結(jié)底也是通過(guò)new Function創(chuàng)建的。

如上面提到的Array類型、Object類型。

實(shí)際上,在每個(gè)函數(shù)對(duì)象創(chuàng)建的時(shí)候,都會(huì)自帶一個(gè)prototype的屬性,這個(gè)屬性相當(dāng)于一個(gè)指針,指向他本身的原型對(duì)象,這個(gè)原型對(duì)象里包含著自定義的方法屬性,

function a(){       this.name='xiaoming';       this.sayName=function () {           console.log(this.name);       }   }

在默認(rèn)情況下,a.prototype下會(huì)帶有一個(gè)constructor屬性,這個(gè)屬性指向創(chuàng)建當(dāng)前函數(shù)對(duì)象的構(gòu)造函數(shù),比如這里

constructor指向構(gòu)造函數(shù)a本身也就是說(shuō):a.prototypr.constructor==a   //true

另外默認(rèn)還有一個(gè)_proto_屬性,這個(gè)屬性指向由創(chuàng)建這個(gè)函數(shù)對(duì)象的引用類型中繼承而來(lái)的屬性和方法。

當(dāng)通過(guò)構(gòu)造函數(shù)實(shí)例化一個(gè)對(duì)象b時(shí),即new a();

首先這個(gè)new出來(lái)的對(duì)象屬于普通對(duì)象,所以沒(méi)有prototype屬性。但他有_proto_這個(gè)屬性,這個(gè)屬性指向創(chuàng)建它的引用類型的原型對(duì)象,在這個(gè)例子中指向a.prototype,從而繼承來(lái)自引用類型a的屬性和方法。推薦閱讀《JS 的 new 到底是干什么的?》

var 對(duì)象 = new 函數(shù)對(duì)象 這個(gè)聲明形式可以引申出:

函數(shù).__proto__ ===Function.prototype Function.__proto__ === Function.prototype Object.__proto__ === Function.prototype //Objec也是個(gè)函數(shù),函數(shù)都是由Function構(gòu)造出來(lái)的。 Number.__proto__ === Function.prototype 構(gòu)造函數(shù).prototype.__proto__ ===Object.prototype Function.prototype.__proto__ ===Object.prototype Number.prototype.__proto__ ===Object.prototype Object.__proto__ .__proto__ ===null

理解了以上的關(guān)系后,'__proto__'是對(duì)象的屬性、'prototype'是函數(shù)的屬性這句話也就懂了

null是對(duì)象原型鏈的終點(diǎn),其值既有(是一個(gè)對(duì)象)又無(wú)(不引用任何對(duì)象),代表著對(duì)象本源的一種混沌、虛無(wú)的狀態(tài),正與老子《道德經(jīng)》中的“道”,有著同等的意義(心中一萬(wàn)只艸尼瑪奔騰而過(guò),還是寫java爽啊)。比如:《undefined與null的區(qū)別》

再談javascriptjs原型與原型鏈及繼承相關(guān)問(wèn)題

在JS中,undefined是全局對(duì)象的一個(gè)屬性,它的初始值就是原始數(shù)據(jù)類型undefined,并且無(wú)法被配置,也無(wú)法被改變。undefined從字面意思上理解為“未定義”,即表示一個(gè)變量沒(méi)有定義其值。

而null是一個(gè)JS字面量,表示空值,即沒(méi)有對(duì)象。與undefined相比,null被認(rèn)為是“期望一個(gè)對(duì)象,但是不引用任何對(duì)象的值”,而undefined是純粹的“沒(méi)有值”。

// null為對(duì)象原型鏈的終點(diǎn) console.log(Object.getPrototypeOf(Object.prototype)); // null // null是一個(gè)對(duì)象 console.log(typeof null); // object // null 為空 console.log(!null); // true

JS中的所有事物都是對(duì)象,對(duì)象是擁有屬性和方法的數(shù)據(jù)

為了描述這些事物,JS便有了“原型(prototype)”的概念。

原型模式是js對(duì)繼承的一種實(shí)現(xiàn):使用原型,能復(fù)用代碼,節(jié)省內(nèi)存空間 (java類的代碼在內(nèi)存只有一份,然后每個(gè)對(duì)象執(zhí)行方法都是引用類的代碼,所有子類對(duì)象調(diào)用父類方法的時(shí)候,執(zhí)行的代碼都是同一份父類的方法代碼。但是JS沒(méi)有類,屬性和方法都是存在對(duì)象之中,根本沒(méi)有辦法做到j(luò)ava那樣通過(guò)類把代碼共享給所有對(duì)象)。

推薦閱讀《深刻理解JavaScript基于原型的面向?qū)ο蟆?/p>

從一張圖看懂原型對(duì)象、構(gòu)造函數(shù)、實(shí)例對(duì)象之間的關(guān)系

再談javascriptjs原型與原型鏈及繼承相關(guān)問(wèn)題

  • prototype:構(gòu)造函數(shù)中的屬性,指向該構(gòu)造函數(shù)的原型對(duì)象。

  • constructor:原型對(duì)象中的屬性,指向該原型對(duì)象的構(gòu)造函數(shù)

  • _proto_:實(shí)例中的屬性,指向new這個(gè)實(shí)例的構(gòu)造函數(shù)的原型對(duì)象

再談javascriptjs原型與原型鏈及繼承相關(guān)問(wèn)題

在JavaScript 中,每個(gè)對(duì)象都有一個(gè)指向它的原型(prototype)對(duì)象的內(nèi)部鏈接。這個(gè)原型對(duì)象又有自己的原型,直到某個(gè)對(duì)象的原型為 null 為止(也就是不再有原型指向),組成這條鏈的最后一環(huán)。這種一級(jí)一級(jí)的鏈結(jié)構(gòu)就稱為原型鏈(prototype chain)

要清楚原型鏈,首先要弄清楚對(duì)象

普通對(duì)象

    最普通的對(duì)象:有__proto__屬性(指向其原型鏈),沒(méi)有prototype屬性。

    原型對(duì)象(Person.prototype 原型對(duì)象還有constructor屬性(指向構(gòu)造函數(shù)對(duì)象))

函數(shù)對(duì)象:

    凡是通過(guò)new Function()創(chuàng)建的都是函數(shù)對(duì)象。

    擁有__proto__、prototype屬性(指向原型對(duì)象)。


JavaScript 對(duì)象是動(dòng)態(tài)的屬性“包”(指其自己的屬性)。JavaScript 對(duì)象有一個(gè)指向一個(gè)原型對(duì)象的鏈。當(dāng)試圖訪問(wèn)一個(gè)對(duì)象的屬性時(shí),它不僅僅在該對(duì)象上搜尋,還會(huì)搜尋該對(duì)象的原型,以及該對(duì)象的原型的原型,依此層層向上搜索,直到找到一個(gè)名字匹配的屬性或到達(dá)原型鏈的末尾。

再談javascriptjs原型與原型鏈及繼承相關(guān)問(wèn)題

原型-顯式原型-隱式原型-共享原型鏈 

顯式原型(explicit prototype property )每一個(gè)函數(shù)在創(chuàng)建之后都會(huì)擁有一個(gè)名為prototype的屬性,這個(gè)屬性指向函數(shù)的原型對(duì)象。用來(lái)實(shí)現(xiàn)基于原型的繼承與屬性的共享。

隱式原型 (implicit prototype link) JS中任意對(duì)象都有一個(gè)內(nèi)置屬性__proto__(部分瀏覽器為[[prototype]]),指向創(chuàng)建這個(gè)對(duì)象的函數(shù)(即構(gòu)造函數(shù))constructor的prototype。用來(lái)構(gòu)成原型鏈,同樣用于實(shí)現(xiàn)基于原型的繼承。



再談javascriptjs原型與原型鏈及繼承相關(guān)問(wèn)題

當(dāng)我們「讀取」 obj.toString 時(shí),JS 引擎會(huì)做下面的事情:

1. 看看 obj 對(duì)象本身有沒(méi)有 toString 屬性。沒(méi)有就走到下一步。

2. 看看 obj.__proto__ 對(duì)象有沒(méi)有 toString 屬性,發(fā)現(xiàn) obj.__proto__ 有 toString 屬性,于是找到了

3. 如果 obj.__proto__ 沒(méi)有,那么瀏覽器會(huì)繼續(xù)查看 obj.__proto__.__proto__,如果 obj.__proto__.__proto__ 也沒(méi)有,那么瀏覽器會(huì)繼續(xù)查,obj.__proto__.__proto__.proto__

直到找到 toString 或者 __proto__ 為 null(不管你從那個(gè)屬性開始,連續(xù)引用__proto__的指針,最后輸出的那個(gè)值就是null)。

上面的過(guò)程,就是「讀」屬性的「搜索過(guò)程」。

而這個(gè)「搜索過(guò)程」,是連著由 __proto__ 組成的鏈子一直走的。

這個(gè)鏈子,就叫做「原型鏈」。


要搞清楚 valueOf / toString / constructor 是怎么來(lái)的,就要用到 console.dir 了。

再談javascriptjs原型與原型鏈及繼承相關(guān)問(wèn)題

共享原型鏈(Shared prototype chain)此模式所有子對(duì)象及后代對(duì)象都共享一個(gè)原型(都是通過(guò)b.prototype=a.prototype;這種模式連接的對(duì)象),在這些后代對(duì)象上修改原型,會(huì)影響所以處在同一共享原型鏈上的所有對(duì)象。而且此模式只繼承原型鏈上的屬性和方法,通過(guò)this定義的屬性和方法無(wú)法訪問(wèn)和繼承

再談javascriptjs原型與原型鏈及繼承相關(guān)問(wèn)題


那么 obj.toString 和 obj2.toString 其實(shí)是同一個(gè)東西,也就是 obj2.__proto__.toString。

這有什么意義呢?

如果我們改寫 obj2.__proto__.toString,那么 obj.toString 其實(shí)也會(huì)變!

這樣 obj 和 obj2 就是具有某些相同行為的對(duì)象,這就是意義所在。

如果我們想讓 obj.toString 和 obj2.toString 的行為不同怎么做呢?

直接賦值就好了:

obj.toString = function(){ return '新的 toString 方法' }

原型對(duì)象

每創(chuàng)建一個(gè)函數(shù)都會(huì)有一個(gè)prototype屬性,這個(gè)屬性是一個(gè)指針,指向一個(gè)對(duì)象(通過(guò)該構(gòu)造函數(shù)創(chuàng)建實(shí)例對(duì)象的原型對(duì)象)原型對(duì)象是包含特定類型的所有實(shí)例共享的屬性和方法。原型對(duì)象的好處是,可以讓所有實(shí)例對(duì)象共享它所包含的屬性和方法。

原型對(duì)象屬于普通對(duì)象。Function.prototype是個(gè)例外,它是原型對(duì)象,卻又是函數(shù)對(duì)象,作為一個(gè)函數(shù)對(duì)象,它又沒(méi)有prototype屬性。

再談javascriptjs原型與原型鏈及繼承相關(guān)問(wèn)題


對(duì)象與函數(shù)

擁有了描述事物的能力,卻沒(méi)有創(chuàng)造事物的能力,顯然是不完整的,因此需要一個(gè)Object的生成器來(lái)進(jìn)行對(duì)象的生成。


JS將生成器以構(gòu)造函數(shù)constructor來(lái)表示,構(gòu)造函數(shù)是一個(gè)指針,指向了一個(gè)函數(shù)

函數(shù)(function) 函數(shù)是指一段在一起的、可以做某一件事的程序。構(gòu)造函數(shù)是一種創(chuàng)建對(duì)象時(shí)使用的特殊函數(shù)

再談javascriptjs原型與原型鏈及繼承相關(guān)問(wèn)題

對(duì)象的構(gòu)造函數(shù)function Object同時(shí)也是一個(gè)對(duì)象,因此需要一個(gè)能夠描述該對(duì)象的原型,該原型便是Function.prototype,函數(shù)的原型用來(lái)描述所有的函數(shù)。對(duì)象的構(gòu)造函數(shù)的__proto__指向該原型。

再談javascriptjs原型與原型鏈及繼承相關(guān)問(wèn)題

函數(shù)的原型本身也是對(duì)象,因此其__proto__指向了對(duì)象的原型。同樣,該對(duì)象也需要一個(gè)對(duì)應(yīng)的生成器,即其構(gòu)造函數(shù)function Function。

再談javascriptjs原型與原型鏈及繼承相關(guān)問(wèn)題

函數(shù)的構(gòu)造函數(shù)是由函數(shù)生成的一個(gè)對(duì)象,所以其原型即為函數(shù)的原型,其隱式原型也同樣為函數(shù)的原型Function.prototype。

instanceof操作符的內(nèi)部實(shí)現(xiàn)機(jī)制和隱式原型、顯式原型有直接的關(guān)系。instanceof的左值一般是一個(gè)對(duì)象,右值一般是一個(gè)構(gòu)造函數(shù),用來(lái)判斷左值是否是右值的實(shí)例。它的實(shí)現(xiàn)原理是沿著左值的__proto__一直尋找到原型鏈的末端,直到其等于右值的prototype為止。

instanceof 的作用是判斷一個(gè)對(duì)象是不是一個(gè)函數(shù)的實(shí)例。比如 obj instanceof fn, 實(shí)際上是判斷fn的prototype是不是在obj的原型鏈上。所以

instanceof運(yùn)算符的實(shí)質(zhì):用來(lái)檢測(cè) constructor.prototype是否存在于參數(shù) object的原型鏈上。

根據(jù)上圖展示的Object和Function的繼承依賴關(guān)系,我們可以通過(guò)instanceof操作符來(lái)看一下Object和Function的關(guān)系:

console.log(Object instanceof Object); // true console.log(Object instanceof Function); // true console.log(Function instanceof Object); // true console.log(Function instanceof Function); // true

函數(shù)與對(duì)象相互依存,分別定義了事物的描述方法和事物的生成方法,在生成JS萬(wàn)物的過(guò)程中缺一不可。

Function instanceof Function    // true, why? Function.prototype是原型對(duì)象,卻是函數(shù)對(duì)象
  • Object特殊在Object.prototype是憑空出來(lái)的。語(yǔ)法上,所有的{}都會(huì)被解釋為new Object();

  • Function特殊在__proto__ == prototype。語(yǔ)法上,所有的函數(shù)聲明都會(huì)被解釋為new Function()。

我們來(lái)看Function和Object的特殊之處:

  1. Object是由Function創(chuàng)建的:因?yàn)镺bject.__proto__ === Funciton.prototype;

  2. 同理,F(xiàn)unction.prototype是由Object.prototype創(chuàng)建的;

  3. Funciton是由Function自己創(chuàng)建的!

  4. Object.prototype是憑空出來(lái)的!

推薦閱讀 《JavaScript 內(nèi)置對(duì)象與原型鏈結(jié)構(gòu)》與《JavaScript中的難點(diǎn)之原型和原型鏈》

這幾句話能解釋一切關(guān)于原型方面的問(wèn)題:

  1. 當(dāng) new 一個(gè)函數(shù)的時(shí)候會(huì)創(chuàng)建一個(gè)對(duì)象,『函數(shù).prototype』 等于 『被創(chuàng)建對(duì)象.__proto__』

  2. 一切函數(shù)都是由 Function 這個(gè)函數(shù)創(chuàng)建的,所以『Function.prototype === 被創(chuàng)建的函數(shù).__proto__』

  3. 一切函數(shù)的原型對(duì)象都是由 Object 這個(gè)函數(shù)創(chuàng)建的,所以『Object.prototype === 一切函數(shù).prototype.__proto__』

推薦閱讀:《對(duì)原型、原型鏈、 Function、Object 的理解》

原型鏈?zhǔn)菍?shí)現(xiàn)繼承的主要方法

先說(shuō)一下繼承,許多OO語(yǔ)言都支持兩張繼承方式:接口繼承、實(shí)現(xiàn)繼承。

    |- 接口繼承:只繼承方法簽名

    |- 實(shí)現(xiàn)繼承:繼承實(shí)際的方法

由于函數(shù)沒(méi)有簽名,在ECMAScript中無(wú)法實(shí)現(xiàn)接口繼承,只支持實(shí)現(xiàn)繼承,而實(shí)現(xiàn)繼承主要是依靠原型鏈來(lái)實(shí)現(xiàn)。

原型鏈基本思路:

利用原型讓一個(gè)引用類型繼承另一個(gè)引用類型的屬性和方法。


每個(gè)構(gòu)造函數(shù)都有一個(gè)原型對(duì)象,原型對(duì)象都包含一個(gè)指向構(gòu)造函數(shù)想指針(constructor),而實(shí)例對(duì)象都包含一個(gè)指向原型對(duì)象的內(nèi)部指針(__proto__)。如果讓原型對(duì)象等于另一個(gè)類型的實(shí)例,此時(shí)的原型對(duì)象將包含一個(gè)指向另一個(gè)原型的指針(__proto__),另一個(gè)原型也包含著一個(gè)指向另一個(gè)構(gòu)造函數(shù)的指針(constructor)。假如另一個(gè)原型又是另一個(gè)類型的實(shí)例……這就構(gòu)成了實(shí)例與原型的鏈條。

原型鏈基本思路(圖解):

再談javascriptjs原型與原型鏈及繼承相關(guān)問(wèn)題

推薦閱讀《JS重點(diǎn)整理之JS原型鏈徹底搞清楚》



類-對(duì)象冒充-class

類(Class)是面向?qū)ο蟪绦蛟O(shè)計(jì)(OOP,Object-Oriented Programming)實(shí)現(xiàn)信息封裝的基礎(chǔ)。類是一種用戶定義類型,也稱類類型。每個(gè)類包含數(shù)據(jù)說(shuō)明和一組操作數(shù)據(jù)或傳遞消息的函數(shù)。類的實(shí)例稱為對(duì)象。

在ECMAScript 2015 中引入的JS類(classes)之前,要在JS中實(shí)現(xiàn)類便是采用原型繼承的方式。

當(dāng)把一個(gè)函數(shù)作為構(gòu)造函數(shù),使用new關(guān)鍵字來(lái)創(chuàng)建對(duì)象時(shí),便可以把該函數(shù)看作是一個(gè)類,創(chuàng)建出來(lái)的對(duì)象則是該類的實(shí)例,其隱式原型__proto__指向的是該構(gòu)造函數(shù)的原型。


在訪問(wèn)該對(duì)象的屬性或方法時(shí),JS會(huì)先搜索該對(duì)象中是否定義了該屬性或方法,若沒(méi)有定義,則會(huì)回溯到其__proto__指向的原型對(duì)象去搜索,若仍然未搜索到,則會(huì)繼續(xù)回溯該原型的原型,直到搜索到原型鏈的終點(diǎn)null;


這種特性可以理解為:構(gòu)造函數(shù)生成的實(shí)例,繼承于該構(gòu)造函數(shù)的原型


得益于這種特性,我們可以使用定義構(gòu)造函數(shù)的方式來(lái)定義類。

再談javascriptjs原型與原型鏈及繼承相關(guān)問(wèn)題

function Person() {} // 定義Person構(gòu)造函數(shù) // 通常以大寫字母開頭來(lái)定義類名 console.log(new Person() instanceof Person); // true

以上定義了Person類,該構(gòu)造函數(shù)是由Function構(gòu)造而來(lái),所以其隱式原型指向函數(shù)的原型,而為了描述該事物,同時(shí)生成了該類的原型Person.prototype,該原型又是由Object構(gòu)造而來(lái),所以其隱式原型指向了對(duì)象的原型。

后記:文字有點(diǎn)亂,就是多篇文章的精華提煉。發(fā)現(xiàn)把一個(gè)自己懂的事情,深入淺出講明白,并非易事。文有不妥之處,請(qǐng)留言告知,謝謝。

文章首發(fā)于:https://www.zhoulujun.cn/html/webfront/ECMAScript/js/2015_0715_119.html,如果不妥之處,請(qǐng)到官網(wǎng)留言,謝謝!

參考文字:

【道生萬(wàn)物】理解Javascript原型鏈

js高級(jí)---本地對(duì)象、內(nèi)置對(duì)象、宿主對(duì)象

js原型與原型鏈

「每日一題」什么是 JS 原型鏈?

JS理解原型、原型鏈

一張圖弄清Javascript中的原型鏈、prototype、__proto__的關(guān)系

js中的原型、原型鏈、繼承模式

說(shuō)說(shuō)原型(prototype)、原型鏈和原型繼承

淺談JS原型和原型鏈

原型語(yǔ)言解釋

基于類 vs 基于原型


向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI