你真的完全理解原型與原型鏈?

前言:原型與原型鏈兩個(gè)名詞對(duì)于大部分的前端初學(xué)者來(lái)說(shuō)玩焰,對(duì)這兩個(gè)概念很模糊织阅,無(wú)從入手,而且還可能會(huì)一臉懵逼震捣,本人不才荔棉,準(zhǔn)備介紹一下原型以及原型鏈。本文從下面幾個(gè)方面講解蒿赢,然后在深入講解原型與原型鏈的相關(guān)知識(shí)润樱。

  • 全局對(duì)象
  • 簡(jiǎn)單類型與對(duì)象
  • Number、Boolean羡棵、String壹若、Object四個(gè)對(duì)象
  • (共用屬性)原型
  • __proto__與 prototype
  • 燒腦的等式
  • 奇葩的Function

全局對(duì)象Window

ECMAScript 規(guī)定全局對(duì)象叫做 global,但是瀏覽器把 window 作為全局對(duì)象(瀏覽器先存在的)

ECMAScript規(guī)定 瀏覽器自己加的屬性(私有)
parseInt alert
parseFloat comfirm
Number console.log
String console.dir
Boolean document
Object history

注:

  • window對(duì)象中的所有方法都可以省去window皂冰,alert()方法可以寫(xiě)成window.alert()店展,或者省去window,直接寫(xiě)做alert()
  • 瀏覽器自己加的屬性秃流,因?yàn)闆](méi)有標(biāo)準(zhǔn)赂蕴,所以瀏覽器上呈現(xiàn)的效果是不一樣的

簡(jiǎn)單類型與對(duì)象

聲明一個(gè)數(shù)值類型的變量

//聲明簡(jiǎn)單的數(shù)據(jù)類型
var n1 = 1;
//聲明一個(gè)對(duì)象,可以用n2.toString()將其轉(zhuǎn)換成字符串
var n2 = new Number(1);

下面通過(guò)內(nèi)存圖查看它們之間的區(qū)別


簡(jiǎn)單類型與對(duì)象.png

它們?cè)趦?nèi)存中的存儲(chǔ)方式是不同的舶胀,n1是直接聲明簡(jiǎn)單的數(shù)據(jù)類型(number)概说,存儲(chǔ)在stack棧內(nèi)存中,而n2是聲明了一個(gè)對(duì)象stack內(nèi)存中存儲(chǔ)著該對(duì)象的內(nèi)存地址嚣伐,對(duì)象的內(nèi)容存儲(chǔ)在heap堆內(nèi)存中糖赔。
但是在平常寫(xiě)代碼的時(shí)候我們沒(méi)有使用n2的寫(xiě)法,也可以使用valueOf() 方法 和toSting()方法,這里有一段黑歷史(JS之父為了滿足Boss的需求轩端,為了讓JavaScript長(zhǎng)得像Java)放典,可以自行g(shù)oogle
原因是:JS使用妙計(jì):臨時(shí)轉(zhuǎn)換(用完了就沒(méi)了),如果你使用n1的寫(xiě)法,調(diào)用了了如valueOf方法奋构,那么JS會(huì)創(chuàng)建一個(gè)臨時(shí)的對(duì)象壳影,然后調(diào)用該對(duì)象的方法,調(diào)用結(jié)束后臨時(shí)對(duì)象就會(huì)被垃圾回收掉声怔。

踩坑時(shí)間到:

var n =1;
n.xxx = 2;
//①n.xxx = 2;會(huì)報(bào)錯(cuò)嗎态贤?
//n.xxx的值是多少?

你覺(jué)得是結(jié)果會(huì)怎樣醋火,下面就來(lái)揭秘啦
答案:n.xxx = 2;這句話不會(huì)報(bào)錯(cuò),執(zhí)行這句話時(shí)硼瓣,JS會(huì)創(chuàng)建一個(gè)臨時(shí)對(duì)象冤馏,為臨時(shí)對(duì)象添加屬性,執(zhí)行這句話后,臨時(shí)對(duì)象就會(huì)被回收入偷,如果再執(zhí)行n.xxx瘩欺,結(jié)果是undefined脖岛,因?yàn)榻on添加完屬性后臨時(shí)對(duì)象就會(huì)被回收隧出,n本質(zhì)上還是一個(gè)數(shù)值,沒(méi)有臨時(shí)對(duì)象丽猬,再去重新創(chuàng)建一個(gè)新的對(duì)象宿饱,里面沒(méi)有這個(gè)屬性(有個(gè)這屬性的對(duì)象已經(jīng)被刪了)。

Number對(duì)象

