欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JavaScript 原型與原型鏈詳情

 更新時(shí)間:2021年10月25日 15:22:30   作者:南玖  
這篇文章主要介紹了JavaScript 原型與原型鏈,JavaScript常被描述為一種基于原型的語(yǔ)言,對(duì)象以其原型為模板、從原型繼承屬性和放法。原型對(duì)象也可能擁有原型,并從中繼承屬性和方法,一層一層以此類推。這種關(guān)系常被稱為原型鏈,帶著簡(jiǎn)單的了解看看下文內(nèi)容具體介紹吧

前言:

JavaScript常被描述為一種「基于原型的語(yǔ)言」——每個(gè)對(duì)象都擁有一個(gè)「原型對(duì)象」,對(duì)象以其原型為模板、從原型繼承屬性和放法。原型對(duì)象也可能擁有原型,并從中繼承屬性和方法,一層一層以此類推。這種關(guān)系常被稱為「原型鏈」,它解釋了為何一個(gè)對(duì)象會(huì)擁有定義在其他對(duì)象中的屬性和方法。

準(zhǔn)確的說(shuō),這些屬性和方法定義在Object的構(gòu)造函數(shù)的prototype屬性上,而非對(duì)象實(shí)例本身。

四句話道破原型與原型鏈:

  • 每個(gè)函數(shù)(類)天生自帶一個(gè)屬性prototype,屬性值是一個(gè)對(duì)象,里面存儲(chǔ)了當(dāng)前類供實(shí)例使用的屬性和方法 「(顯示原型)」
  • 在瀏覽器默認(rèn)給原型開(kāi)辟的堆內(nèi)存中有一個(gè)constructor屬性:存儲(chǔ)的是當(dāng)前類本身(⚠️注意:自己開(kāi)辟的堆內(nèi)存中默認(rèn)沒(méi)有constructor屬性,需要自己手動(dòng)添加)「(構(gòu)造函數(shù))」
  • 每個(gè)對(duì)象都有一個(gè)__proto__屬性,這個(gè)屬性指向當(dāng)前實(shí)例所屬類的原型(不確定所屬類,都指向Object.prototype)「(隱式原型)」
  • 當(dāng)你試圖獲取一個(gè)對(duì)象的某個(gè)屬性時(shí),如果這個(gè)對(duì)象本身沒(méi)有這個(gè)屬性,那么它會(huì)去它的隱式原型__proto__(也就是它的構(gòu)造函數(shù)的顯示原型prototype)中查找。「(原型鏈)」

構(gòu)造函數(shù),原型與實(shí)例的關(guān)系:

每個(gè)構(gòu)造函數(shù)(constructor)都有一個(gè)原型對(duì)象(prototype),原型對(duì)象(prototype)都包含一個(gè)指向構(gòu)造函數(shù)(constructor)的指針,而實(shí)例(instance)都包含一個(gè)指向原型對(duì)象(__proto__)的內(nèi)部指針

1、prototype(顯式原型)

每個(gè)函數(shù)都有一個(gè)prototype屬性

// 構(gòu)造函數(shù)(類)
function Person(name){
    this.name = name
}
// new了一個(gè)實(shí)例 (對(duì)象)
var person = new Person('南玖')
console.log(person) //Person { name: '南玖' }
console.log(Person.prototype)  //構(gòu)造函數(shù)(類)的原型 ----->對(duì)象
Person.prototype.age = 18  // 構(gòu)造函數(shù)原型
console.log(person.age)  // 18


上面我們把這個(gè)函數(shù)Person的原型打印出來(lái)了,它指向的是一個(gè)對(duì)象,并且這個(gè)對(duì)象正是調(diào)用該構(gòu)造函數(shù)而創(chuàng)建的實(shí)例的原型

上面這張圖表示的是構(gòu)造函數(shù)與實(shí)例原型之間的關(guān)系,所以我們知道了構(gòu)造函數(shù)的prototype屬性指向的是一個(gè)對(duì)象。

那實(shí)例與實(shí)例原型之間的關(guān)系又是怎樣的呢?這里就要提到__proto__屬性了

2、__proto__(隱式原型)

從上面四句話中我們可以知道這是每一個(gè)Javascript對(duì)象(除null)都具有的一個(gè)屬性,這個(gè)屬性會(huì)指向該對(duì)象的原型(也就是實(shí)例原型)

因?yàn)樵?code>JavaScript中沒(méi)有類的概念,為了實(shí)現(xiàn)類似繼承的方式,通過(guò)__proto__將對(duì)象和原型聯(lián)系起來(lái)組成原型鏈,的以讓對(duì)象訪問(wèn)到不屬于自己的屬性。

那么我們就能夠證明實(shí)例與實(shí)例原型之間的關(guān)系

console.log(person.__proto__)  //實(shí)例(對(duì)象)的原型--->對(duì)象

console.log(person.__proto__ === Person.prototype)  //實(shí)例的原型與構(gòu)造函數(shù)的原型相等

從上圖我們可以看出實(shí)例對(duì)象與構(gòu)造函數(shù)都可以指向原型,那么原型能不能指向構(gòu)造函數(shù)或者是實(shí)例呢?

3、constructor(構(gòu)造函數(shù))

原型是沒(méi)有屬性指向?qū)嵗?,因?yàn)橐粋€(gè)構(gòu)造函數(shù)可以創(chuàng)建多個(gè)實(shí)例對(duì)象;

從前面的四句話中我們知道「在瀏覽器默認(rèn)給原型開(kāi)辟的堆內(nèi)存中有一個(gè)constructor屬性」,所以原型也是可以指向構(gòu)造函數(shù)的,這個(gè)屬性就是「constructor

于是我們可以證明一下觀點(diǎn):

