一文搞懂JavaScript中原型與原型鏈
在ES6之前,我們面向?qū)ο笫峭ㄟ^構(gòu)造函數(shù)實(shí)現(xiàn)的。我們把對(duì)象的公共屬性和方法放在構(gòu)造函數(shù)里
像這樣:
function student(uname,age) {
this.uname = uname;
this.age = age;
this.school = function() {
console.log('深圳理工大學(xué)');
}
}
var stu1 = new student('小紅',18);
var stu2 = new student('小紫',20);但是構(gòu)造函數(shù)方法雖然好用,可他存在浪費(fèi)內(nèi)存的問題。比如在上例中在構(gòu)造函數(shù)里我們有一個(gè)函數(shù),函數(shù)屬于復(fù)雜數(shù)據(jù)類型,他會(huì)單獨(dú)在內(nèi)存中開辟一個(gè)空間。在這里我們創(chuàng)建了兩個(gè)實(shí)例化對(duì)象,那么就會(huì)開辟兩個(gè)內(nèi)存空間來存放同一個(gè)函數(shù),那就造成了內(nèi)存浪費(fèi)的問題。
1.構(gòu)造函數(shù)原型prototype
構(gòu)造函數(shù)通過原型分配的函數(shù)是所有對(duì)象所共享的。
JavaScript規(guī)定,每一個(gè)構(gòu)造函數(shù)都有一個(gè)prototype屬性, 指向另一個(gè)對(duì)象。注意這個(gè)prototype就是一個(gè)對(duì)象,這個(gè)對(duì)象的所有屬性和方法,都會(huì)被構(gòu)造函數(shù)所擁有。
我們可以把那些不變的方法,直接定義在prototype對(duì)象上,這樣所有對(duì)象的實(shí)例就可以共享這些方法。
所以在上例中我們就可以把公共函數(shù)放在原型對(duì)象的里面,這樣就不會(huì)造成內(nèi)存浪費(fèi)
function student(uname,age) {
this.uname = uname;
this.age = age;
}
student.prototype.school = function() {
console.log('深圳理工大學(xué)');
}
var stu1 = new student('小紅',18);
var stu2 = new student('小紫',20);那么我們就明白了原型是什么,他就是一個(gè)對(duì)象,我們稱prototype為原型對(duì)象
原型的作用是什么呢?四個(gè)字,共享方法
2.對(duì)象原型__proto__
對(duì)象都會(huì)有一個(gè)屬性__proto__指向構(gòu)造函數(shù)的 prototype原型對(duì)象,之所以我們對(duì)象可以使用構(gòu)造函數(shù)prototype原型對(duì)象的屬性和方法,就是因?yàn)閷?duì)象有_ proto_ 原型的存在。
在對(duì)象身上系統(tǒng)自己添加了一個(gè)__proto__指向我們構(gòu)造函數(shù)的原型對(duì)象,所以__proto__對(duì)象原型和原型對(duì)象prototype是等價(jià)的。
我們驗(yàn)證一下,看看會(huì)輸出什么:
console.log(stu1.__proto__ === student.prototype);

最后輸出是true證明對(duì)象原型__proto__和原型對(duì)象protptype是等價(jià)的
所以方法的查找規(guī)則就是首先看stu1對(duì)象身上是否有school方法,如果有就執(zhí)行這個(gè)對(duì)象上的school,如果沒有school這個(gè)方法, 因?yàn)橛衉_proto__的存在,就去構(gòu)造函數(shù)原型對(duì)象prototype身上去查找school這個(gè)方法
如果覺得還是不太懂,一圖搞懂你的疑問:

3.constructor構(gòu)造函數(shù)
對(duì)象原型(__proto__) 和構(gòu)造函數(shù)( prototype )原型對(duì)象里面都有一個(gè)屬性 constructor屬性, constructor我們稱為構(gòu)造函數(shù),因?yàn)樗富貥?gòu)造函數(shù)本身。
我們打印一下student.prototype和stu1.__type__看看是否存在constructor屬性:
console.log(student.prototype); console.log(stu1.__proto__);