Number的常用屬性 含義
Number.valueOf() 獲取對(duì)象本身的值
Number.toString() 將數(shù)值轉(zhuǎn)化為字符串
Number.toFixed() 將其轉(zhuǎn)換為小數(shù)
Number.toExponential() 將其轉(zhuǎn)化為科學(xué)計(jì)數(shù)法

如:

var n2 = new Number(1);
n2.toString();  //"1"
n2.valueOf();  //1
n2.toFixed(2);  //"1.00"
n2.toExponential();  //"1e+0"

注:number類型的的toString方法可以加參數(shù)脚祟,表示按照什么進(jìn)制來(lái)解析(不加參數(shù)默認(rèn)按十進(jìn)制解析)谬以,如:

(100).toString(16);  //"64"
(100).toString(2); //"1100100"

String對(duì)象

String的常用屬性 含義
String.charAt() 獲取字符串中某一位的字符
String.charCodeAt() 獲取字符串中某一位的字符的Unicode編碼
String.trim() 刪除字符串中多余的空格
String1.concat(String2) 連接字符串1和字符串2
String.slice(start,end) 切片,截取字符串(包前不包后)由桌,從start到end
String.replace('e','o') 將字符串中的e替換成o(只能替換第一次出現(xiàn)的字符)
String.indexOf() 搜索字符串中的內(nèi)容(只檢測(cè)到第一次出現(xiàn)的字符)为黎,沒(méi)搜到返回-1
String.split() 分隔
String.substr(start[, length]) 截取,返回一個(gè)字符串中從指定位置開(kāi)始到指定字符數(shù)的字符

如:

var s = new String('hello World');

//獲取字符串中某一位的字符
s.charAt(1) ; //"e"

//獲取字符串中某一位的字符的Unicode編碼
s.charCodeAt(0);  //104

//刪除字符串中多余的空格,是左右兩面的空格
s.trim();  //"hello World"

//連接字符串1和字符串2,字符串1和字符串2是沒(méi)有被改變的
var s1 = "hello";
var s2 = " world";
s1.concat(s2);  //"hello world"
console.log(s1);  //"hello"
console.log(s2);  //" world"

//切片,截取字符串(包前不包后)行您,從start到end
s.slice(0,2);  //"he"

//將字符串中的e替換成o(只能替換第一次出現(xiàn)的字符)
s.replace('e','o');  //"hollo World"

//搜索字符串中的內(nèi)容(只檢測(cè)到第一次出現(xiàn)的字符)铭乾,沒(méi)搜到返回-1
s.indexOf('s')  //-1

//根據(jù)字符串中間的空格分隔字符串,變成數(shù)組
s.split();  //["hello World"]

//返回一個(gè)字符串中從指定位置開(kāi)始到指定字符數(shù)的字符
s.substr(0);  //"hello World"
s.substr(0,5);  //"hello"

Boolean對(duì)象

介紹一個(gè)兩種不同的賦值方法下容易出錯(cuò)的地方娃循。

var f1 = false;
var f2 = new Boolean(false);
if(f1) { console.log('1') } ;
if(f2) { console.log('2') } ;

注:
f1和f2的值都是false炕檩,但是f2是對(duì)象,一切對(duì)象(不論是否是空對(duì)象)都是truey淮野,所以使用if判斷語(yǔ)句捧书,會(huì)將f2轉(zhuǎn)化為了true,打印出2

Object對(duì)象

Object對(duì)象骤星,兩種賦值方法是一樣的,沒(méi)有任何區(qū)別爆哑。
注:

var obj1 = {};
var obj2 = {};
obj1 === obj2; // false

為什么obj1不恒等于obj2洞难??揭朝?同樣都是空獨(dú)享队贱,但是它們?cè)趕tack棧內(nèi)存中存儲(chǔ)的內(nèi)容是heap堆內(nèi)存中的地址色冀,每個(gè)對(duì)象的內(nèi)容在heap內(nèi)存中的地址是不會(huì)一樣的,所以對(duì)象與對(duì)象一般都是不相等的柱嫌。(除非你將一個(gè)對(duì)象的內(nèi)存地址復(fù)制給另一個(gè)對(duì)象)

敲黑板锋恬,重頭戲來(lái)了

原型/共用屬性