console.log(Person.prototype.constructor) //實(shí)例的顯式原型的構(gòu)造函數(shù)ƒ Person(name){this.name = name}
console.log(person.__proto__.constructor)  //實(shí)例的隱式原型的構(gòu)造函數(shù) ƒ Person(name){this.name = name}
console.log(person.__proto__.constructor === Person.prototype.constructor)//true 實(shí)例原型的構(gòu)造函數(shù)與類的構(gòu)造函數(shù)相等
console.log(Person === Person.prototype.constructor)  //true


實(shí)例對(duì)象的__proto__是如何產(chǎn)生的?
我們知道當(dāng)我們使用new 操作符時(shí),生成的實(shí)例對(duì)象就擁有了__proto__屬性

function Foo() {}
// 這個(gè)函數(shù)時(shí)Function的實(shí)例對(duì)象
// function是一個(gè)語(yǔ)法糖
// 內(nèi)部其實(shí)調(diào)用了new Function()


所以可以說(shuō),在new的過(guò)程中,新對(duì)象被添加了__proto__屬性并且鏈接到了構(gòu)造函數(shù)的原型上。

4、new的原理

說(shuō)簡(jiǎn)單點(diǎn)可以分為以下四步:

  • 新建一個(gè)空對(duì)象
  • 鏈接原型
  • 綁定this,執(zhí)行構(gòu)造函數(shù)
  • 返回新對(duì)象
function myNew() {
// 1.新建一個(gè)空對(duì)象
let obj = {}
// 2.獲得構(gòu)造函數(shù)
let con = arguments.__proto__.constructor
// 3.鏈接原型
obj.__proto__ = con.prototype
// 4.綁定this,執(zhí)行構(gòu)造函數(shù)
let res = con.apply(obj, arguments)
// 5.返回新對(duì)象
return typeof res === 'object' ? res : obj
}

5、原型鏈

說(shuō)完了原型,我們?cè)賮?lái)看看什么是原型鏈?先來(lái)看一張圖:

這張圖中,由__proto__串起來(lái)的鏈?zhǔn)疥P(guān)系,我們就稱它為原型鏈

5.1 原型鏈的作用

原型鏈決定了JavaScript中繼承的實(shí)現(xiàn)方式,當(dāng)我們?cè)L問(wèn)一個(gè)屬性時(shí),它的查找機(jī)制如下:

  • 訪問(wèn)對(duì)象實(shí)例屬性,有的話直接返回,沒(méi)有則通過(guò)__proto__去它的原型對(duì)象上查找
  • 原型對(duì)象上能找到的話則返回,找不到繼續(xù)通過(guò)原型對(duì)象的__proto__查找
  • 一直往下找,直到找到Object.prototype,如果能找到則返回,找不到就返回undefined,不會(huì)再往下找了,因?yàn)?code>Object.prototype.__proto__是null,說(shuō)明了Object是所有對(duì)象的原型鏈頂層了。

從圖中我們可以發(fā)現(xiàn),所有對(duì)象都可以通過(guò)原型鏈最終找到 Object.prototype ,雖然 Object.prototype 也是一個(gè)對(duì)象,但是這個(gè)對(duì)象卻不是 Object 創(chuàng)造的,而是引擎自己創(chuàng)建了 Object.prototype 。所以可以這樣說(shuō),所有實(shí)例都是對(duì)象,但是對(duì)象不一定都是實(shí)例。

5.2 構(gòu)造函數(shù)的__proto__是什么呢?

由上面的原型鏈的解釋,我們應(yīng)該能夠理解構(gòu)造函數(shù)的__proto__的,在JavaScript中所有東西都是對(duì)象,那么構(gòu)造函數(shù)肯定也是對(duì)象,是對(duì)象就有__proto__ 。

function Person(){}
console.log(Person.__proto__)
console.log(Function.prototype)
console.log(Person.__proto__===Function.prototype) // true


「這也說(shuō)明了所有函數(shù)都是Function的實(shí)例」

那這么理解的話,Function.__proto__豈不是等于Function.prototype。。。。我們不妨來(lái)打印一下看看

Function.__proto__ === Function.prototype // true


打印出來(lái)確實(shí)是這樣的。難道 Function.prototype 也是通過(guò) new Function() 產(chǎn)生的嗎?

答案是否定的,這個(gè)函數(shù)也是引擎自己創(chuàng)建的。首先引擎創(chuàng)建了 Object.prototype ,然后創(chuàng)建了 Function.prototype ,并且通過(guò) __proto__ 將兩者聯(lián)系了起來(lái)。這里也很好的解釋了上面的一個(gè)問(wèn)題,為什么 let fun = Function.prototype.bind() 沒(méi)有 prototype 屬性。因?yàn)?Function.prototype 是引擎創(chuàng)建出來(lái)的對(duì)象,引擎認(rèn)為不需要給這個(gè)對(duì)象添加 prototype 屬性。

6、總結(jié)

  • Object 是所有對(duì)象的爸爸,所有對(duì)象都可以通過(guò) __proto__ 找到它
  • Function 是所有函數(shù)的爸爸,所有函數(shù)都可以通過(guò) __proto__ 找到它
  • Function.prototype Object.prototype 是兩個(gè)特殊的對(duì)象,他們由引擎來(lái)創(chuàng)建
  • 除了以上兩個(gè)特殊對(duì)象,其他對(duì)象都是通過(guò)構(gòu)造器 new 出來(lái)的
  • 函數(shù)的 prototype 是一個(gè)對(duì)象,也就是原型
  • 對(duì)象的 __proto__ 指向原型, __proto__ 將對(duì)象和原型連接起來(lái)組成了原型鏈

到此這篇關(guān)于JavaScript 原型與原型鏈詳情的文章就介紹到這了,更多相關(guān)JavaScript 原型與原型鏈內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論