摘要:通過同一個構(gòu)造函數(shù)實例化的多個實例對象具有同一個原型對象。所以當給原型對象賦值一個新對象時,切記將原型對象的指回原構(gòu)造函數(shù)以上就是本次分享的內(nèi)容,關(guān)于原型對象的其他知識,下一篇基礎(chǔ)原型對象的那些事二會講到。
談起js的基礎(chǔ),繞不過去的坎就是:原型鏈、作用域鏈、this(em...好吧,還有閉包),今天總結(jié)一下關(guān)于原型對象的一些知識,供自己和大家復(fù)習(xí)。
概念理解什么是原型對象呢?有以下幾點:
1.構(gòu)造函數(shù)有一個prototype屬性,指向構(gòu)造函數(shù)的原型對象。而實例有一個__proto__屬性,也指向原型對象。
PS: 準確的說,實例指向原型對象的是[[Prototype]]屬性,但這是一個隱式屬性,腳本不可訪問。因此瀏覽器廠商提供了一個屬性__proto__,用來顯式指向原型對象,但它并不是ECMA規(guī)范。
注意函數(shù)的是prototype屬性,實例的是__proto__屬性,不要弄錯。
舉個栗子,我們有一個構(gòu)造函數(shù)Person:
function Person(name) { this.name = name }
這時,我們創(chuàng)建一個Person的實例person:
var person = new Person("張三")
按照上邊的理論,就可以表示為:
Person.prototype === person.__proto__
他們指向的都是原型對象。
2.通過同一個構(gòu)造函數(shù)實例化的多個實例對象具有同一個原型對象。
var person1 = new Person("張三") var person2 = new Person("李四")
person1.__proto__、person2.__proto__ 、Person.prototype 他們是兩兩相等的。
3.原型對象有一個constructor屬性,指向該原型對象對應(yīng)的構(gòu)造函數(shù)。
Person.prototype.constructor === Person person.__proto__.constructor === Person
4.實例對象本身并沒有constructor屬性,但它可以繼承原型對象的constructor屬性。
person1.constructor === Person person2.constructor === Person作用
OK,說清楚了什么是原型,就要說一下這玩意是干嘛用的,為啥要在構(gòu)造函數(shù)里加這么個東西。
還是以構(gòu)造函數(shù)Person為例,稍微改一下:
function Person(name) { this.name = name this.sayName = function() { console.log(this.name) } } var person1 = new Person("張三") var person2 = new Person("李四")
我們在構(gòu)造函數(shù)Person中增加了一個方法sayName,這樣Person的實例person1、person2就各自都有了一個sayName方法。
注意,我說的是各自,什么意思呢?就是說每次創(chuàng)建一個實例,就要在內(nèi)存中創(chuàng)建一個sayName方法,這些sayName并不是同一個sayName。
person1.sayName === person2.sayName -> false
多個實例重復(fù)創(chuàng)建相同的方法,這顯然是浪費資源的。這個時候,我們的原型對象登場了。假如構(gòu)造函數(shù)中的方法我們這樣寫:
function Person(name) { this.name = name } Person.prototype.sayName = function() { console.log(this.name) } var person1 = new Person("張三") var person2 = new Person("李四")
和之前的區(qū)別是,我們將sayName方法寫到了構(gòu)造函數(shù)的原型對象上,而不是寫在構(gòu)造函數(shù)里。
這里要先提一個概念,就是當對象找屬性或者方法時,先在自己身上找,找到就調(diào)用。在自己身上找不到時,就會去他的原型對象上找。這就是原型鏈的概念,先點到這,大家知道這件事就可以了。
還記得之前說的嗎:
通過同一個構(gòu)造函數(shù)實例化的多個實例對象具有同一個原型對象
person1和person2上顯然是沒有sayName方法的,但是他們的原型對象有啊。
所以這里的person1.sayName和person2.sayName,實際上都是繼承自他原型對象上的sayName方法,既然原型對象是同一個,那sayName方法自然也是同一個了,所以此時:
person1.sayName === person2.sayName -> true
將需要共享的方法和屬性放到原型對象上,實例在調(diào)用這些屬性和方法時,不用每次都創(chuàng)建,從而節(jié)約資源,這就是原型對象的作用。
共享帶來的“煩惱”但是,既然是共享,就有一點問題了,還是Person構(gòu)造函數(shù),我們再改造一下。
function Person(name) { this.name = name } Person.prototype.ageList = [12, 16, 18] var person1 = new Person("張三") var person2 = new Person("李四")
這個時候,我們在person1上做一些操作:
person1.ageList.push(30)
看一下此時person2.ageList是什么:
person2.ageList -> [12, 16, 18, 30]
有點意思,person2上的ageList也多了30。
原因其實還是因為共享。
共享不好的地方就是:一個實例對引用類型(數(shù)組、對象、函數(shù))的屬性進行修改,會導(dǎo)致原型對象上的屬性修改(其實修改的就是原型對象上的屬性,實例是沒有這個屬性的),進而導(dǎo)致所有的實例中,這個屬性都改了!
很顯然,大部分時候,我們喜歡共享,可以節(jié)約資源。但是不喜歡每一個實例都受影響,要不還創(chuàng)建不同的實例干嘛,用一個不就好了(攤手)。
所以,我們需要把那些需要共享的屬性和方法,寫在原型對象上,而每個實例多帶帶用的、不希望互相影響的屬性,就寫在構(gòu)造函數(shù)里邊。類似這樣:
function Person(name) { this.name = name this.ageList = [12, 16, 18] } var person1 = new Person("張三") var person2 = new Person("李四") person1.ageList.push(30) person1.ageList -> [12, 16, 18, 30] person2.ageList -> [12, 16, 18]此處有坑
關(guān)于原型對象,還有兩個坑,需要和大家說一下。
1.
function Person(name) { this.name = name } Person.prototype.ageList = [12, 16, 18] var person1 = new Person("張三") var person2 = new Person("李四") person1.ageList.push(30) person2.ageList -> [12, 16, 18, 30]
這個沒毛病,但是假如我把操作
person1.ageList.push(30)
改為
person1.ageList = [1, 2, 3],結(jié)果會怎樣呢?
person2.ageList -> [12, 16, 18]
這里就奇怪了,都是對person1.ageList進行操作,怎么就不一樣呢?
其實原因在于,person1.ageList = [1, 2, 3]是一個賦值操作。
我們說過,person1本身是沒有ageList屬性的,而賦值操作,會給person1增加自己的ageList屬性。既然自己有了,也就不用去原型對象上找了。這個時候,原型對象的ageList其實是沒有變化的。而person2沒有自己的ageList屬性,所以person2.ageList還是繼承自原型,就是[12, 16, 18]。
2.
function Person(name) { this.name = name } Person.prototype = { ageList : [12, 16, 18] } var person1 = new Person("張三") var person2 = new Person("李四") person1.ageList.push(30) person2.ageList -> [12, 16, 18, 30]
這里依然沒毛病,但是寫法上有一個變化:我們不再采用Person.prototype.ageList = [12, 16, 18]的形式賦值,而是給Person.prototype賦值了一個對象,對象中有ageList。
這樣看貌似沒有問題,用起來也都一樣:改變person1.ageList,person2.ageList也變化了,說明person1.ageList和person2.ageList還是繼承自同一個原型對象。
但是,這里有一個問題,之前我們說過:
實例對象本身并沒有constructor屬性,但它可以繼承原型對象的constructor屬性
但是此時
person1.constructor === Person -> false person2.constructor === Person -> false
為什么呢?
因為通過給Person.prototype賦值一個對象,就修改了原型對象的指向,此時原型對象的constructor指向內(nèi)置構(gòu)造函數(shù)Object了,使用Person.prototype.ageList = [12, 16, 18]的形式賦值,就不會造成這樣的問題。
所以當給原型對象賦值一個新對象時,切記將原型對象的constructor指回原構(gòu)造函數(shù):
Person.prototype.constructor = Person
以上就是本次分享的內(nèi)容,關(guān)于原型對象的其他知識,下一篇JS基礎(chǔ)—原型對象的那些事(二)會講到。
ps:寫的啰啰嗦嗦的,也不知道大家會不會看著煩。。。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/84900.html
摘要:只是構(gòu)造函數(shù)上的一個屬性,它是一個指針,指向原型對象,并不表示就是原型對象。在上一個例子中,就是一個對象,這個對象可以說是原生構(gòu)造函數(shù)的實例,所以也是一個對象,所以它也有屬性,不過它的指向也就是原型鏈的頂端,再往上就沒有了。 上一篇講了①原型對象是什么;②__proto__、prototype、constructor的關(guān)系;③原型對象的作用;④原型對象帶來的一些需要注意的問題; 沒理解...
摘要:的擴展知識對于哈希表來說,最重要的莫過于生成哈希串的哈希算法和處理沖突的策略了。由于鏈表的查找需要遍歷,如果我們將鏈表換成樹或者哈希表結(jié)構(gòu),那么就能大幅提高沖突元素的查找效率。 最近在整理數(shù)據(jù)結(jié)構(gòu)和算法相關(guān)的知識,小茄專門在github上開了個repo https://github.com/qieguo2016...,后續(xù)內(nèi)容也會更新到這里,歡迎圍觀加星星! js對象 js中的對象是基...
摘要:有需要還可以修改指向謙龍寄生組合式繼承思路是通過借用構(gòu)造函數(shù)來繼承屬性,通過原型鏈的混合形式來繼承方法改變執(zhí)行環(huán)境實現(xiàn)繼承有需要還可以修改指向謙龍謙龍拷貝繼承該方法思路是將另外一個對象的屬性和方法拷貝至另一個對象使用遞歸 前言 js中實現(xiàn)繼承的方式只支持實現(xiàn)繼承,即繼承實際的方法,而實現(xiàn)繼承主要是依靠原型鏈來完成的。 原型鏈式繼承 該方式實現(xiàn)的本質(zhì)是重寫原型對象,代之以一個新類型的實例...
摘要:委托上面的代碼結(jié)合了構(gòu)造函數(shù)和原型兩種方式去創(chuàng)建對象,首先聊聊構(gòu)造函數(shù)構(gòu)造函數(shù)構(gòu)造函數(shù)本質(zhì)上還是函數(shù),只不過為了區(qū)分將其首字母大寫了而已。注意注釋掉的代碼是自動執(zhí)行的,但這并不是構(gòu)造函數(shù)獨有的,每個函數(shù)在聲明時都會自動生成。 首先看看下面兩個1+1=2的問題: 問題一:為什么改變length的值,數(shù)組的內(nèi)容會變化? var arr = [1]; arr.length = 3; aler...
摘要:如圖遍歷數(shù)組遍歷數(shù)組元素并以某種方式處理每個元素是一個常見的操作。如圖不過,里的功能比較強大,可以遍歷而且返回值是的則被省略掉總結(jié)遍歷對象,遍歷出來的是鍵名,而不是鍵值,參數(shù)必須是對象。 可能是由于職業(yè)的關(guān)系,下班之后完全不想Open PC,但很多知識點有必要自己做個小小總結(jié)。本人之前對原生Array和Object完全沒概念。 遍歷對象的方法: Object.keys(Object)...
閱讀 2307·2023-04-25 14:17
閱讀 1515·2021-11-23 10:02
閱讀 2170·2021-11-23 09:51
閱讀 873·2021-10-14 09:49
閱讀 3384·2021-10-11 10:57
閱讀 2921·2021-09-24 09:47
閱讀 3046·2021-08-24 10:00
閱讀 2298·2019-08-29 18:46