所有對(duì)象都有 toString 和 valueOf 屬性,那么我們是否有必要給每個(gè)對(duì)象一個(gè) toString 和 valueOf 呢编丘?答案是不需要的与学。因?yàn)镴S每次聲明一個(gè)對(duì)象都要寫(xiě)一次這些方法這樣寫(xiě)的話會(huì)非常占用內(nèi)存,而且內(nèi)存還那么嘉抓,所以JS 的做法是把所有的對(duì)象共用的屬性全部放在heap堆內(nèi)存的一個(gè)對(duì)象(共用屬性組成的對(duì)象)索守,然后讓每一個(gè)對(duì)象的 __proto__存儲(chǔ)這個(gè)「共用屬性組成的對(duì)象」的地址。而這個(gè)共用屬性抑片,就是傳說(shuō)中的原型
原型的目的:可以減少不必要的內(nèi)存浪費(fèi)
如:

var s1 = new String('hi');
var s2 = new String('he');
var n1 = new Number(1);
var n2 = new Number(2);
var b1 = new Boolean(true);
var b2 = new Boolean(false);
var o1 = {
    name: 'xiao',
    age: 6
}
var o2 = {
    name: 'ming',
    age: 18
}

根據(jù)下面內(nèi)存圖分析原型

原型.png

圖中紅色的箭頭(不是很明顯卵佛,是有兩個(gè)箭頭的),所連成的線敞斋,就組成了一條原型鏈截汪。

  • __proto__就是這些共用屬性的引用。
  • 聲明Number對(duì)象植捎、String對(duì)象衙解、Boolean對(duì)象時(shí),如聲明Number對(duì)象鸥跟,在stack棧內(nèi)存中存儲(chǔ)著該對(duì)象的內(nèi)存地址丢郊,對(duì)象的內(nèi)容存儲(chǔ)在heap堆內(nèi)存中。對(duì)象的內(nèi)容里面有__proto__医咨,它指向的Number的共用屬性(Number.prototype)枫匾。
    某些等式:
//對(duì)象的__proto__指向Object對(duì)象的prototype
var o1= {};
o1.__proto__ === Object.prototype;

var n1 = new Number(2);
//數(shù)值的__proto__指向Number對(duì)象的共用屬性
n1.__proto__ === Number.prototype;
//Number對(duì)象的共用屬性的__proto__指向Object對(duì)象的共用屬性。
n1.__proto__.__proto__ === Object.prototype;

其他對(duì)象也可以得出類似的等式

__proto__ 與 prototype

prototype是瀏覽器本身就寫(xiě)好的.png

上圖是我們還沒(méi)有寫(xiě)代碼的時(shí)候,瀏覽器都已經(jīng)初始化好了拟淮,prototype是瀏覽器提前準(zhǔn)備好的干茉。
當(dāng)我們寫(xiě)代碼的時(shí)候:

var s = new String(' hello ') ;

我們創(chuàng)建的對(duì)象的__proto__ 會(huì)用來(lái)指向原有的String對(duì)象,使得我們可以調(diào)用String對(duì)象的公有屬性很泊。
總結(jié):

  • __proto__是某對(duì)象的共用屬性的引用角虫,是為了用戶使用其共用屬性中的方法而存在的 。(使用的)
  • prototype 是瀏覽器寫(xiě)的委造,本身就存在戳鹅,是某對(duì)象的共同屬性的引用,為了不讓對(duì)象的共用屬性因沒(méi)有被調(diào)用而被垃圾回收而存在昏兆。(防止回收)

一些燒腦的等式

通過(guò)var 對(duì)象 = new 函數(shù)枫虏;推出其他燒腦的等式

var n = new Number(1);
//var 對(duì)象 = new 函數(shù);

//對(duì)象的__proto__最終指向某對(duì)象的共用屬性,構(gòu)造某對(duì)象的函數(shù)的prototype也指向某對(duì)象的共用屬性
//__proto__ 是對(duì)象的屬性隶债,prototype是函數(shù)的屬性
對(duì)象.__proto__ === 函數(shù).prototype

//函數(shù)的prototype是對(duì)象腾它,這個(gè)對(duì)象對(duì)應(yīng)的就是最簡(jiǎn)單的函數(shù)Object
函數(shù).prototype.__proto__ === Object.prototype

//由于函數(shù)本身即是函數(shù)(最優(yōu)先被視為函數(shù)),也是對(duì)象死讹,而函數(shù)的構(gòu)造函數(shù)是Function
函數(shù).__proto__ === Function.prototype

//Function即是對(duì)象瞒滴,也是函數(shù),但他優(yōu)先是個(gè)函數(shù)
Function.__proto__ === Function.prototype

//Function.prototype也是對(duì)象赞警,是普通的對(duì)象妓忍,所以其對(duì)應(yīng)的函數(shù)是Object
Funciton.prototype.__proto__=== Object.prototype

奇葩的Function

