全局對(duì)象
在ECMA Script 標(biāo)準(zhǔn)中,全局對(duì)象叫做 global, 全局對(duì)象不一定是 window,但在瀏覽器(早于ES)環(huán)境中,默認(rèn)的全局對(duì)象就是 window。
global.parseInt
global.parseFloat
windows
實(shí)際是一個(gè)哈希表,有許多屬性,我們稱為全局變量。
全局變量
常用全局變量舉例,詳細(xì)使用可查看MDN,實(shí)際應(yīng)用中可以省略 window,比如 window.alert() 可以直接寫(xiě)成 alert()。
| ECAM Script 規(guī)定 | 私有 (chrome/Firefox) |
|---|---|
global.parseInt() |
window.alert (彈框提示) |
global.parseFloat() |
window.prompt(用戶填寫(xiě)) |
global.Number() |
window.confirm(確認(rèn)) |
global.String() |
window.console.log |
global.Boolean() |
window.console.dir |
global.Object() |
window.document(文檔,DOM,W3C規(guī)定) |
global.Symbol() |
window.document.createElement |
global.setTimeout(function(){},time) |
window.document.getElementById |
window.history(瀏覽器,BOM) |
ECMA規(guī)定里的幾個(gè)重要函數(shù)/對(duì)象
Number()
-
基本類(lèi)型的Number
var n1 = Number('1') -
用
new創(chuàng)建的實(shí)例對(duì)象var n2 = new Number(1)
內(nèi)存圖
變量 n1 :
- stack棧內(nèi)存:1
- heap堆內(nèi)存:/
變量 n2:
stack棧內(nèi)存:Address 44
-
heap堆內(nèi)存:
Address 44: // A hash // Number {1} // -------------------------- // __proto__: Number // [[PrimitiveValue]]: 1 // -------------------------- // 相關(guān)屬性舉例: n2.toString() // "1" n2.ValueOf() // 1 n2.toExponential() // 1e+0 n2.toFixed(2) // 1.000
然而在Java Script中,我們沒(méi)必要使用第二種方式申明對(duì)象,盡管 n1 只是一個(gè)簡(jiǎn)單類(lèi)型的數(shù)值,不是一個(gè)對(duì)象,但 n2 所含的這些屬性,在Java Script中,我們也可以和 n2 一樣簡(jiǎn)單通過(guò)點(diǎn)運(yùn)算符(.)得到。
n1.toString()
n1.ValueOf()
n1.toExponential()
n1.toFixed(2)
// 實(shí)際上述屬性不存在,但是JS創(chuàng)建了一個(gè)臨時(shí)對(duì)象
// temp = new Number(n1)
// n1.toString() 實(shí)際上得的的結(jié)果是 temp.toString()的結(jié)果
// temp 是臨時(shí)存在的對(duì)象,用完就會(huì)被抹除
所以,在Java Script中,簡(jiǎn)單類(lèi)型的數(shù)據(jù)也可以添加不存在的屬性,然而實(shí)際是在給臨時(shí)創(chuàng)建的對(duì)象添加屬性,用完就被抹除,所以當(dāng)我們?cè)僭噲D讀取之前添加的屬性時(shí),原來(lái)的臨時(shí)對(duì)象已經(jīng)被抹除,然而在新的臨時(shí)對(duì)象中,該屬性不存在(可內(nèi)存圖輔助加深理解)
n1.balabala = ''
n1.balabala // undefined
String()
-
基本類(lèi)型的String
var s1 = String('qw ') -
用
new創(chuàng)建的實(shí)例對(duì)象var s2 = new String(s1) console.log(s2) // A hash // String {"qw "} // -------------------------- // __proto__: String // [[PrimitiveValue]]: "qw " // 0: "q" // 1: "w" // 2: " " // length: 3 // -------------------------- // 相關(guān)屬性舉例: s2.charAt(1) // "w",獲取某一個(gè)索引對(duì)應(yīng)的字符,等價(jià)于 s2[1] s2.charAt(3) // "" s2.charCodeAt(1) // 119,獲取某一個(gè)索引對(duì)應(yīng)的字符的編碼碼點(diǎn),十進(jìn)制Unicode s2.charCodeAt(3) // NaN s2.charCodeAt(1).toString(16) // 77,十六進(jìn)制的Unicode s2.trim() // "qw",去掉字符串內(nèi)空格 s2.concat("asd") // "qw asd",連接字符串 s2.slice(0,2) // "qw",從s2[0]開(kāi)始算的前兩個(gè)字符串 s2.replace(" ","e") // "qwe"," "替換為"e"的一個(gè)字符串 s2.substring(0,2) // "qw",以s2[0]我首字母,s2[2](不包括)結(jié)束的字符串 s2.includes(" ") // true,返回一個(gè)布爾值判斷是否" "在s2中
更多 String 屬性 可以google搜索 String MDN 學(xué)習(xí)。
Boolean()
-
基本類(lèi)型的Boolean
var b1 = true -
用
new創(chuàng)建的實(shí)例對(duì)象var b2 = new Boolean(true) console.log(b2) // A hash // Boolean {true} // -------------------------- // __proto__: Boolean // [[PrimitiveValue]]: true // -------------------------- // 相關(guān)屬性舉例: b2.valueOf() // true b2.toString() // "true" // 注意:b2是對(duì)象,不是falsy值
Object()
var o1 = {}
var o2 = new object({})
o1 === o2
// false
// o1 和 o2 沒(méi)有任何區(qū)別,但并不相等
// 通過(guò)內(nèi)存圖分析,事先申明的對(duì)象,在stack棧內(nèi)存中,兩者在堆內(nèi)存的地址不同
// 自然在heap堆內(nèi)存中,不同地址引用的空對(duì)象也不是同一個(gè)
| 變量 | Stack棧內(nèi)存 | Heap堆內(nèi)存 | |
|---|---|---|---|
o1 |
堆內(nèi)存地址1 | -------> | {} |
o2 |
堆內(nèi)存地址2 | -------> | {} |
往往事先聲明的對(duì)象一般都是不相等的,除非兩者把其中一個(gè)變量堆內(nèi)存的地址()賦給另外一個(gè)變量。
var o1 = {}
var o2 = o1
o1 === o2
// true
// o1 和 o2 都指向了堆內(nèi)存中同一個(gè)空對(duì)象
// o1的堆內(nèi)存地址賦值給了o2
// 賦值操作后,兩者保存了同一個(gè)堆內(nèi)存對(duì)象地址
// 注意:所以改變?nèi)魏我粋€(gè)變量都會(huì)互相影響,除非對(duì)象地址發(fā)生變化
o2.name = 'aaa'
console.log(o2) // {name: 1}
console.log(o1) // {name: 1}
JavaScript 原型鏈
我們從上述介紹的幾個(gè)函數(shù)對(duì)象(Number(),String()等)中發(fā)現(xiàn) ,這實(shí)例對(duì)象都有一些共有屬性,比如 toString(),valueOf() 等等。如果把這些屬性都當(dāng)作對(duì)象的私有屬性,給每個(gè)對(duì)象單獨(dú)存這些共有的屬性,顯然是十分浪費(fèi)內(nèi)存的。JS的做法是,每一個(gè)實(shí)例對(duì)象都有一個(gè)私有的屬性(__proto__)來(lái)表示這些共有的屬性,但并不直接存這些共有的屬性,而是指向它的構(gòu)造函數(shù)的原型對(duì)像(prototype)。
舉例:
var n1 = new Number()
var n2 = new Number()
n1 === n2 // false
n1.toString === n2.toString // true
n1.__proto__ === n2.__proto__ // true
n1.__proto__ === Number.prototype // true
// n1,n2都指向一個(gè)原型對(duì)象 Number.prototype
同時(shí),我們也注意到了除了Object對(duì)象之外,比如Number對(duì)象,它的原型對(duì)象(Number.prototype)也有一個(gè)自己的原型對(duì)象。
Number.prototype.__proto__ === Object.prototype // true
Object.prototype.__proto__ // null
Number對(duì)象的原型對(duì)象是一個(gè)Object對(duì)象,Object對(duì)象的原型對(duì)象是null。
延伸開(kāi)來(lái),每一個(gè)實(shí)例對(duì)象都有一個(gè)__proto__指向它的構(gòu)造函數(shù)的原型對(duì)象(prototype),然后其原型對(duì)象也有一個(gè)自己的原型對(duì)象,這樣層層往上直到Object的原型對(duì)象為null,null沒(méi)有原型對(duì)象,并且我們稱其為原型鏈的最后環(huán)節(jié)。
通過(guò)上文對(duì) 幾個(gè)函數(shù)/對(duì)象的了解 (Number,String,Boolean)我們可以發(fā)現(xiàn),這些對(duì)象都有他們獨(dú)特的屬性。也有一些他們共同擁有的屬性(Object的共有屬性)。上面,我們已經(jīng)分析了Number對(duì)象的原型鏈,可以看到Number對(duì)象的原型對(duì)象是Number.prototype,里面存了Number對(duì)象獨(dú)有的共有屬性。
n1.__proto__ === Number.prototype // true
Number對(duì)象的原型對(duì)象的原型對(duì)象是Object.prototype,里面存了Object對(duì)象普遍有的共有屬性。
n1.__proto__.__proto__ === Object.prototype // true
當(dāng)JS需要調(diào)用某個(gè)對(duì)象的屬性時(shí),它不單單在該對(duì)象上搜尋,同時(shí)也會(huì)搜尋它的原型以及原型的原型,層層往上直到找到或者搜到原型鏈的頂點(diǎn),所以我們才能直接調(diào)用Number對(duì)象的toFixed (Number.prototype中)和toString屬性(Object.prototype中)
區(qū)分 __proto__ 和prototype
簡(jiǎn)單來(lái)說(shuō)__proto__總是跟在一個(gè)對(duì)象后面,它是用來(lái)表示指向這個(gè)對(duì)象的原型,而prototype,我們可以發(fā)現(xiàn)它總是跟在一個(gè)構(gòu)造函數(shù)的后面,prototype是自帶在瀏覽器中的,即便不寫(xiě)任何代碼,prototype也是存在的,且無(wú)法修改。
構(gòu)造函數(shù)(constructor)
構(gòu)造函數(shù)主要有以下幾個(gè)特點(diǎn)
- 首字母大寫(xiě)
- 用
new來(lái)調(diào)用生成實(shí)例對(duì)象 - 函數(shù)內(nèi)部使用
this對(duì)象來(lái)指向要生成的實(shí)例對(duì)象
下表概括了JS中數(shù)據(jù)類(lèi)型的構(gòu)造函數(shù)
| 數(shù)據(jù)類(lèi)型 | 構(gòu)造函數(shù) |
|---|---|
| 數(shù)值 | Number |
| 字符串 | String |
| 布爾值 | Boolean |
| null | 無(wú) |
| undefined | 無(wú) |
| 符號(hào) | 無(wú) |
| 函數(shù)(對(duì)象) | Function |
| 數(shù)組(對(duì)象) | Array |
| 普通對(duì)象 | Object |
結(jié)合這些,我們就能更清晰地解釋原型鏈。
推論
舉例:
var s = new String()
s.__proto__ === String.prototype // true
上述例子中,被構(gòu)造函數(shù)String創(chuàng)造的實(shí)例對(duì)象s的__proto__指向String的prototype屬性。
String.prototype 就表示String的原型對(duì)象。
延伸開(kāi)來(lái),被構(gòu)造函數(shù)Func創(chuàng)造的實(shí)例對(duì)象func的__proto__指向Func的prototype屬性。
Func.prototype 就表示Func的原型對(duì)象,也就是
var func = new Func()
func.__proto__ === Func.prototype // true
延伸1
同時(shí)我們注意到構(gòu)造函數(shù)Func的原型對(duì)象 Func.prototype本身也是一個(gè)Object(對(duì)于Number,String等),所以當(dāng)我們把它當(dāng)做構(gòu)造函數(shù)Object的一個(gè)示例對(duì)象,我們可以得到:
舉例:
Number.prototype.__proto__ === Object.prototype // true
Function.prototype.__proto__ === Object.prototype // true
這個(gè)結(jié)果也就解釋了上文中為何Number對(duì)像的原型對(duì)象的__proto__指向了Object的prototype屬性。
延伸2
函數(shù)對(duì)象的構(gòu)造函數(shù)是Function,而構(gòu)造函數(shù)比如Number都是Function的實(shí)例對(duì)象。所以我們可以得到以下結(jié)果:
Number.__proto__ === Function.prototype // true
String.__proto__ === Function.prototype // true
Object.__proto__ === Function.prototype // true
Boolean.__proto__ === Function.prototype // true
Function.__proto__ === Function.prototype // true
// 在這,我們可以把Function函數(shù)本身也看成被其本身創(chuàng)造的一個(gè)實(shí)例對(duì)象
注意
我們要注意的是,Object的原型對(duì)象的__proto__指向的是null而不是Object.prototype
Object.prototype.__proto__ === null // true