《JavaScript面向?qū)ο缶烽喿x記錄
1. 原始類型、引用類型
原始類型(boolean、string、number、null、undefined)的變量直接保存原始值;
引用類型的變量不在變量中直接保存對(duì)象,而是保存指向內(nèi)存中實(shí)際對(duì)象所在位置的指針/引用;引用值(對(duì)象)是引用類型的實(shí)例;
把一個(gè)對(duì)象賦值給變量時(shí),實(shí)際是賦值給這個(gè)變量一個(gè)指針。
null空類型只有一個(gè)值:null;
undefined未定義類型只有一個(gè)值:undefined
typeof null == 'object' :可以認(rèn)為?null
?是一個(gè)空的對(duì)象指針,所以結(jié)果為"object";
判斷一個(gè)值是否為空類型(null)的最佳方式是直接和?null
?比較(val===null)
對(duì)象是屬性的無序列表。屬性包含鍵(始終是字符串)和值。如果一個(gè)屬性的值是函數(shù),它就被稱為方法;
對(duì)象引用解除: obj=null;? // 賦值為null即可

內(nèi)建類型:Function、Object、Array、Date、RegExp、Error
可使用?new
?來實(shí)例化每一個(gè)內(nèi)建引用類型
字面量形式雖然沒有用new 實(shí)例化,但是js引擎背后做的事情確是一樣的
typeof能返回的類型:boolean、string、number、undefined、object、function
instanceof能鑒別繼承類型:obj instanceof Object

原始封裝類型:Boolean、String、Number;(為了讓原始類型看上去更像引用類型)
當(dāng)讀取原始封裝類型變量值時(shí),原始封裝類型在背后自動(dòng)創(chuàng)建并隨后銷毀:
雖然原始封裝類型會(huì)被自動(dòng)創(chuàng)建,在這些值上進(jìn)行?instanceof
?檢查對(duì)應(yīng)類型的返回值卻是?false
。 這是因?yàn)?strong>臨時(shí)對(duì)象僅在值被讀取時(shí)創(chuàng)建。instanceof
?操作符并沒有真的讀取任何東西,也就沒有臨時(shí)對(duì)象的創(chuàng)建。
也可以手動(dòng)創(chuàng)建原始封裝類型。
注意:手動(dòng)創(chuàng)建原始封裝類型和使用原始值是有區(qū)別的。所以盡量避免手動(dòng)創(chuàng)建原始封裝類型。
2. 函數(shù)
函數(shù)也是對(duì)象,使函數(shù)不同于其它對(duì)象的決定性特點(diǎn)是函數(shù)存在一個(gè)被稱為?[[Call]]
?的內(nèi)部屬性。內(nèi)部屬性無法通過代碼訪問而是定義了代碼執(zhí)行時(shí)的行為。ECMAScript為JavaScript的對(duì)象定義了多種內(nèi)部屬性,這些內(nèi)部屬性都用雙重中括號(hào)來標(biāo)注。
[[Call]] 屬性是函數(shù)獨(dú)有的,表明該對(duì)象可以被執(zhí)行。由于僅函數(shù)擁有該屬性,ECMAScript 定義 typeof 操作符對(duì)任何具有 [[Call]] 屬性的對(duì)象返回 "function"。過去因某些瀏覽器曾在正則表達(dá)式中包含?[[Call]]
?屬性,導(dǎo)致正則表達(dá)式被錯(cuò)誤鑒別為函數(shù)。
函數(shù)聲明和函數(shù)表達(dá)式的一個(gè)重要區(qū)別是:函數(shù)聲明會(huì)被提升至上下文(要么是該函數(shù)被聲明時(shí)所在的函數(shù)范圍,要么是全局范圍)的頂部。
函數(shù)參數(shù)保存在類數(shù)組對(duì)象?arguments
?(Array.isArray(arguments)
?返回?false
)中??梢越邮杖我鈹?shù)量的參數(shù)。 函數(shù)的?length
?屬性表明其期望的參數(shù)個(gè)數(shù)。
可以像使用對(duì)象一樣使用函數(shù)(因?yàn)楹瘮?shù)本來就是對(duì)象,F(xiàn)unction 構(gòu)造函數(shù)更加容易說明)。
定義多個(gè)同名的函數(shù)時(shí),只有最后的定義有效,之前的函數(shù)聲明被完全刪除(函數(shù)也是對(duì)象,變量只是存指針)。

