一文搞懂JavaScript中原型與原型鏈
在ES6之前,我們面向對象是通過構造函數(shù)實現(xiàn)的。我們把對象的公共屬性和方法放在構造函數(shù)里
像這樣:
function student(uname,age) { this.uname = uname; this.age = age; this.school = function() { console.log('深圳理工大學'); } } var stu1 = new student('小紅',18); var stu2 = new student('小紫',20);
但是構造函數(shù)方法雖然好用,可他存在浪費內存的問題。比如在上例中在構造函數(shù)里我們有一個函數(shù),函數(shù)屬于復雜數(shù)據(jù)類型,他會單獨在內存中開辟一個空間。在這里我們創(chuàng)建了兩個實例化對象,那么就會開辟兩個內存空間來存放同一個函數(shù),那就造成了內存浪費的問題。
1.構造函數(shù)原型prototype
構造函數(shù)通過原型分配的函數(shù)是所有對象所共享的。
JavaScript規(guī)定,每一個構造函數(shù)都有一個prototype屬性, 指向另一個對象。注意這個prototype就是一個對象,這個對象的所有屬性和方法,都會被構造函數(shù)所擁有。
我們可以把那些不變的方法,直接定義在prototype對象上,這樣所有對象的實例就可以共享這些方法。
所以在上例中我們就可以把公共函數(shù)放在原型對象的里面,這樣就不會造成內存浪費
function student(uname,age) { this.uname = uname; this.age = age; } student.prototype.school = function() { console.log('深圳理工大學'); } var stu1 = new student('小紅',18); var stu2 = new student('小紫',20);
那么我們就明白了原型是什么,他就是一個對象,我們稱prototype為原型對象
原型的作用是什么呢?四個字,共享方法
2.對象原型__proto__
對象都會有一個屬性__proto__指向構造函數(shù)的 prototype原型對象,之所以我們對象可以使用構造函數(shù)prototype原型對象的屬性和方法,就是因為對象有_ proto_ 原型的存在。
在對象身上系統(tǒng)自己添加了一個__proto__指向我們構造函數(shù)的原型對象,所以__proto__對象原型和原型對象prototype是等價的。
我們驗證一下,看看會輸出什么:
console.log(stu1.__proto__ === student.prototype);
最后輸出是true證明對象原型__proto__和原型對象protptype是等價的
所以方法的查找規(guī)則就是首先看stu1對象身上是否有school方法,如果有就執(zhí)行這個對象上的school,如果沒有school這個方法, 因為有__proto__的存在,就去構造函數(shù)原型對象prototype身上去查找school這個方法
如果覺得還是不太懂,一圖搞懂你的疑問:
3.constructor構造函數(shù)
對象原型(__proto__) 和構造函數(shù)( prototype )原型對象里面都有一個屬性 constructor屬性, constructor我們稱為構造函數(shù),因為它指回構造函數(shù)本身。
我們打印一下student.prototype和stu1.__type__看看是否存在constructor屬性:
console.log(student.prototype); console.log(stu1.__proto__);
可以看到這里面都有constructor,那constructor有什么作用呢?
constructor主要用于記錄該對象引用于哪個構造函數(shù),它可以讓原型對象重新指向原來的構造函數(shù)
我們知道在原型對象中我們可以定義那些公共的方法,但是如果公共的方法很多呢,我們通過對象的形式存儲就方便多了:
student.prototype = { school:function() {}, location:function() {} }
然后我們輸出一下原型對象的constructor看看有沒有變化:
console.log(student.prototype.constructor); console.log(stu1.__proto__.constructor);
最后的輸出結果是這樣:
這是為什么呢,constructor不應該指向我們的student構造函數(shù)嗎
因為我們通過student.prototype.school這樣屬于往原型對象里添加方法,但是我們剛才屬于賦值,這樣就把原先prototype里的東西都覆蓋掉了,這樣student.prototype就沒有constructor了,沒有constructor自然就指回不了student構造函數(shù)了
這個時候我們就需要手動的利用constructor這個屬性指回原來的構造函數(shù)
student.prototype = { constructor:student, school:function() {}, location:function() {} }
我們再輸出一下原型對象的constructor:
這樣我們就知道這個對象到底是通過哪個構造函數(shù)創(chuàng)建出來的了
現(xiàn)在我們更新一下構造函數(shù)、實例、原型對象三者關系圖:
4.原型鏈
因為student原型對象也是一個對象,我們之前說了只要是對象就有對象原型的存在
那我們打印一下原型對象看看里面是否有原型:
function student(uname,age) { this.uname = uname; this.age = age; } student.prototype.school = function() { console.log('深圳理工大學'); } var stu1 = new student('小紅',18); console.log(student.prototype);
輸出結果:
可以看到原型對象里也有一個原型,又因為原型指向的是原型對象,那么我們這個student.prototype里面的__proto__指向的是誰呢?
我們打印一下:
console.log(student.prototype.__proto__);
可以看到指向的是這個constructor指向的是Object原型對象
Object原型對象是由誰創(chuàng)建出來的呢,毫無疑問是Object構造函數(shù)創(chuàng)建出來的。那么我們繼續(xù),Object原型對象也是一個對象,那它也有一個原型,這個原型指向的又是誰呢?
我們輸出一下:
console.log(Object.prototype.__proto__);
最后的結果為空:
這樣就到了最頂層了,這樣我們把這些串起來就能得到一個原型鏈:
5.原型對象中的this指向
我們知道在構造函數(shù)中的this指向的是對象實例,那么原型對象里的函數(shù),這個函數(shù)里的this指向的是誰呢?
我們聲明一個全局變量that,把原型對象里的this賦給that,看看這個that指向的是不是實例對象:
function student(uname,age) { this.uname = uname; this.age = age; } var that; student.prototype.school = function() { that = this; console.log('深圳理工大學'); } var stu1 = new student('小紅',18); stu1.school(); console.log(that === stu1);
輸出結果:
所以原型對象函數(shù)里面的this指向的也是實例對象stu1
6.擴展內置對象(原型對象的應用)
我們可以通過原型對象,對原來的內置對象進行擴展自定義的方法。比如給數(shù)組增加自定義求和的功能
我們輸出一下數(shù)組的原型對象,看看里面有什么方法:
console.log(Array.prototype);
這里沒有給數(shù)組自定義求和的函數(shù),那么我們往數(shù)組的原型對象里添加這個方法:
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指的就是調用這個方法的數(shù)組的長度,因為在上一節(jié)中我們知道原型對象函數(shù)里面的this指向的也是實例對象
我們通過new方法創(chuàng)建一個數(shù)組實例對象,我們向數(shù)組的原型對象添加sum方法,那么我們的實例對象就可以調用它。
輸出結果:
我們再打印一下數(shù)組的原型對象,看看里面有沒有sum方法:
可以看到sum成功的添加到數(shù)組的原型對象里了,這樣我們繼續(xù)用到數(shù)組求和時,就可以直接調用sum方法了。
到此這篇關于一文搞懂JavaScript中原型與原型鏈的文章就介紹到這了,更多相關JS原型與原型鏈內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
JavaScript數(shù)組排序小程序實現(xiàn)解析
這篇文章主要介紹了JavaScript數(shù)組排序小程序實現(xiàn)解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-01-01用javascript實現(xiàn)檢測指定目錄是否存在的方法
今天看到一篇關于onegreen被掛馬的代碼發(fā)現(xiàn)這個函數(shù),它用js就可以檢測,制定的目錄或指定的文件是否存在,一般用來讀chm文件中的圖片來檢測,目錄的存在。高手就是不學好。2008-01-01js判斷一個對象是數(shù)組(函數(shù))的方法實例
這篇文章主要給大家介紹了關于利用js如何判斷一個對象是數(shù)組(函數(shù))的相關資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用JS具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧2019-12-12