我們經(jīng)過(guò)上面的推導(dǎo),發(fā)現(xiàn)Function仅颇,他即是函數(shù)单默,也是對(duì)象,所以他有函數(shù)的prototype忘瓦,也有對(duì)象的__proto__搁廓,即Function.prototype 與Funciton.__proto__互相引用。
注:
Object.__proto__ === Function.prototype耕皮,因?yàn)?Function 是 Object 的構(gòu)造函數(shù)境蜕。

參考資料:
初識(shí)傳說(shuō)中的原型與原型鏈

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市凌停,隨后出現(xiàn)的幾起案子粱年,更是在濱河造成了極大的恐慌,老刑警劉巖罚拟,帶你破解...
    沈念sama閱讀 222,590評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件台诗,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡赐俗,警方通過(guò)查閱死者的電腦和手機(jī)拉队,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)阻逮,“玉大人粱快,你說(shuō)我怎么就攤上這事∈宥螅” “怎么了事哭?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,301評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)瓜富。 經(jīng)常有香客問(wèn)我鳍咱,道長(zhǎng),這世上最難降的妖魔是什么与柑? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,078評(píng)論 1 300
  • 正文 為了忘掉前任流炕,我火速辦了婚禮澎现,結(jié)果婚禮上仅胞,老公的妹妹穿的比我還像新娘每辟。我一直安慰自己,他們只是感情好干旧,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,082評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布渠欺。 她就那樣靜靜地躺著,像睡著了一般椎眯。 火紅的嫁衣襯著肌膚如雪挠将。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,682評(píng)論 1 312
  • 那天编整,我揣著相機(jī)與錄音舔稀,去河邊找鬼。 笑死掌测,一個(gè)胖子當(dāng)著我的面吹牛内贮,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播汞斧,決...
    沈念sama閱讀 41,155評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼夜郁,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了粘勒?” 一聲冷哼從身側(cè)響起竞端,我...
    開(kāi)封第一講書(shū)人閱讀 40,098評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎庙睡,沒(méi)想到半個(gè)月后事富,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,638評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡乘陪,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,701評(píng)論 3 342
  • 正文 我和宋清朗相戀三年统台,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片暂刘。...
    茶點(diǎn)故事閱讀 40,852評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡饺谬,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出谣拣,到底是詐尸還是另有隱情募寨,我是刑警寧澤,帶...
    沈念sama閱讀 36,520評(píng)論 5 351
  • 正文 年R本政府宣布森缠,位于F島的核電站拔鹰,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏贵涵。R本人自食惡果不足惜列肢,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,181評(píng)論 3 335
  • 文/蒙蒙 一恰画、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧瓷马,春花似錦拴还、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,674評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至怀骤,卻和暖如春费封,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蒋伦。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,788評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工弓摘, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人痕届。 一個(gè)月前我還...
    沈念sama閱讀 49,279評(píng)論 3 379
  • 正文 我出身青樓韧献,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親爷抓。 傳聞我的和親對(duì)象是個(gè)殘疾皇子势决,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,851評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容

  • 前言:原型與原型鏈這兩個(gè)名詞毋庸置疑聽(tīng)起來(lái)是很高大上的,以前總是出現(xiàn)在傳說(shuō)中蓝撇,這兩天看了教程果复,準(zhǔn)備介紹一下這傳說(shuō)中...
    EnochQin閱讀 662評(píng)論 0 3
  • 什么是原型語(yǔ)言 只有對(duì)象,沒(méi)有類;對(duì)象繼承對(duì)象,而不是類繼承類。 “原型對(duì)象”是核心概念渤昌。原型對(duì)象是新對(duì)象的模板虽抄,...
    zhoulujun閱讀 2,335評(píng)論 0 12
  • 在這篇文章里我們將要了解以下幾個(gè)方面: 關(guān)于內(nèi)存的那點(diǎn)事兒 關(guān)于垃圾回收那點(diǎn)事兒 包裝對(duì)象 什么是原型 什么是原型...
    長(zhǎng)鯨向南閱讀 779評(píng)論 0 1
  • 寫(xiě)在前面: 因?yàn)樯蠈W(xué)交手機(jī),其實(shí)根本不能按時(shí)更新独柑,在微博看見(jiàn)催更的時(shí)候又開(kāi)心又惶恐迈窟,我其實(shí)怕我寫(xiě)的東西就是垃圾,所...
    三R哥閱讀 573評(píng)論 7 2
  • 陸奇最大的遺憾是未能憑借自己的能力把百度這艘大船真正調(diào)頭忌栅。應(yīng)該也不是陸奇與百度內(nèi)部具體某個(gè)人的沖突车酣。參加婚禮的賓客...
    ciwwoetyve閱讀 187評(píng)論 0 0