對(duì)象某個(gè)屬性的值是函數(shù),該函數(shù)就稱為方法;
所有的函數(shù)作用域內(nèi)都有一個(gè)?this
?對(duì)象代表調(diào)用該函數(shù)的對(duì)象。在全局作用域中,this
?代表全局對(duì)象(瀏覽器里的 window)。當(dāng)一個(gè)函數(shù)作為對(duì)象的方法調(diào)用時(shí),默認(rèn)?this
?的值等于該對(duì)象。?this在函數(shù)調(diào)用時(shí)才被設(shè)置。
bind
?是 ECMAScript 5 新增的,它會(huì)創(chuàng)建一個(gè)新函數(shù)返回。其參數(shù)與?call
?類似,而且其所有參數(shù)代表需要被永久設(shè)置在新函數(shù)中的命名參數(shù)(綁定了的參數(shù)(沒綁定的參數(shù)依然可以傳入),就算調(diào)用時(shí)再傳入其它參數(shù),也不會(huì)影響這些綁定的參數(shù))。
3. 對(duì)象
對(duì)象是屬性的無序集合;
在 Chrome 中,對(duì)象屬性會(huì)按 ASCII 表排序,而不是定義時(shí)的順序
判斷屬性是否存在的方法是使用?in
?操作符。?in
?操作符會(huì)檢查自有屬性和原型屬性。
所有的對(duì)象都擁有的?hasOwnProperty
()
?方法(其實(shí)是繼承自?Object.prototype
?原型對(duì)象的),該方法在給定的屬性存在且為自有屬性時(shí)返回?true
。
刪除屬性:delete obj.xxx
MDN:delete 操作符不能刪除的屬性有:
①顯式聲明的全局變量不能被刪除,該屬性不可配置(not configurable);?
②內(nèi)置對(duì)象的內(nèi)置屬性不能被刪除;?
③不能刪除一個(gè)對(duì)象從原型繼承而來的屬性(不過你可以從原型上直接刪掉它)。
所有人為添加的屬性默認(rèn)都是可枚舉的。可枚舉的內(nèi)部特征?[[Enumerable]]
?都被設(shè)置為?true。對(duì)象的大部分原生方法的?
[[Enumerable]]
?特征都被設(shè)置為?false
??捎?propertyIsEnumerable
()
方法檢查一個(gè)屬性是否為可枚舉的。arr.propertyIsEnumerable("length")

屬性分為 數(shù)據(jù)屬性 和 訪問器屬性 兩種類型:數(shù)據(jù)屬性包含一個(gè)值,訪問器屬性定義了當(dāng)一個(gè)屬性被讀取(getter)和被寫入(setter)時(shí)調(diào)用的函數(shù)。
數(shù)據(jù)屬性和訪問器屬性均由以下兩個(gè)屬性特制:?
[[Enumerable]]
?決定了是否可以遍歷該屬性;
[[Configurable]]
?決定了該屬性是否可配置。數(shù)據(jù)屬性額外擁有兩個(gè)訪問器屬性不具備的特征:
[[Value]]
?包含屬性的值(哪怕是函數(shù))。
[[Writable]]
?布爾值,指示該屬性是否可寫入。訪問器屬性額外擁有兩個(gè)特征:
[[Get]]
?和?[[Set]]
,內(nèi)含?getter
?和?setter
?函數(shù)。
所有人為定義的屬性默認(rèn)都是可枚舉、可配置的。
可以用 Object.defineProperty() 方法改變屬性特征:
數(shù)據(jù)屬性額外擁有兩個(gè)訪問器屬性不具備的特征:
[[Value]]
?包含屬性的值(哪怕是函數(shù))。
[[Writable]]
?布爾值,指示該屬性是否可寫入。
所有屬性默認(rèn)都是可寫的。
在?Object.defineProperty()
?被調(diào)用時(shí):
a. 如果屬性本來就有,則會(huì)按照新定義屬性特征值去覆蓋默認(rèn)屬性特征(enumberable
、configurable
?和?writable
?均為?true
),只有你指定的特征會(huì)被改變;
b. 定義新的屬性時(shí),沒有為所有的特征值指定一個(gè)值,則所有布爾值的特征值會(huì)被默認(rèn)設(shè)置為?false
。即不可枚舉、不可配置、不可寫的。?
訪問器屬性額外擁有兩個(gè)特征:
[[Get]]
?和?[[Set]]
,內(nèi)含?getter
?和?setter
?函數(shù)。
Object.defineProperties() 方法可以定義任意數(shù)量的屬性,甚至可以同時(shí)改變已有的屬性并創(chuàng)建新屬性。
獲取屬性特征 Object.getOwnPropertyDescriptor()
?:
接受兩個(gè)參數(shù):對(duì)象和屬性名。如果屬性存在,它會(huì)返回一個(gè)屬性描述對(duì)象,內(nèi)涵?4
?個(gè)屬性:configurable
?和?enumerable
,另外兩個(gè)屬性則根據(jù)屬性類型決定。