可以看到這里面都有constructor,那constructor有什么作用呢?
constructor主要用于記錄該對(duì)象引用于哪個(gè)構(gòu)造函數(shù),它可以讓原型對(duì)象重新指向原來的構(gòu)造函數(shù)
我們知道在原型對(duì)象中我們可以定義那些公共的方法,但是如果公共的方法很多呢,我們通過對(duì)象的形式存儲(chǔ)就方便多了:
student.prototype = {
school:function() {},
location:function() {}
}然后我們輸出一下原型對(duì)象的constructor看看有沒有變化:
console.log(student.prototype.constructor); console.log(stu1.__proto__.constructor);
最后的輸出結(jié)果是這樣:

這是為什么呢,constructor不應(yīng)該指向我們的student構(gòu)造函數(shù)嗎
因?yàn)槲覀兺ㄟ^student.prototype.school這樣屬于往原型對(duì)象里添加方法,但是我們剛才屬于賦值,這樣就把原先prototype里的東西都覆蓋掉了,這樣student.prototype就沒有constructor了,沒有constructor自然就指回不了student構(gòu)造函數(shù)了
這個(gè)時(shí)候我們就需要手動(dòng)的利用constructor這個(gè)屬性指回原來的構(gòu)造函數(shù)
student.prototype = {
constructor:student,
school:function() {},
location:function() {}
}我們?cè)佥敵鲆幌略蛯?duì)象的constructor:

這樣我們就知道這個(gè)對(duì)象到底是通過哪個(gè)構(gòu)造函數(shù)創(chuàng)建出來的了
現(xiàn)在我們更新一下構(gòu)造函數(shù)、實(shí)例、原型對(duì)象三者關(guān)系圖:

4.原型鏈
因?yàn)閟tudent原型對(duì)象也是一個(gè)對(duì)象,我們之前說了只要是對(duì)象就有對(duì)象原型的存在
那我們打印一下原型對(duì)象看看里面是否有原型:
function student(uname,age) {
this.uname = uname;
this.age = age;
}
student.prototype.school = function() {
console.log('深圳理工大學(xué)');
}
var stu1 = new student('小紅',18);
console.log(student.prototype);輸出結(jié)果:

可以看到原型對(duì)象里也有一個(gè)原型,又因?yàn)樵椭赶虻氖窃蛯?duì)象,那么我們這個(gè)student.prototype里面的__proto__指向的是誰呢?
我們打印一下:
console.log(student.prototype.__proto__);
可以看到指向的是這個(gè)constructor指向的是Object原型對(duì)象

Object原型對(duì)象是由誰創(chuàng)建出來的呢,毫無疑問是Object構(gòu)造函數(shù)創(chuàng)建出來的。那么我們繼續(xù),Object原型對(duì)象也是一個(gè)對(duì)象,那它也有一個(gè)原型,這個(gè)原型指向的又是誰呢?
我們輸出一下:
console.log(Object.prototype.__proto__);
最后的結(jié)果為空:

這樣就到了最頂層了,這樣我們把這些串起來就能得到一個(gè)原型鏈:

5.原型對(duì)象中的this指向
我們知道在構(gòu)造函數(shù)中的this指向的是對(duì)象實(shí)例,那么原型對(duì)象里的函數(shù),這個(gè)函數(shù)里的this指向的是誰呢?
我們聲明一個(gè)全局變量that,把原型對(duì)象里的this賦給that,看看這個(gè)that指向的是不是實(shí)例對(duì)象:
function student(uname,age) {
this.uname = uname;
this.age = age;
}
var that;
student.prototype.school = function() {
that = this;
console.log('深圳理工大學(xué)');
}
var stu1 = new student('小紅',18);
stu1.school();
console.log(that === stu1);輸出結(jié)果:

