JS原型學習筆記,若有錯誤,還請留言~~node
在談window以前,試想一個簡單的問題,打開瀏覽器在控制檯輸入console.log("Hello");
並按下回車鍵,咱們理所應當看到了控制檯給咱們返回的結果Hello
,那麼,console.log()
這個方法是怎麼來的呢?其實瀏覽器中已經爲咱們內置了一個全局對象叫作window,window做爲全局對象,表明腳本正在運行的瀏覽器窗口。console.log()
是一種簡寫的格式,更加精確的寫法爲:window.console.log()
。window下則封裝了多種 多樣的屬性,這些屬性中,有些是瀏覽器自帶的屬性,有些則是ECMAScript標準規定的屬性。ECMAScript規定的全局對象爲global,可是在瀏覽器下則是window。
數組
window
能夠查看全局對象的全部屬性。而在node.js環境中,則須要使用
global
,且瀏覽器中規定的屬性在node.js環境下天然是無效的。
先上圖:
瀏覽器
toString()
方法,看一看內存中到底會發生什麼。
var obj = new Object();
複製代碼
obj.__proto__ === Object.prototype
結果會返回
true
。
__proto__
,這個屬性指向了一個
Object.prototype
這樣一個對象,Object.prototype對象中有着Object所共有的一些屬性。其實這個prototype就是原型,比起原型,我更喜歡叫它共有屬性對象。那麼
__proto__
是什麼呢?
__proto__
是瀏覽器自動賦予
對象的一個屬性,這個屬性指向着一個函數的原型,固然最後的root必然是Object.prototype。
var n = new Number(15);
n.toString(16);// "f"
複製代碼
上述代碼的含義是,將數值類型的n轉化爲16進制後,再將其轉化爲字符串,15在16進制中對應的值爲f,轉化爲字符串以後的結果爲"f"。很顯然,Object原型中的toString()方法是沒有辦法將一個值按照進制轉化,再變爲字符串的,也就是說,Number類型的toString(),不一樣於Object原型的toString()方法。假若是Java,咱們會想到方法的重寫,可是JS則不同,咱們繼續從內存模型的角度來分析到底發生了什麼:
bash
var n = new Number(15);
n爲一個對象,若是不明白爲何n的值會在堆內存中,能夠參考個人文章
JS內存模型。咱們能夠看到,對象n的
__proto__
指向了Number.prototype,在Number.prototype中有什麼呢?
Number.prototype.toString === Object.prototype.toString
返回的結果爲false,也就是說,Number.prototype中的toString是一個「重寫」的屬性,當咱們聲明瞭對象n,並調用toString()方法時,首先,瀏覽器會在n這個對象中尋找toString這個屬性,若是沒有它就會在n這個對象的
__proto__
屬性所指向的原型中尋找,
n.__proto__
指向了
Number.prototype
。 由於Numebr.prototype即Number原型也是一個對象,
Number.prototype.__proto__
則指向了root即
Object.prototype
。若是在Number原型中沒有toString這個屬性,那麼順其天然地就會在Object原型中尋找這個屬性。固然本例中,在Number的原型中
Number.prototype
找到了toString這個屬性,天然會調用它所指向的Number獨有的toString()方法。剛剛描述的過程當中,這種指向的關係好似
鏈表,而在JS中,咱們能夠形象地稱做爲「
原型鏈」。
typeof
一個函數返回的結果爲「function」,可是咱們一再強調JavaScript裏的數據類型只有七種,不管是數組仍是函數,它們的本質都是對象。既然明確了函數是一個對象,那麼在上文中,我曾經暗示prototype是一個函數所擁有的屬性,__proto__是一個對象所擁有的屬性,那麼函數既然是對象,那麼換言之,一個函數中天然擁有兩種屬性了。咱們再將內存模型圖完善一些:
Funcion.__proto__ === Funciton.prototype
。 這能夠形象地理解爲:本身造本身,本身賦予本身了屬性。其實理解不了上圖也可有可無,咱們只須要記住原型裏面的一個規則便可:
內置函數.__proto__ === Function.prototype;
複製代碼
JS中一切皆爲對象?很顯然這句話是錯的,用最簡單的代碼就能夠證實:函數
var n = 15;
typeof n;// "number"
複製代碼
JS中,有七種數據類型,在上面的代碼中,咱們聲明瞭var n = 15;
,在使用typeof n
時,咱們也能夠看到返回的類型是number
。可是,咱們卻能夠這樣作:post
n.toString(16);// "f"
複製代碼
和上面介紹的var n = new Number(15)
聲明n的方式不一樣。n的typeof 返回的是一個「number」,若是使用var n = new Number(15)
聲明n,那麼使用typeof n
返回的結果就會是「object」。在聲明一個對象時,瀏覽器會爲這個對象自動添加__proto__
這樣一個屬性指向原型,好調用相應的方法,既然咱們聲明瞭var n = 15;
且能夠調用toString()這樣一個方法,那不仍是說明n其實是一個對象嗎?實際上,並非這樣的,n天然是一個number類型的數字,只不過這裏面另有蹊蹺。學習
var n = 15;
n.toString(16);
複製代碼
當咱們調用toString()方法時,在堆內存中會生成一個臨時對象,咱們暫時叫它temp。也就是說這個過程是這樣的:spa
var n = 15;
// 調用toString()方法時,會在堆內存中產生一個臨時變量temp
// var temp = new Number(n);
// 將temp.toString(16)的結果記錄下來
// 臨時變量temp隨即被"抹殺掉"
複製代碼
一個數值型,字符串型等普通類型的變量能夠調用原型中的方法,並不能說明它們類型的本質是對象,由於「建立臨時變量機制」,讓許多人對此有了誤解,實際上數值型便是數值型,字符串型是字符串型,JS當中一切皆對象很顯然是一個謬論。再看一個例子:prototype
var a = 1;
// 問:執行此條語句 a.xxx = 2 是否會執行成功?
複製代碼
其實只要理解了"臨時對象"這個概念,就不難回答這個問題,在聲明var a = 1;
後,咱們已經肯定了a的類型是Number,在執行語句a.xxx = 2;
時,在堆內存中會生成一個臨時對象,對於這個臨時對象來講,執行a.xxx = 2;
就至關於添加了一個屬性xxx其值爲2,因此這條語句天然能執行成功。固然這個臨時對象會馬上被「抹殺」,當咱們再次在控制檯輸入a.xxx查看這個值時,返回的結果天然是undefined。
插件