對(duì)象和屬性一樣具有指導(dǎo)其行為的內(nèi)部特性:
?[[Extensible]]
?是布爾值,指明該對(duì)象本身是否可以被修改。默認(rèn)是?true
。當(dāng)值為?false
?時(shí),就能禁止新屬性的添加。
Object.preventExtensions()
?:創(chuàng)建一個(gè)不可擴(kuò)展的對(duì)象(即不能添加新屬性);
Object.isExtensible()
?:檢查?[[Extensible]]
?的值。
Object.seal():創(chuàng)建一個(gè)不可擴(kuò)展不可配置只能讀寫屬性的對(duì)象;
Object.isSealed()
?:判斷一個(gè)對(duì)象是否被封印。
Object.freeze()
?:創(chuàng)建一個(gè)數(shù)據(jù)屬性都為只讀的被封印對(duì)象(不能添加或刪除屬性,不能修改屬性類型,也不能寫入任何數(shù)據(jù)屬性);
Object.isFrozen()
?:判斷對(duì)象是否被凍結(jié)。
4. 構(gòu)造函數(shù)和原型對(duì)象
每個(gè)對(duì)象都有隱式的__proto__ ([[prototype]])屬性,值為創(chuàng)建這個(gè)對(duì)象的構(gòu)造函數(shù)的原型對(duì)象;幾乎所有的函數(shù)(除了一些內(nèi)建函數(shù))都有prototype屬性,值為這個(gè)構(gòu)造函數(shù)的原型對(duì)象。所有創(chuàng)建的對(duì)象實(shí)例(同一構(gòu)造函數(shù),當(dāng)然,可能訪問上層的原型對(duì)象)共享該原型對(duì)象,且這些對(duì)象實(shí)例可以訪問原型對(duì)象的屬性。
構(gòu)造函數(shù)的原型對(duì)象有個(gè) constructor 屬性,指向這個(gè)構(gòu)造函數(shù)。

構(gòu)造函數(shù)屬性可以被覆蓋(person.constructor = "")。
可借助?prototype
?原型對(duì)象共享同一個(gè)方法會(huì)更高效:
鑒別一個(gè)原型屬性(通過繼承來的屬性):

當(dāng)讀取一個(gè)對(duì)象 obj 的屬性時(shí),JavaScript 引擎首先在該對(duì)象的自有屬性查找屬性名。如果找到則返回;否則會(huì)搜索 obj 對(duì)象的 [[Prototype]] 中的屬性,找到則返回,找不到則返回undefined;(如果查找過程還沒有到 Object.__proto__??則繼續(xù)搜索 obj.__proto_.__proto__?( obj的原型對(duì)象的原型對(duì)象?)中的屬性,一直到 Object.__proto__為止。 Object.__proto__ === null)
Object.getPrototypeOf() 方法可讀取 [[Prototype]] 屬性的值;
isPrototypeOf() 方法會(huì)檢查某個(gè)對(duì)象是否是另一個(gè)對(duì)象的原型對(duì)象:
直接改變構(gòu)造函數(shù)的原型對(duì)象:
這種方式有一種副作用:
因?yàn)樵蛯?duì)象上具有一個(gè)?constructor
?屬性,這是其他對(duì)象實(shí)例所沒有的。當(dāng)一個(gè)函數(shù)被創(chuàng)建時(shí),它的?prototype
?屬性也會(huì)被創(chuàng)建,且該原型對(duì)象的?constructor
?屬性指向該函數(shù)。當(dāng)使用字面量時(shí),因沒顯式設(shè)置原型對(duì)象的?constructor
?屬性,因此其?constructor
?屬性是指向?Object
?的。?
因此,當(dāng)通過此方式設(shè)置原型對(duì)象時(shí),可手動(dòng)設(shè)置?constructor
?屬性:
因?yàn)槊總€(gè)對(duì)象的?[[Prototype]]
?只是一個(gè)指向原型對(duì)象的指針,原型對(duì)象的改動(dòng)會(huì)立刻反映到所有引用它的對(duì)象。 當(dāng)對(duì)一個(gè)對(duì)象使用封印?Object.seal()
?或凍結(jié)?Object.freeze()
?時(shí),完全是在操作對(duì)象的自有屬性,仍然可以通過在原型對(duì)象上添加屬性來擴(kuò)展這些對(duì)象實(shí)例。
內(nèi)建對(duì)象的原型對(duì)象也能修改:
5. 繼承
JavaScript中的繼承是通過原型鏈實(shí)現(xiàn)的。對(duì)象實(shí)例繼承了原型對(duì)象的屬性,而原型對(duì)象作為對(duì)象也有自己的原型對(duì)象,一直到Object.prototype為止。所有對(duì)象都繼承自?Object.prototype
。任何以對(duì)象字面量形式定義的對(duì)象,其?[[Prototype]]
?的值都被設(shè)為?Object.prototype
,這意味著它繼承?Object.prototype
?的屬性。
Object.create() 方法用指定的原型對(duì)象創(chuàng)建一個(gè)對(duì)象:
第一個(gè)是新對(duì)象的?[[Prototype]]
?所指向的對(duì)象;第二個(gè)參數(shù)是可選的一個(gè)屬性描述對(duì)象,其格式與?Object.definePrototies()
一樣。
也可以用?Object.create()
創(chuàng)建一個(gè)?[[Prototype]]
?為?null
?的對(duì)象:
var obj = Object.create(null);
console.log("toString" in obj); // false
該對(duì)象是一個(gè)沒有原型對(duì)象鏈的對(duì)象,即是一個(gè)沒有預(yù)定義屬性的白板。
構(gòu)造函數(shù)都有prototype屬性,實(shí)質(zhì)為: