本博客主要講以下幾部分
全局對(duì)象
window
全局函數(shù)
公用屬性是什么
重要公式
全局對(duì)象window
ECMAScript 規(guī)定全局對(duì)象叫做 global
驾窟,但是瀏覽器把 window
作為全局對(duì)象(瀏覽器先存在的)
window
就是一個(gè)哈希表,有很多屬性伦连。
window
的屬性就是全局變量。
這些全局變量分為兩種:
-
一種是
ECMAScript
規(guī)定的
global.parseInt
global.parseFloat
global.Number
global.String
global.Boolean
global.Object
-
一種是瀏覽器自己加的屬性(私有)
history //瀏覽器歷史罐柳,也叫BOM
window.alert
window.prompt
window.comfirm
window.console.log
window.console.dir
window.document //有規(guī)范踱讨,叫DOM(W3C規(guī)定)
window.document.createElement
window.document.getElementById
所有 API 都可以在 MDN 里找到詳細(xì)的資料悴侵。
全局函數(shù)
-
Number
先看以下代碼
var n = 1
var n1 = new Number(1) //創(chuàng)建一個(gè) Number 對(duì)象
那么問(wèn)題來(lái)了箱叁,
n
與 n1
的區(qū)別是什么铡羡?
這時(shí)畫一個(gè)內(nèi)存圖就清楚了
這樣可以看出积蔚,
n
和n1
的區(qū)別是內(nèi)存上是不一樣的那么
Number(1)
里寫了什么呢?valueOf
,toString
...這些都是Number()
函數(shù)內(nèi)置的操作符烦周,也就是說(shuō)尽爆,如果包裝成對(duì)象的話,n1
就有更多便捷的操作給你用读慎,而n
就只有數(shù)字1
-
臨時(shí)轉(zhuǎn)換
這是為什么呢漱贱,因?yàn)镴S發(fā)明時(shí),JS之父的BOSS要求JS要長(zhǎng)得像Java
所以就有了Number()
函數(shù)贪壳,但是實(shí)際上Number()
基本沒(méi)用饱亿,大家都喜歡直接用var n = 1
,但是n.toString
因?yàn)椴皇菍?duì)象闰靴,所以不能直接轉(zhuǎn)換
這時(shí),臨時(shí)轉(zhuǎn)換就出現(xiàn)了
臨時(shí)轉(zhuǎn)換就是在想要調(diào)用n
的toString
操作時(shí)钻注,創(chuàng)建一個(gè)臨時(shí)對(duì)象蚂且,用這個(gè)對(duì)象的toString()
方法去操作n
,臨時(shí)轉(zhuǎn)換后就會(huì)把那個(gè)臨時(shí)對(duì)象抹殺
掉
用內(nèi)存圖來(lái)理解是這樣的:
所以現(xiàn)在幅恋,就算我們只寫
var n = 1
杏死,之后也能使用復(fù)雜Number()
的所有功能
但是要注意的是,n
本身是沒(méi)有toString()
函數(shù)的捆交,只是利用來(lái)臨時(shí)變量的方法淑翼,請(qǐng)看下面這題
var n = 1
n.xxx = 2
那么,n.xxx的值是什么呢品追?
因?yàn)?code>n只是將2存到臨時(shí)變量的xxx
里玄括,所以n.xxx的值是undefined
-
String
var s = 'asdfg'
var s1 = new String(asdfg)
和之前理解Number()
一樣,s
之所以可以直接Number(s)
肉瓦,是因?yàn)闉g覽器創(chuàng)建了一個(gè)臨時(shí)對(duì)象遭京,然后's'調(diào)用了這個(gè)對(duì)象的'Number()'方法胃惜,使用完后這個(gè)臨時(shí)對(duì)象就被抹殺了
這里要提一句的是,代碼中的new
如果不加哪雕,那就是用作轉(zhuǎn)換用的船殉。如果加了,就是生成對(duì)象斯嚎。
-
Boolean
接下來(lái)看這一題
var f = false
var f1 = new Boolean(false)
if(f){console.log(1)} // 打印1
if(f1){console.log(2)} // 打印2
請(qǐng)問(wèn)這題瀏覽器會(huì)打印出什么呢利虫?
我們畫個(gè)內(nèi)存圖
因?yàn)?code>f=false,所以
1
是不會(huì)打印出來(lái)的因?yàn)?code>f1實(shí)際上是一個(gè)對(duì)象堡僻,所以瀏覽器會(huì)打印出
2
-
Object
var o1 = {}
var o2 = new Object()
其實(shí)o1
與o2
的方式根本沒(méi)區(qū)別糠惫,只是他們的值內(nèi)存地址不一樣而已
所以Object()
基本沒(méi)用
-
小結(jié)
看到這里,我們可以知道四個(gè)全局函數(shù)的作用和相應(yīng)內(nèi)存的改變了
這些全局函數(shù)只是將值由基本類型變成了對(duì)象而已
公用屬性(原型)
所有對(duì)象都有 toString 和 valueOf 屬性苦始,那么我們是否有必要給每個(gè)對(duì)象一個(gè) toString 和 valueOf 呢寞钥?
JS 的做法是把 toString 和 valueOf 放在一個(gè)對(duì)象里(暫且叫做公用屬性組成的對(duì)象)
然后讓每一個(gè)對(duì)象的 __proto__
存儲(chǔ)這個(gè)公用屬性組成的對(duì)象的地址。
-
這里可以看圖來(lái)理解
在看這張圖前陌选,我們先考慮一下瀏覽器的垃圾回收機(jī)制理郑,垃圾回收會(huì)回收沒(méi)有被引用的對(duì)象。
這些全局對(duì)象如果不被引用的話咨油,就會(huì)被瀏覽器回收掉您炉,如何避免這些全局屬性被回收掉呢?
瀏覽器在打開(kāi)的時(shí)候役电,就會(huì)創(chuàng)建一個(gè)名為window
的全局屬性赚爵,這個(gè)全局屬性包含了所有全局函數(shù)的地址值。
這些地址又引用了該函數(shù)特有的公共屬性(對(duì)象)法瑟,每個(gè)函數(shù)特有的公共屬性(對(duì)象)又用_prote_
來(lái)儲(chǔ)存Object
對(duì)象的地址
-
舉個(gè)例子
n.toString()
流程是這樣的
1.瀏覽器先看n
是不是對(duì)象冀膝,不是做臨時(shí)轉(zhuǎn)換。
2.是的話就先去看看n
對(duì)應(yīng)的函數(shù)公共類型里找有沒(méi)有toString()
這個(gè)操作符
3.如果沒(méi)有霎挟,就進(jìn)入_prote_
對(duì)應(yīng)的公共屬性里找有沒(méi)有toString()
操作符
4.有的話窝剖,就調(diào)用這個(gè)toString()
這樣的,形成的穿過(guò)多個(gè)節(jié)點(diǎn)的流程酥夭,就叫原型鏈
-
內(nèi)存圖理解
var o1 = new Number(8)
var o2 = 8
o1 === o2 // false
o1.toString === o2.toString // true
因?yàn)樗麄冋{(diào)用的方法是一樣的
他們的數(shù)據(jù)類型是不一樣的赐纱,但是他們調(diào)用的共同屬性的方法(對(duì)象)是一樣的
重要公式
由此,我們可以得出一個(gè)公式熬北,結(jié)合原型解釋圖理解
var 對(duì)象 = new 函數(shù)()
對(duì)象.__proto__ === 對(duì)象的構(gòu)造函數(shù).prototype
由這個(gè)公式疙描,我們可以再推論
var number = new Number()
number.__proto__ = Number.prototype
Number.__proto__ = Function.prototype // 因?yàn)?Number 是 Function 的實(shí)例
var object = new Object()
object.__proto__ = Object.prototype
Object.__proto__ = Function.prototype // 因?yàn)?Object 是 Function 的實(shí)例
var function = new Function()
function.__proto__ = Function.prototype
Function.__proto__ == Function.prototye // 因?yàn)?Function 是 Function 的實(shí)例!
這個(gè)公式如果你能讀懂的話讶隐,你也就懂JS里的對(duì)象到底是什么了