所以原型對(duì)象函數(shù)里面的this指向的也是實(shí)例對(duì)象stu1
6.擴(kuò)展內(nèi)置對(duì)象(原型對(duì)象的應(yīng)用)
我們可以通過原型對(duì)象,對(duì)原來的內(nèi)置對(duì)象進(jìn)行擴(kuò)展自定義的方法。比如給數(shù)組增加自定義求和的功能
我們輸出一下數(shù)組的原型對(duì)象,看看里面有什么方法:
console.log(Array.prototype);

這里沒有給數(shù)組自定義求和的函數(shù),那么我們往數(shù)組的原型對(duì)象里添加這個(gè)方法:
Array.prototype.sum = function() {
var sum = 0;
for(var i = 0;i<this.length;i++)
{
sum += this[i];
}
return sum;
}
var ss = new Array(4,5,3,6);
console.log(ss.sum());我們自定義的sum方法里,this.length指的就是調(diào)用這個(gè)方法的數(shù)組的長(zhǎng)度,因?yàn)樵谏弦还?jié)中我們知道原型對(duì)象函數(shù)里面的this指向的也是實(shí)例對(duì)象
我們通過new方法創(chuàng)建一個(gè)數(shù)組實(shí)例對(duì)象,我們向數(shù)組的原型對(duì)象添加sum方法,那么我們的實(shí)例對(duì)象就可以調(diào)用它。
輸出結(jié)果:

我們?cè)俅蛴∫幌聰?shù)組的原型對(duì)象,看看里面有沒有sum方法:

可以看到sum成功的添加到數(shù)組的原型對(duì)象里了,這樣我們繼續(xù)用到數(shù)組求和時(shí),就可以直接調(diào)用sum方法了。
到此這篇關(guān)于一文搞懂JavaScript中原型與原型鏈的文章就介紹到這了,更多相關(guān)JS原型與原型鏈內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JavaScript Event學(xué)習(xí)第十章 一些可替換的事件對(duì)
為了讓我們的JavaScript驅(qū)動(dòng)的頁(yè)面對(duì)那些不能或者不想使用鼠標(biāo)的用戶也能很好的使用,我們對(duì)于像mouseover和click這樣的事件做一些處理,同樣的,對(duì)于非鼠標(biāo)事件也同樣的要我們的腳本執(zhí)行。2010-02-02
JavaScript函數(shù)式編程(Functional Programming)聲明式與命令式實(shí)例分析
這篇文章主要介紹了JavaScript函數(shù)式編程(Functional Programming)聲明式與命令式,結(jié)合實(shí)例形式分析了JS聲明式與命令式相關(guān)概念、原理、定義及使用方法,需要的朋友可以參考下2019-05-05
js中如何將多層嵌套的數(shù)組轉(zhuǎn)換為一層數(shù)組
這篇文章主要介紹了js中如何將多層嵌套的數(shù)組轉(zhuǎn)換為一層數(shù)組問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06
微信小程序?qū)W習(xí)之?dāng)?shù)據(jù)處理詳解
這篇文章主要給大家介紹了關(guān)于微信小程序中數(shù)據(jù)處理的相關(guān)資料,文中介紹的非常詳細(xì),對(duì)大家具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考借鑒,下面來一起看看吧。2017-07-07
JavaScript高級(jí)程序設(shè)計(jì) 閱讀筆記(十二) js內(nèi)置對(duì)象Math
js內(nèi)置對(duì)象Math使用介紹, 需要的朋友可以參考下2012-08-08
JS動(dòng)態(tài)插入腳本和插入引用外部鏈接腳本的方法
js 動(dòng)態(tài)插入腳本的是在頁(yè)面加載時(shí)不存在,但將來的某一時(shí)刻通過修改該 DOM 動(dòng)態(tài)添加的腳本。接下來通過本文給大家介紹JS動(dòng)態(tài)插入腳本和插入引用外部鏈接腳本,需要的朋友可以參考下2018-05-05

