1角撞、8種數(shù)據(jù)類型
number
bigint: 任意長度的整數(shù)
string
boolean
unll:空或不存在
undefined:未定義
object
symbol
2、typeof null == "object" // JavaScript 編程語言的設(shè)計錯誤
typeof function(){} == "function" // 函數(shù)被特殊對待
3谒所、創(chuàng)建對象的方法
構(gòu)造函數(shù):let user = new Obiect()
字面量: let user = {}
4沛申、屬性存在性測試,“in” 操作符
能夠被訪問任何屬性铁材。即使屬性不存在也不會報錯!
讀取不存在的屬性只會得到 undefined著觉。所以我們可以很容易地判斷一個屬性是否存在:
let user = {};alert( user.noSuchProperty === undefined ); // true 意思是沒有這個屬性
這里還有一個特別的,檢查屬性是否存在的操作符 "in"饼丘,key in object,in 的左邊必須是 屬性名葬毫。通常是一個帶引號的字符串。如果我們省略引號贴捡,就意味著左邊是一個變量,它應(yīng)該包含要判斷的實際屬性名屹逛。
let user = { name: "John", age: 30 };
alert( "age" in user ); // true,user.age 存在
alert( "blabla" in user ); // false罕模,user.blabla 不存在。
為何會有 in 運算符呢淑掌?與 undefined 進行比較來判斷還不夠嗎?
let obj = {? test: undefined};
alert( obj.test ); // 顯示 undefined抛腕,所以屬性不存在芋绸?
alert( "test" in obj ); // true摔敛,屬性存在!
這種情況很少發(fā)生马昙,因為通常情況下不應(yīng)該給對象賦值 undefined。我們通常會用 null 來表示未知的或者空的值行楞。因此,in 運算符是代碼中的特殊來賓敢伸。
5恒削、for...in循環(huán),遍歷對象
for (key in object) {? // 對此對象屬性中的每個鍵執(zhí)行的代碼}
let user = {? name: "John",? age: 30,? isAdmin: true};
for (let key in user) {? // keys? alert( key );
// name, age, isAdmin? // 屬性鍵的值? alert( user[key] ); // John, 30, true}
6钓丰、訪問屬性的方法&其它
點符號: obj.property。
方括號 obj["property"]携丁,方括號允許從變量中獲取鍵,例如 obj[varWithKey]
刪除屬性:delete obj.prop梦鉴。
檢查是否存在給定鍵的屬性:"key" in obj。
遍歷對象:for(let key in obj) 循環(huán)肥橙。
7、對象的引用和復(fù)制
與原始類型相比存筏,對象的根本區(qū)別之一是對象是通過引用被存儲和復(fù)制的,與原始類型相反string椭坚、number、boolean等始終以整體值得形式被復(fù)制得善茎;
賦值了對象的變量存儲的不是對象本身,而是該對象“在內(nèi)存中的地址”汁掠,換句話說就是對該對象的“引用”。
當(dāng)一個對象變量被復(fù)制 —— 引用則被復(fù)制考阱,而該對象并沒有被復(fù)制
let user = { name: 'John' }
let admin = user
user? ——> name <——? admin? 現(xiàn)在我們有了兩個變量鞠苟,它們保存的都是對同一個對象的引用;這里依然是只有一個對象当娱,現(xiàn)在有兩個引用它的變量,我們可以通過其中任何一個變量來訪問該對象并修改它的內(nèi)容跨细。
admin.name = 'pete'
console.log(user.name)? // pete
這就像我們有個帶著兩把鑰匙的柜子,并使其中一把鑰匙來打開它震叙,那么我們?nèi)绻笥昧硪话谚€匙打開,則也能看到更改媒楼。
8、通過引用來比較
僅當(dāng)兩個對象為同一對象時划址,兩者才相等
let a = {}
let b = a
console.log(a==b) // true
console.log(a===b) // true
這里a和b引用的都是同一個對象,所以它們相等夺颤;
let a = {}
let b = {}
console.log(a==b) // false
這里的a和b是兩個互相獨立的對象所以它們不相等;
9世澜、克隆與合并,Object.assign
如何拷貝一個對象變量會又創(chuàng)建一個對相同對象的引用宜狐。
let user = { name: 'lili', age: 48 }
let clone = {}
for (let key in user) {
? clone[key] = user[key]
}
// 現(xiàn)在 clone 是帶有相同內(nèi)容的完全獨立的對象
clone.name = 'mike'
console.log(user.name) // lili
下面使用Object.assign也能達到同樣的效果
let user = { name: "John" }
let permissions1 = { canView: true }
let permissions2 = { canEdit: true }
// 將 permissions1 和 permissions2 中的所有屬性都拷貝到 user 中Object.assign(user,permissions1,permissions2)
// 現(xiàn)在 user = { name: "John", canView: true, canEdit: true }
如果被拷貝的屬性的屬性名已經(jīng)存在蛇捌,那么它會被覆蓋:
let user = { name: "John" }
Object.assign(user, { name: "Pete" })
console.log(user.name) // 現(xiàn)在 user = { name: "Pete" }
我們也可以用 Object.assign 代替 for..in 循環(huán)來進行簡單克隆:
let user = {? name: "John",? age: 30}
let clone=Object.assign({},user)
10、深層克隆
let user = {? name: "John",? sizes: {? ? height: 182,? ? width: 50? }}
let clone = Object.assign({}, user)
console.log( user.sizes === clone.sizes ) // true
同一個對象user 和 clone 分享同一個 sizes,user.sizes.width++
// 通過其中一個改變屬性值
console.log(clone.sizes.width); // 51俭驮,能從另外一個看到變更的結(jié)果
為了解決此問題,我們應(yīng)該使用會檢查每個 user[key] 的值的克隆循環(huán)混萝,如果值是一個對象,那么也要復(fù)制它的結(jié)構(gòu)逸嘀。這就叫“深拷貝”。我們可以用遞歸來實現(xiàn)崭倘。或者不自己造輪子司光,使用現(xiàn)成的實現(xiàn),例如 JavaScript 庫 lodash 中的 _.cloneDeep(obj)残家。
11、總結(jié)
對象通過引用被賦值和拷貝坞淮。換句話說,一個變量存儲的不是“對象的值”碾盐,而是一個對值的“引用”(內(nèi)存地址)。因此毫玖,拷貝此類變量或?qū)⑵渥鳛楹瘮?shù)參數(shù)傳遞時,所拷貝的是引用付枫,而不是對象本身。
所有通過被拷貝的引用的操作(如添加阐滩、刪除屬性)都作用在同一個對象上。
為了創(chuàng)建“真正的拷貝”(一個克碌嗬啤),我們可以使用 Object.assign 來做所謂的“淺拷貝”(嵌套對象被通過引用進行拷貝)或者使用“深拷貝”函數(shù)装获,例如 _.cloneDeep(obj)。