JavaScript中的對(duì)象操作詳解
JavaScript中對(duì)象是數(shù)據(jù)和功能的集合,幾乎所有值都可以視為對(duì)象(除原始類型外),掌握對(duì)象的創(chuàng)建、屬性操作、遍歷及繼承等核心技能,是深入理解JavaScript的關(guān)鍵。
一、對(duì)象的創(chuàng)建方式
JavaScript提供了多種創(chuàng)建對(duì)象的方式,各有適用場(chǎng)景,選擇合適的方式能讓代碼更高效。
1.1 對(duì)象字面量(最常用)
對(duì)象字面量是創(chuàng)建對(duì)象最簡(jiǎn)潔的方式,用{}
包裹鍵值對(duì),鍵名可省略引號(hào)(符合標(biāo)識(shí)符規(guī)則時(shí))。
// 基礎(chǔ)語(yǔ)法 const user = { name: "張三", age: 25, isStudent: false, // 方法簡(jiǎn)寫(ES6+) greet() { console.log(`你好,我是${this.name}`); }, // 嵌套對(duì)象 address: { city: "北京", district: "海淀區(qū)" } }; // 調(diào)用屬性和方法 console.log(user.name); // "張三" user.greet(); // "你好,我是張三" console.log(user.address.city); // "北京"
特性:語(yǔ)法簡(jiǎn)潔,適合創(chuàng)建單個(gè)對(duì)象,無(wú)需定義構(gòu)造函數(shù),是日常開發(fā)的首選。
1.2 構(gòu)造函數(shù)與new
關(guān)鍵字
構(gòu)造函數(shù)用于創(chuàng)建多個(gè)結(jié)構(gòu)相同的對(duì)象,通過(guò)this
綁定屬性,new
關(guān)鍵字實(shí)例化對(duì)象。
// 定義構(gòu)造函數(shù)(首字母大寫,約定俗成) function Person(name, age) { // 實(shí)例屬性 this.name = name; this.age = age; // 實(shí)例方法(每次創(chuàng)建實(shí)例都會(huì)重復(fù)定義,不推薦) this.greet = function() { console.log(`我是${this.name}`); }; } // 原型方法(所有實(shí)例共享,推薦) Person.prototype.sayAge = function() { console.log(`我${this.age}歲`); }; // 實(shí)例化對(duì)象 const person1 = new Person("李四", 30); const person2 = new Person("王五", 28); console.log(person1.name); // "李四" person1.greet(); // "我是李四" person2.sayAge(); // "我28歲"
特性:適合創(chuàng)建多個(gè)同類型對(duì)象,通過(guò)原型(prototype
)共享方法可節(jié)省內(nèi)存;需注意忘記寫new
時(shí)this
會(huì)指向全局對(duì)象(嚴(yán)格模式下報(bào)錯(cuò))。
1.3 Object.create()方法
Object.create()
通過(guò)指定原型對(duì)象創(chuàng)建新對(duì)象,是實(shí)現(xiàn)繼承的靈活方式。
// 原型對(duì)象 const animal = { type: "動(dòng)物", eat() { console.log("進(jìn)食中"); } }; // 以animal為原型創(chuàng)建新對(duì)象 const cat = Object.create(animal); cat.name = "咪咪"; cat.meow = function() { console.log("喵喵叫"); }; console.log(cat.name); // "咪咪"(自身屬性) console.log(cat.type); // "動(dòng)物"(繼承自原型) cat.eat(); // "進(jìn)食中"(繼承的方法)
特性:直接指定原型,適合實(shí)現(xiàn)復(fù)雜繼承關(guān)系;創(chuàng)建的對(duì)象默認(rèn)無(wú)自身屬性,需手動(dòng)添加。
1.4 其他方式(ES6+)
ES6新增了class
語(yǔ)法糖(本質(zhì)還是構(gòu)造函數(shù))和對(duì)象擴(kuò)展運(yùn)算符,簡(jiǎn)化對(duì)象創(chuàng)建:
// 1. class語(yǔ)法(ES6+) class Car { constructor(brand) { this.brand = brand; } drive() { console.log(`${this.brand}在行駛`); } } const bmw = new Car("寶馬"); bmw.drive(); // "寶馬在行駛" // 2. 對(duì)象擴(kuò)展運(yùn)算符(復(fù)制對(duì)象) const obj1 = { a: 1 }; const obj2 = { ...obj1, b: 2 }; // 復(fù)制obj1并添加新屬性 console.log(obj2); // { a: 1, b: 2 }
二、對(duì)象屬性的操作方法
對(duì)象的核心是屬性(包括數(shù)據(jù)屬性和方法),掌握屬性的增刪改查是對(duì)象操作的基礎(chǔ)。
2.1 訪問(wèn)與修改屬性
屬性訪問(wèn)有兩種方式:點(diǎn)語(yǔ)法(.
)和方括號(hào)語(yǔ)法([]
),后者支持動(dòng)態(tài)屬性名。
const user = { name: "趙六", age: 22 }; // 1. 訪問(wèn)屬性 console.log(user.name); // "趙六"(點(diǎn)語(yǔ)法,屬性名固定) console.log(user["age"]); // 22(方括號(hào)語(yǔ)法,屬性名可動(dòng)態(tài)) // 2. 修改屬性 user.age = 23; user["name"] = "趙六六"; console.log(user); // { name: "趙六六", age: 23 } // 3. 動(dòng)態(tài)屬性名(ES6+) const propKey = "gender"; user[propKey] = "男"; // 等價(jià)于user.gender = "男" console.log(user); // { name: "趙六六", age: 23, gender: "男" }
注意:方括號(hào)中需用字符串或變量(變量值為字符串);屬性名若為數(shù)字會(huì)自動(dòng)轉(zhuǎn)為字符串(如obj[1]
等價(jià)于obj["1"]
)。
2.2 添加與刪除屬性
對(duì)象屬性可動(dòng)態(tài)添加,通過(guò)delete
關(guān)鍵字刪除。
const book = { title: "JavaScript入門" }; // 添加屬性 book.author = "張三"; book["price"] = 59; console.log(book); // { title: "JavaScript入門", author: "張三", price: 59 } // 刪除屬性 delete book.price; console.log(book.price); // undefined(屬性已刪除) console.log("price" in book); // false(檢查屬性是否存在)
特性:delete
僅刪除對(duì)象自身屬性,無(wú)法刪除繼承的屬性;刪除成功返回true
(即使屬性不存在),但不能刪除變量或函數(shù)。
2.3 檢查屬性是否存在
判斷屬性是否存在需區(qū)分“自身屬性”和“繼承屬性”,常用方法如下:
const obj = { a: 1 }; // 繼承自O(shè)bject.prototype的屬性 console.log(obj.toString); // 存在(繼承) // 1. in運(yùn)算符:檢查自身+繼承屬性 console.log("a" in obj); // true(自身屬性) console.log("toString" in obj); // true(繼承屬性) // 2. hasOwnProperty():僅檢查自身屬性 console.log(obj.hasOwnProperty("a")); // true console.log(obj.hasOwnProperty("toString")); // false(繼承屬性) // 3. 檢查屬性值是否為undefined(不可靠,因?qū)傩钥赡艽嬖诘禐閡ndefined) obj.b = undefined; console.log(obj.b === undefined); // true(但屬性b存在) console.log("b" in obj); // true(正確判斷)
最佳實(shí)踐:用hasOwnProperty()
檢查自身屬性,in
運(yùn)算符檢查是否可訪問(wèn)(包括繼承)。
三、對(duì)象的遍歷方法
遍歷對(duì)象的屬性是常見(jiàn)需求,不同方法適用于不同場(chǎng)景,需注意遍歷順序和屬性類型。
3.1 for...in循環(huán)
for...in
遍歷對(duì)象的可枚舉屬性(包括繼承的),適合簡(jiǎn)單遍歷。
const car = { brand: "奔馳", price: 300000 }; // 添加不可枚舉屬性 Object.defineProperty(car, "color", { value: "黑色", enumerable: false // 不可枚舉 }); // 遍歷可枚舉屬性(自身+繼承的可枚舉屬性) for (const key in car) { // 過(guò)濾繼承屬性 if (car.hasOwnProperty(key)) { console.log(`${key}: ${car[key]}`); } } // 輸出: // brand: 奔馳 // price: 300000
注意:
- 會(huì)遍歷繼承的可枚舉屬性(需用
hasOwnProperty()
過(guò)濾); - 遍歷順序:數(shù)字屬性按升序,字符串屬性按插入順序,符號(hào)屬性不遍歷。
3.2 Object.keys()與Object.values()
Object.keys()
返回對(duì)象自身可枚舉屬性的鍵名數(shù)組,Object.values()
返回值數(shù)組。
const user = { name: "孫七", age: 26, gender: "男" }; // 獲取鍵名數(shù)組 const keys = Object.keys(user); console.log(keys); // ["name", "age", "gender"] // 獲取值數(shù)組 const values = Object.values(user); console.log(values); // ["孫七", 26, "男"] // 遍歷鍵值對(duì) keys.forEach(key => { console.log(`${key}: ${user[key]}`); });
特性:僅包含自身可枚舉屬性,不包括繼承和不可枚舉屬性;返回?cái)?shù)組的順序與for...in
一致。
3.3 Object.entries()與Object.fromEntries()
Object.entries()
返回鍵值對(duì)數(shù)組,Object.fromEntries()
則將鍵值對(duì)數(shù)組轉(zhuǎn)為對(duì)象(互為逆操作)。
const obj = { a: 1, b: 2 }; // 轉(zhuǎn)為鍵值對(duì)數(shù)組 const entries = Object.entries(obj); console.log(entries); // [["a", 1], ["b", 2]] // 遍歷鍵值對(duì) entries.forEach(([key, value]) => { console.log(`${key}: ${value}`); }); // 鍵值對(duì)數(shù)組轉(zhuǎn)回對(duì)象 const newObj = Object.fromEntries(entries); console.log(newObj); // { a: 1, b: 2 }
應(yīng)用場(chǎng)景:結(jié)合數(shù)組方法處理對(duì)象,例如過(guò)濾屬性:
// 過(guò)濾值大于1的屬性 const filteredEntries = entries.filter(([key, value]) => value > 1); const filteredObj = Object.fromEntries(filteredEntries); // { b: 2 }
3.4 其他方法(獲取所有屬性)
Object.getOwnPropertyNames(obj)
:返回自身所有屬性(包括不可枚舉,不包括符號(hào)屬性);Object.getOwnPropertySymbols(obj)
:返回自身所有符號(hào)屬性;Reflect.ownKeys(obj)
:返回自身所有屬性(包括不可枚舉和符號(hào)屬性),最全面。
const sym = Symbol("id"); const obj = { a: 1 }; obj[sym] = 100; Object.defineProperty(obj, "b", { value: 2, enumerable: false }); console.log(Object.getOwnPropertyNames(obj)); // ["a", "b"](不含符號(hào)屬性) console.log(Object.getOwnPropertySymbols(obj)); // [Symbol(id)] console.log(Reflect.ownKeys(obj)); // ["a", "b", Symbol(id)](所有自身屬性)
四、對(duì)象的高級(jí)操作
除基礎(chǔ)操作外,對(duì)象的復(fù)制、合并、屬性描述符等高級(jí)功能在復(fù)雜場(chǎng)景中非常實(shí)用。
4.1 對(duì)象的復(fù)制(淺拷貝與深拷貝)
對(duì)象是引用類型,直接賦值會(huì)導(dǎo)致共享內(nèi)存,需通過(guò)方法實(shí)現(xiàn)拷貝。
4.1.1 淺拷貝(僅復(fù)制頂層屬性)
const obj = { a: 1, b: { c: 2 } }; // 1. 對(duì)象擴(kuò)展運(yùn)算符 const copy1 = { ...obj }; // 2. Object.assign() const copy2 = Object.assign({}, obj); // 淺拷貝的問(wèn)題:嵌套對(duì)象仍共享引用 copy1.b.c = 3; console.log(obj.b.c); // 3(原對(duì)象被修改)
4.1.2 深拷貝(復(fù)制所有層級(jí))
const obj = { a: 1, b: { c: 2 }, d: [3, 4] }; // 1. JSON方法(簡(jiǎn)單場(chǎng)景,有局限性:不支持函數(shù)、符號(hào)、循環(huán)引用等) const deepCopy1 = JSON.parse(JSON.stringify(obj)); // 2. 遞歸實(shí)現(xiàn)深拷貝(完整方案) function deepClone(target) { if (typeof target !== "object" || target === null) { return target; // 非對(duì)象直接返回 } let clone = Array.isArray(target) ? [] : {}; for (const key in target) { if (target.hasOwnProperty(key)) { clone[key] = deepClone(target[key]); // 遞歸拷貝 } } return clone; } const deepCopy2 = deepClone(obj); deepCopy2.b.c = 3; console.log(obj.b.c); // 2(原對(duì)象不受影響)
4.2 對(duì)象的合并
合并多個(gè)對(duì)象為一個(gè),相同屬性后面的會(huì)覆蓋前面的。
const obj1 = { a: 1, b: 2 }; const obj2 = { b: 3, c: 4 }; const obj3 = { d: 5 }; // 1. Object.assign() const merged1 = Object.assign({}, obj1, obj2, obj3); console.log(merged1); // { a: 1, b: 3, c: 4, d: 5 } // 2. 對(duì)象擴(kuò)展運(yùn)算符 const merged2 = { ...obj1, ...obj2, ...obj3 }; console.log(merged2); // 同上
特性:均為淺合并,嵌套對(duì)象仍共享引用;適合合并配置對(duì)象等場(chǎng)景。
4.3 屬性描述符(Object.defineProperty())
通過(guò)屬性描述符可精確控制屬性的行為(是否可修改、枚舉等)。
const obj = {}; // 定義屬性描述符 Object.defineProperty(obj, "name", { value: "屬性值", // 屬性值 writable: false, // 是否可修改(默認(rèn)false) enumerable: true, // 是否可枚舉(默認(rèn)false) configurable: false // 是否可刪除或修改描述符(默認(rèn)false) }); obj.name = "新值"; // 無(wú)效(writable為false) delete obj.name; // 無(wú)效(configurable為false) console.log(Object.keys(obj)); // ["name"](enumerable為true)
應(yīng)用場(chǎng)景:定義常量屬性、實(shí)現(xiàn)數(shù)據(jù)劫持(如Vue響應(yīng)式原理)等。
五、常見(jiàn)問(wèn)題與避坑指南
5.1 引用類型的賦值陷阱
const obj1 = { a: 1 }; const obj2 = obj1; // 引用賦值,共享內(nèi)存 obj2.a = 2; console.log(obj1.a); // 2(原對(duì)象被修改)
解決方案:用淺拷貝或深拷貝創(chuàng)建新對(duì)象,避免直接引用賦值。
5.2 for...in遍歷的繼承屬性問(wèn)題
const obj = { a: 1 }; // 給原型添加屬性(會(huì)被for...in遍歷到) Object.prototype.b = 2; for (const key in obj) { console.log(key); // "a", "b"(不希望遍歷繼承的b) }
解決方案:用hasOwnProperty()
過(guò)濾繼承屬性:
for (const key in obj) { if (obj.hasOwnProperty(key)) { console.log(key); // "a"(僅自身屬性) } }
5.3 符號(hào)屬性的遍歷問(wèn)題
符號(hào)(Symbol
)作為屬性名時(shí),for...in
、Object.keys()
等方法無(wú)法遍歷:
const sym = Symbol("id"); const obj = { a: 1, [sym]: 2 }; console.log(Object.keys(obj)); // ["a"](不含符號(hào)屬性) for (const key in obj) { console.log(key); // "a"(不含符號(hào)屬性) }
解決方案:用Object.getOwnPropertySymbols()
獲取符號(hào)屬性:
const symbols = Object.getOwnPropertySymbols(obj); console.log(symbols); // [Symbol(id)] console.log(obj[symbols[0]]); // 2
總結(jié):對(duì)象操作的核心原則
- 選擇合適的創(chuàng)建方式:簡(jiǎn)單對(duì)象用字面量,多實(shí)例對(duì)象用
class
或構(gòu)造函數(shù),復(fù)雜繼承用Object.create()
;- 區(qū)分自身與繼承屬性:操作屬性時(shí)注意
hasOwnProperty()
的使用,避免誤操作繼承屬性;- 遍歷方法的選擇:
Object.keys()
/values()
適合簡(jiǎn)單遍歷,Reflect.ownKeys()
適合獲取所有屬性;- 深淺拷貝的區(qū)別:淺拷貝適合扁平對(duì)象,嵌套對(duì)象需用深拷貝避免引用問(wèn)題。
到此這篇關(guān)于JavaScript之對(duì)象操作詳解的文章就介紹到這了,更多相關(guān)js對(duì)象操作內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Vuejs對(duì)象常用操作之取對(duì)應(yīng)的值、取key和value值、轉(zhuǎn)數(shù)組及合并等
- JavaScript數(shù)學(xué)對(duì)象Math操作數(shù)字的方法
- JavaScript時(shí)間對(duì)象Date內(nèi)置構(gòu)造函數(shù)操作實(shí)例
- JS?中的URLSearchParams?對(duì)象操作(以對(duì)象的形式上傳參數(shù)到url)
- JS數(shù)組操作大全對(duì)象數(shù)組根據(jù)某個(gè)相同的字段分組
- JavaScript操作DOM對(duì)象詳解
- JavaScript Dom對(duì)象的操作
- Java讀取項(xiàng)目json文件并轉(zhuǎn)為JSON對(duì)象的操作
相關(guān)文章
JavaScript實(shí)現(xiàn)移動(dòng)端輪播效果
這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)移動(dòng)端輪播效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06bootstrap multiselect 多選功能實(shí)現(xiàn)方法
這篇文章主要介紹了bootstrap multiselect 多選功能實(shí)現(xiàn)方法,需要的朋友可以參考下2017-06-06JS實(shí)現(xiàn)區(qū)分中英文并統(tǒng)計(jì)字符個(gè)數(shù)的方法示例
這篇文章主要介紹了JS實(shí)現(xiàn)區(qū)分中英文并統(tǒng)計(jì)字符個(gè)數(shù)的方法,涉及JavaScript事件響應(yīng)、正則匹配及數(shù)值運(yùn)算相關(guān)操作技巧,需要的朋友可以參考下2018-06-06關(guān)于COOKIE個(gè)數(shù)與大小的問(wèn)題
在一次面試過(guò)程中,面試官問(wèn)過(guò)我關(guān)于瀏覽器cookie的問(wèn)題包括:cookie大小,cookie個(gè)數(shù)限制以及如何操作cookie等一系列的問(wèn)題。2011-01-01檢測(cè)是否已安裝 .NET Framework 3.5的js腳本
管理員必須首先確認(rèn)存在 .NET Framework 3.5 運(yùn)行庫(kù),然后才能將 Windows Presentation Foundation (WPF) 應(yīng)用程序部署在面向 .NET Framework 3.5 的系統(tǒng)上。2009-02-02JavaScript操作XML實(shí)例代碼(獲取新聞標(biāo)題并分頁(yè),并分頁(yè))
XML 代碼部分 這是一個(gè)新聞的XML 文件,如果 NBody部分包含 XML 和Html 不可識(shí)別部分, 就 包含在DATA 表示附中。2010-05-05javascript實(shí)現(xiàn)的多個(gè)層切換效果通用函數(shù)實(shí)例
這篇文章主要介紹了javascript實(shí)現(xiàn)的多個(gè)層切換效果通用函數(shù),涉及javascript針對(duì)頁(yè)面元素樣式的遍歷與操作技巧,需要的朋友可以參考下2015-07-07- 當(dāng)大家使用window.onload執(zhí)行一個(gè)函數(shù)時(shí),必須要等到頁(yè)面上的圖片等信息全部加載完畢之后才執(zhí)行的。但很多時(shí)候圖片的數(shù)量比較多,所以需要很多時(shí)間下載。更令人尷尬的是,當(dāng)網(wǎng)頁(yè)文檔(或者說(shuō)Dom)已經(jīng)加載完畢,而圖片尚未加載完畢,很多用戶已經(jīng)開始瀏覽網(wǎng)頁(yè),但這時(shí)很多由window.onload所觸發(fā)的函數(shù)不能執(zhí)行,這就導(dǎo)致一部分功能不能完美地給用戶使用,更嚴(yán)重的是會(huì)給用戶留下不好的印象!2008-05-05