[JS] JavaScript 物件(Object)
- Property flags and descriptors @ javascript.info
- 🔖 Object @ MDN > Web technology for developers > JavaScript
- 🔖 JavaScript object basics @ MDN > Learn Web Development > JavaScript
- 🔖 重新認識 JavaScript: Day 22 深入理解 JavaScript 物件屬性 @ iThome 鐵人賽
使用物件:
// 同時對 object destructuring 的變數「重新命名」和給予「預設值」
const { message: msg = 'Something went wrong' } = { message: 'Hello'};
Object.keys(obj); // 列出物件的所有鍵(需為可列舉的屬性)
Object.values(obj); // 取得物件的所有值
Object.entries(obj); // 把物件的 key 和 value 攤成陣列
let copyObj = { ...obj, weight: 67 }; // 複製物件,並以更新值取代
/* 檢驗物件是否具有特定屬性 */
Object.hasOwn(instance, prop); // 檢驗是否為該物件原本就具有的屬性(繼承而來的「不會」顯示)
prop in instance; // 檢驗是否為該物件原本就具有的屬性(繼承而來的「會」顯示)
obj.hasOwnProperty(propertyName); // 建議改用 Object.hasOwn()
Object.is(value1, value2); // 比較 value1 和 value2 是否為相同的 value
delete object.property; // 刪除物件中的屬性
定義與建立物件:
const newObject = Object.create(obj); // newObject 會繼承 obj 的物件
// 定義物件 property 的 attributes/flag (descriptors)
Object.defineProperty(obj, propertyName, {
// attributes/flags (descriptors)
value: undefined,
writable: false,
enumerable: false,
configurable: false,
});
Object.defineProperties(obj, {
propertyName1: {/* descriptors */},
propertyName2: {/* descriptors */}
})
// 檢視物件中某個 property 的 attributes/flag (descriptors)
const descriptor = Object.getOwnPropertyDescriptor(obj, propertyName);
const descriptors = Object.getOwnPropertyDescriptors(obj);
// 連同 descriptors 一併複製出新的物件
const clonedObj = {};
Object.defineProperties(clonedObj, Object.getOwnPropertyDescriptors(obj));
觀念
在 JavaScript 中,差不多所有事物都是物件,除了 null
及 undefined
以外,其它所有原始類型都可以看成是物件。
Snippets
依據條件指定物件屬性(conditionally assign object key)
keywords: dynamic object key
, dynamic object property
// Will result in { foo: 'foo', bar: 'bar'}
const item = {
foo: 'foo',
...(true && { bar: 'bar' }),
...(false && { falsy: 'falsy' }),
};
console.log(item);
- Assign, and set js object property conditionally @ Stack Overflow
- In Javascript, how to conditionally add a member to an object? @ Stack Overflow
還有一些類似的用法,像是:
let planA: object | undefined;
planA = {
foo: 'foo',
};
let planB: object | undefined;
planB = {
bar: 'bar',
};
const plan = {
...(planA && { planA }), // planA 存在的話,就把 { planA } 放進去物件
// ...(planA ? { planA } : {}), // 相同結果的寫法
...(planB || undefined), // planB 存在的話就直接把它解開來
...(planB || {}), // 相同結果的寫法
};
// plan
// {
// "planA": {
// "foo": "foo"
// },
// "bar": "bar"
// }
將物件扁平化
keywords: array to object
, object flatten
let arr = [{ a: 10 }, { b: 20 }, { c: 30 }];
let obj = arr.reduce((acc, current, index, array) => {
return Object.assign(acc, current);
}, {});
console.log(obj); // { a: 10, b: 20, c: 30 }
console.log({ ...arr }); // { 0: { a: 10 }, 1: { b: 20 }, 2: { c: 30 } }
簡潔的列出物件的屬性
keywords: object to array
, Object.entries()
const cars = {
BMW: 3,
Tesla: 2,
Toyota: 1,
};
Object.entries(cars); // [ [ 'BMW', 3 ], [ 'Tesla', 2 ], [ 'Toyota', 1 ] ]
for (let [key, value] of Object.entries(cars)) {
console.log(key, value);
}
移除物件屬性(immutable, pure function)
const obj = {
foo: 'bar',
stack: 'overflow',
};
// delete foo
const { foo, ...newObject } = obj;
console.log(newObject); // { stack: 'overflow' }
// delete foo through dynamic key
const keyToDelete = 'stack';
const { [keyToDelete]: value, ...newObject } = obj;
console.log(newObject); // { foo: 'bar' }
資料來源:Remove a property in an object immutably @ Stack Overflow
物件的擴展(object literal extension)
基本使用
在 ES6 中,我們可以不對物件屬性賦值,它會自動以屬性名稱當作屬性值:
let obj = { name, country }; // 等同於 obj = {name: name, country: country}
當我們寫:
let name = 'Aaron';
let country = 'Taiwan';
let obj = { name, country }; // 等同於 obj = {name: name, country: country}
console.log(obj); // [Object]{name: "Aaron", country: "Taiwan"}
所以賦值的情況如下:
因此,我們可以想像,如果我們寫成這樣:
let website = 'pjchender';
let obj = { abc: website };
console.log(obj); // [object]{abc: "pjchender}
要留意的是如果有直接在 object literal 中賦值,會覆蓋掉在更上面時所做的宣告:
let name = 'PJCHENder'; // 會被覆蓋
let country = 'Taiwan';
let obj_es6 = {
name: 'Aaron',
country,
};
console.log(obj_es6); // [Object]{name: "Aaron", country: "Taiwan"}
簡寫物件中的函式/方法
let obj = {
location() {
// 等同於 location: function () { ... }
// ...
},
};
obj.location();
允許將表達式作為屬性名稱(動態賦予屬性名稱)
keywords: dynamic object property key
允許將表達式作為屬性的名稱,只需要使用 [ ]
就可以了:
let websiteName = 'pjchender';
let a = 2;
let b = 3;
let obj_es = {
[websiteName]: 'welcome',
[a + b]: 'sumNumber',
};
console.log(obj_es); // [Object]{5: "sumNumber", pjchender: "welcome"}
let data = [
{
name: 'Aaron',
height: '171',
},
{
name: 'Lynn',
height: '160',
},
];
let obj = data.map((item) => {
return { [item.name]: item.height };
});
console.log(obj); // [ { Aaron: '171' }, { Lynn: '160' } ]
物件的解構賦值(object destructuring)
物件的解構賦值 @ 阮一峰
概念
陣列的解構賦值強調的順序,而物件的解構賦值強調的則是屬性名稱,屬性名稱必須相互對應才能夠取得到值。 在物件解構賦值中,冒號前是用來對應物件的屬性名稱,冒號後才是真正建立的變數名稱和被賦值的對象:
let { website, country } = { website: 'pjchender', country: 'Taiwan' };
let { website: website, country: country } = {
website: 'pjchender',
country: 'Taiwan',
}; // 等同於
console.log(website); // pjchender
console.log(country); // Taiwan
修改變數名稱
// 變數物件後面的值才是真正被建立和賦值的對象
let { website: wb, country: ct } = { website: 'pjchender', country: 'Taiwan' };
console.log(website, country); // website in not defined
console.log(wb, ct); // "pjchender", "Taiwan"