對象
基本形式
- 聲明形式(對象字面量)
var obj = {
name: 'object',
age: 25
}
- 構(gòu)造形式
var obj = new Object({name: 'object', age: 25})
對象類型
對象是JavaScript的基礎(chǔ)铛碑。在JavaScript中一共有六種主要類型聂渊。
- string
- number
- boolean
- undefined
- null
- object
簡單基本類型(string衰伯、boolean、number浅役、null和undefined)本身并不是對象漱受。typeof null 返回 'object' 是語言本身的一個(gè)bug。JavaScript沒打算修復(fù)這個(gè)bug荞彼,因?yàn)樾迯?fù)了這個(gè)bug會(huì)引發(fā)其他更多的bug冈敛。
原理是這樣的, 不同的對象在底層都表示為二進(jìn)制卿泽, 在JavaScript中二進(jìn)制前三位都為0的話會(huì)被判斷為object類型莺债,null的二進(jìn)制表示是全0,自然前三位也是0签夭,所以執(zhí)行typeof時(shí)會(huì)返回“object”齐邦。
內(nèi)置對象
- String
- Number
- Boolean
- Array
- Function
- Object
- Date
- RegExp
- Error
這些內(nèi)置對象從表現(xiàn)形式來說很像其他語言中的類型(type)或者類(class),比如Java中的String類第租。
但是在JavaScript中措拇, 它們實(shí)際上只是一些內(nèi)置函數(shù)。 這些內(nèi)置函數(shù)可以當(dāng)作構(gòu)造函數(shù)(由new產(chǎn)生的函數(shù)調(diào)用)來使用慎宾,從而可以構(gòu)造一個(gè)對應(yīng)子類型的新對象丐吓。
對象內(nèi)容
對象的內(nèi)容是由一些存儲(chǔ)在特定命名位置的( 任意類型的)值組成的浅悉,我們稱之為屬性。
需要強(qiáng)調(diào)的一點(diǎn)是券犁, 當(dāng)我們說“ 內(nèi)容”時(shí)术健, 似乎在暗示這些值實(shí)際上被存儲(chǔ)在對象內(nèi)部,但是這只是它的表現(xiàn)形式粘衬。 在引擎內(nèi)部荞估, 這些值的存儲(chǔ)方式是多種多樣的, 一般并不會(huì)存在對象容器內(nèi)部稚新。 存儲(chǔ)在對象容器內(nèi)部的是這些屬性的名稱勘伺, 它們就像指針( 從技術(shù)角度來說就是引用)一樣,指向這些值真正的存儲(chǔ)位置褂删。
訪問對象的屬性:
var obj = {
name: 'object',
age: 25
}
obj.name
obj['name']
屬性和方法:
如果訪問的對象屬性是一個(gè)函數(shù)飞醉, 有些開發(fā)者喜歡使用不一樣的叫法以作區(qū)分。 由于函數(shù)很容易被認(rèn)為是屬于某個(gè)對象屯阀, 在其他語言中缅帘, 屬于對象( 也被稱為“ 類”)的函數(shù)通常被稱為“方法”,因此把“屬性訪問”說成是“方法訪問”也就不奇怪了蹲盘。
從技術(shù)角度來說股毫, 函數(shù)永遠(yuǎn)不會(huì)“ 屬于”一個(gè)對象, 所以把對象內(nèi)部引用的函數(shù)稱為“ 方法”似乎有點(diǎn)不妥召衔。
確實(shí)铃诬, 有些函數(shù)具有this引用, 有時(shí)候這些this確實(shí)會(huì)指向調(diào)用位置的對象引用苍凛。 但是這種用法從本質(zhì)上來說并沒有把一個(gè)函數(shù)變成一個(gè)“ 方法”趣席,因?yàn)閠his是在運(yùn)行時(shí)根據(jù)調(diào)用位置動(dòng)態(tài)綁定的,所以函數(shù)和對象的關(guān)系最多也只能說是間接關(guān)系醇蝴。
function foo() {
return this.value
}
let anotherFoo = foo
let obj = {
ownFoo: anotherFoo
}
console.log(foo === anotherFoo)
console.log(anotherFoo === obj.ownFoo)
// 這里的 foo anotherFoo obj.ownFoo 指向的都是同一個(gè)函數(shù) function () { return this.value }
復(fù)制對象
如何復(fù)制一個(gè)對象:
// 淺復(fù)制
let obj = {
name: 'clone object',
list: [1, 2, 3, 4, 5]
}
let anotherObj = obj
/**
* 對于 obj 中的 name 屬性宣肚,anotherObj 會(huì)復(fù)制一份
* 而對于 list 屬性,因?yàn)樗且弥涤扑ǎ?another 只是取得了對它的引用霉涨,實(shí)際上跟 obj 的list屬性指向的是同一個(gè)值
*/
obj.list.push(6)
anotherObj.list // [1, 2, 3, 4, 5, 6]
ES6 通過 Object.assign() 實(shí)現(xiàn)了淺復(fù)制
Object.assign(targetObject, {}, {}, ...)
- 第一個(gè)參數(shù)是目標(biāo)對象
- 后面可以接多個(gè)參數(shù)對象
對于JSON安全( 也就是說可以被序列化為一個(gè)JSON字符串并且可以根據(jù)這個(gè)字符串解析出一個(gè)結(jié)構(gòu)和值完全一樣的對象)的對象來說,有一種巧妙的復(fù)制方法:
let anotherObj = JSON.parse(JSON.stringify())
JSON不安全值:
- undefined惭适、 function笙瑟、 symbol( ES6+)和包含循環(huán)引用(對象之間相互引用,形成一個(gè)無限循環(huán))的對象都不符合 JSON結(jié)構(gòu)標(biāo)準(zhǔn)癞志,支持 JSON 的語言無法處理它們往枷。
- JSON.stringify(..) 在對象中遇到 undefined、 function 和 symbol 時(shí)會(huì)自動(dòng)將其忽略,在數(shù)組中則會(huì)返回 null(以保證單元位置不變)错洁。
let foo = function () {}
let bar = JSON.parse(JSON.stringify(foo))
/**
* SyntaxError: Unexpected token u in JSON at position 0
* JSON.stringify(foo) 返回了 undefined
* JSON.parse(undefined) 自然就報(bào)錯(cuò)了
*/
如何實(shí)現(xiàn)一個(gè)復(fù)制的通用方法:
function deepClone(target, source) {}
屬性描述符:writable秉宿、enumerable、configurable
let obj = {}
obj.defineProperty(obj, 'name', {
value: 'propertyDescriptor',
// 是否可以更改該值屯碴,通過obj.name 的方法修改值描睦,設(shè)為false則不可修改
writable: false,
// 是否可以遍歷
enumerable: true,
/**
* 是否可配置,即是否可通過 obj.defineProperty 的方式重新配置
* 設(shè)為false窿锉,不僅不能修改酌摇,也不能刪除該屬性
*/
configurable: fasle,
})