Objects
JavaScript 有 7 種資料類型,6 種只能儲存一個值,但物件能儲存多個 key: value,key 為 string 或 symbol,value 可以為任何值。
let user = new Object(); // "object constructor" syntax
let user = {}; // "object literal" syntax
Literals and properties
let user = { // an object
name: "John", // by key "name" store value "John"
age: 30, // by key "age" store value 30
"likes birds": true, // multiword property name must be quoted 最後一個加上,
};
// get fields of the object:
alert( user.name ); // John
alert( user.age ); // 30
// 刪除物件資料
delete user.age;
Square brackets
let user = {};
// this would give a syntax error
user.likes birds = true
// set
user["likes birds"] = true;
// get
alert(user["likes birds"]); // true
// delete
delete user["likes birds"];
let key = "likes birds";
// same as user["likes birds"] = true;
user[key] = true;
// key obtain property name as a result of expression
let user = {
name: "John",
age: 30
};
let key = prompt("What do you want to know about the user?", "name");
// access by variable
alert( user[key] ); // John (if enter "name")
Computed properties
let fruit = prompt("Which fruit to buy?", "apple");
let bag = {
[fruit]: 5, // the name of the property is taken from the variable fruit
};
alert( bag.apple ); // 5 if fruit="apple"
// same
let fruit = prompt("Which fruit to buy?", "apple");
let bag = {};
// take property name from the fruit variable
bag[fruit] = 5;
// more complex expression
let fruit = 'apple';
let bag = {
[fruit + 'Computers']: 5 // bag.appleComputers = 5
};
Reserved words are allowed as property names
任意的名稱都可以作為屬性名稱,只有 _proto_ 不行。
let obj = {
for: 1,
let: 2,
return: 3
};
alert( obj.for + obj.let + obj.return ); // 6
let obj = {};
obj.__proto__ = 5;
alert(obj.__proto__); // [object Object], didn't work as intended
Property value shorthand
通常會使用現存變數的名稱作為 key,可以簡寫為一個值,如下範例。
function makeUser(name, age) {
return {
name: name,
age: age
// ...other properties
};
}
let user = makeUser("John", 30);
alert(user.name); // John
// shorthand
function makeUser(name, age) {
return {
name, // same as name: name
age // same as age: age
// ...
};
}
// both use normal and shorthands
let user = {
name, // same as name:name
age: 30
};
Existence check
要取得物件不存在的屬性不會出現錯誤,會返回 undefined,可以用來檢測屬性是否存在;也可以用 in 檢查。
let user = {};
alert( user.noSuchProperty === undefined ); // true means "no such property"
// special operator in
let user = { name: "John", age: 30 };
alert( "age" in user ); // true, user.age exists
alert( "blabla" in user ); // false, user.blabla doesn't exist
// omit ""
let user = { age: 30 };
let key = "age";
alert( key in user ); // true, takes the name from key and checks for such property
// special condition if value = undefined
let obj = {
test: undefined
};
alert( obj.test ); // it's undefined, so - no such property?
alert( "test" in obj ); // true, the property does exist!
The “for…in” loop
物件的迴圈不適用 for { ; ; }
而是 for { in }
,
for (key in object) {
// executes the body for each key among object properties
}
let user = {
name: "John",
age: 30,
isAdmin: true
};
for (let key in user) {
// keys
alert( key ); // name, age, isAdmin
// values for the keys
alert( user[key] ); // John, 30, true
}
Ordered like an object
整數的屬性依照大小排列,其他的屬性依寫得先後順序排列。
let codes = {
"49": "Germany",
"41": "Switzerland",
"44": "Great Britain",
// ..,
"1": "USA"
};
for (let code in codes) {
alert(code); // 1, 41, 44, 49
}
// Math.trunc is a built-in function that removes the decimal part
alert( String(Math.trunc(Number("49"))) ); // "49", same, integer property
alert( String(Math.trunc(Number("+49"))) ); // "49", not same "+49" ⇒ not integer property
alert( String(Math.trunc(Number("1.2"))) ); // "1", not same "1.2" ⇒ not integer property
let codes = {
"+49": "Germany",
"+41": "Switzerland",
"+44": "Great Britain",
// ..,
"+1": "USA"
};
for (let code in codes) {
alert( +code ); // 49, 41, 44, 1
}
let user = {
name: "John",
surname: "Smith"
};
user.age = 25; // add one more
// non-integer properties are listed in the creation order
for (let prop in user) {
alert( prop ); // name, surname, age
}
Copying by reference
原始值會複製一樣的值進去,物件會指到相同的記憶體,只要有一個物件的值改變,所有指向相同記憶體的物件都會改變
let message = "Hello!";
let phrase = message;
let user = { name: "John" };
let admin = user; // copy the reference
admin.name = 'Pete'; // changed by the "admin" reference
alert(user.name); // 'Pete', changes are seen from the "user" reference
Comparison by reference
== 跟 === 對物件來說是一樣的,只有當 2 個變數都只到相同記憶體時才相同。
let a = {};
let b = a; // copy the reference
alert( a == b ); // true, both variables reference the same object
alert( a === b ); // true
// different reference
let a = {};
let b = {}; // two independent objects
alert( a == b ); // false
Const object
const
在同個記憶體內改變物件不會出現錯誤,除非將變數指向另一個記憶體才會出現錯誤。
const user = {
name: "John"
};
user.age = 25; // (*)
alert(user.age); // 25
// change reference
const user = {
name: "John"
};
// Error (can't reassign user)
user = {
name: "Pete"
};
Cloning and merging, Object.assign
通常會使用變數指到相同的記憶體,但若想要複製獨立一樣的物件,也是可行的。
let user = {
name: "John",
age: 30
};
let clone = {}; // the new empty object
// let's copy all user properties into it
for (let key in user) {
clone[key] = user[key];
}
// now clone is a fully independent clone
clone.name = "Pete"; // changed the data in it
alert( user.name ); // still John in the original object
// 或是使用 Object.assign
Object.assign(dest, [src1, src2, src3...])
let user = { name: "John" };
let permissions1 = { canView: true };
let permissions2 = { canEdit: true };
// copies all properties from permissions1 and permissions2 into user
Object.assign(user, permissions1, permissions2);
// now user = { name: "John", canView: true, canEdit: true }
// use Object.assign
let user = {
name: "John",
age: 30
};
let clone = Object.assign({}, user);
// 以上方法是用在物件的屬性為原始值,若屬性包含物件會指向相同記憶體。
let user = {
name: "John",
sizes: {
height: 182,
width: 50
}
};
let clone = Object.assign({}, user);
alert( user.sizes === clone.sizes ); // true, same object
// user and clone share sizes
user.sizes.width++; // change a property from one place
alert(clone.sizes.width); // 51, see the result from the other one
// 為了解決屬性也是物件的問題,可以使用函式庫 lodash 的函式 .cloneDeep(obj)
Last updated