Javascript之深入淺出prototype
我們先來講一個(gè)故事,一個(gè)大大的池塘,里面有很多魚。這是屬于我們大家的池塘所以里面的魚我們都可以吃,但是我們也會(huì)從集市買一些魚放在家里,那么放在家里的魚肯定是屬于我們私人的,外人是不會(huì)擁有的。那么在js里我們就把這個(gè)池塘稱為原型對(duì)象,池塘里面我們所共享的魚稱為原型中的屬性及方法,而我們自己的魚稱為構(gòu)造函數(shù)中的屬性及方法,我們是什么呢?對(duì)了,我們是對(duì)象的實(shí)例。
以上是為了讓大家能夠趣味性的對(duì)prototype有一個(gè)概念,接下來就通過代碼具體總結(jié)一下prototype~
一、理解prototype
我們創(chuàng)建的每一個(gè)函數(shù)都有一個(gè)prototype屬性,這個(gè)屬性是一個(gè)指向?qū)ο蟮闹羔槨?/p>
構(gòu)建對(duì)象中有一種模式叫做原型模式,意思是將對(duì)象實(shí)例所不可共享的屬性及方法定義在構(gòu)造函數(shù)中,而將可共享的屬性及方法放在原型對(duì)象中,也就是prototype指向的對(duì)象中。以下是用原型模式創(chuàng)建的一個(gè)對(duì)象:
function person(name, age) { this.name = name; this.age = age; } person.prototype = { sayName: function() { console.log(this.name); } }; var p1 = new person("Wind", 20); p1.sayName(); // "Wind" var p2 = new person("Nic", 20); p2.sayName(); // Nic
這里我將name、age屬性定義在構(gòu)造函數(shù)中,將sayName方法定義在原型中。所以p1和p2對(duì)象實(shí)例的內(nèi)存空間里面各有一份name和age,但是它們卻共享一份sayName方法,意思是它們調(diào)用的sayName方法是同一個(gè)。
試想如果我們不用prototype,而是直接將sayName寫進(jìn)構(gòu)造函數(shù)呢?
那么p1和p2中將各有一份sayName,這樣浪費(fèi)內(nèi)存空間,所以用prototype的好處之一:提高了代碼的復(fù)用性,減少內(nèi)存。
在了解原型對(duì)象的同時(shí)我們還有一個(gè)小知識(shí)要明白:每當(dāng)代碼讀取一個(gè)對(duì)象屬性的時(shí)候會(huì)執(zhí)行一次搜索,搜索目標(biāo)是給定名字的屬性,搜索路徑為:
對(duì)象實(shí)例本身---->原型對(duì)象---->對(duì)象所繼承的父類對(duì)象---->父類對(duì)象原型...---->原型鏈末端
二、prototype的注意點(diǎn)
1、不可變性:盡管prototype是共享的,但不能通過對(duì)象實(shí)例重寫原型中的值,但是可以由對(duì)象統(tǒng)一改。通俗一點(diǎn):只能爸爸統(tǒng)一改,不能兒子改。(這也和類型有關(guān)系,孩子不能改變基本類型的值,但是可以改變對(duì)象,比如數(shù)組)
基本類型:
function person() {} person.prototype = { num: 0 }; var p1 = new person(); var p2 = new person(); p1.num++; p2.num; // 0
非基本類型:
function person() {} person.prototype = { num: [1,2,3] }; var p1 = new person(); var p2 = new person(); p1.num[2] = 8; p2.num; // [1, 2, 8] 改變了
2、同名覆蓋性:如果我們?cè)趯?shí)例中添加了一個(gè)與原型屬性同名的屬性,那么該屬性會(huì)創(chuàng)建到對(duì)象實(shí)例中并且會(huì)覆蓋掉原型中的相應(yīng)屬性。
function person(name) { this.name = name; } person.prototype = { age: 18 9 }; var p1 = new person("Wind"); var p2 = new person("Nic"); p1.age = 20; p1.age; // 20 p2.age; // 18
3、使用對(duì)象字面量創(chuàng)建原型方法,會(huì)切斷之前的鏈而重寫原型鏈
function person(name) { this.name = name; } person.prototype = { sayName: function() { console.log(this.name); } }; var p1 = new person("Wind"); person.prototype = { age = 20 }; p1.sayName(); // error
因?yàn)閜rototype指針指向了一個(gè)新的對(duì)象,切斷了構(gòu)造函數(shù)與之前的prototype舊對(duì)象的聯(lián)系,所以p1不能調(diào)用了它。那么p1調(diào)用新對(duì)象的屬性呢?
p1.age; // error
所以我做了一個(gè)大膽的猜測(cè),就是以前包含sayName的舊對(duì)象被“拋棄”了,也就是被內(nèi)存回收了,然而p1的prototype指針指向的依舊是舊對(duì)象,所以會(huì)產(chǎn)生error。
三、總結(jié)
prototype的用法:構(gòu)造函數(shù)模型用于定義實(shí)例的屬性,而原型模型用于定義方法和共享的屬性。
以上就是本文的全部內(nèi)容,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來一定的幫助,同時(shí)也希望多多支持腳本之家!
相關(guān)文章
SOSO地圖JS畫出標(biāo)注和中心點(diǎn)以html形式運(yùn)行
SOSO地圖想必大家都知道吧,本文將為大家詳細(xì)介紹下使用JS畫出標(biāo)注和中心點(diǎn),直接貼出代碼,感興趣的朋友可以參考下2013-08-08TypeScript使用vscode監(jiān)視代碼編譯的過程
這篇文章主要介紹了TypeScript使用vscode監(jiān)視代碼編譯,使用tsc 文件名稱可以將ts文件轉(zhuǎn)化為js文件,js文件可以引入在html文件中直接使用,需要的朋友可以參考下2021-12-12頁面js遇到亂碼問題的解決方法是和無法轉(zhuǎn)碼的情況
在老項(xiàng)目里加些js文件和老項(xiàng)目的編碼格式不一致出現(xiàn)亂碼,由于兩個(gè)文件都不能轉(zhuǎn)格式,于是百度個(gè)不錯(cuò)的方法在此與大家分享下2014-04-04javascript 處理HTML元素必須避免使用的一種方法
我們?cè)诰帉懬芭_(tái)頁面的時(shí)候,可能經(jīng)常會(huì)用到“javascript+數(shù)據(jù)”生成頁面元素的方法,但當(dāng)我們要處理的數(shù)據(jù)量較大,導(dǎo)致頁面需要展現(xiàn)過多的控件的時(shí)候,頁面的響應(yīng)速度也會(huì)直線下降2009-07-07Bootstrap導(dǎo)航條學(xué)習(xí)使用(二)
這篇文章主要為大家詳細(xì)介紹了Bootstrap導(dǎo)航條的使用方法第二篇,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-02-02動(dòng)態(tài)的改變IFrame的高度實(shí)現(xiàn)IFrame自動(dòng)伸展適應(yīng)高度
動(dòng)態(tài)的改變IFrame的高度,實(shí)現(xiàn)IFrame自動(dòng)伸展,父頁面也自動(dòng)神縮原理: 在IFrame子頁面一加載的時(shí)候,調(diào)用父IFrame對(duì)象,改變其高度2012-12-12