一、对象
1.新建一个对象
// An object literal with two key-value pairs
let spaceship = {
'Fuel Type': 'diesel',
color: 'silver'
};
We separate each key-value pair in an object literal with a comma (,
)
Keys are strings, but when we have a key that does not have any special characters in it, JavaScript allows us to omit the quotation marks
Keys are strings, but when we have a key that does not have any special characters in it, JavaScript allows us to omit the quotation marks
2.Accessing Properties
我们可以用dot notation:
'hello'.length; // Returns 5
也可以用这种方法:
let spaceship = {
'Fuel Type': 'Turbo Fuel',
'Active Duty': true,
homePlanet: 'Earth',
numCrew: 5
};
spaceship['Active Duty']; // Returns true
spaceship['Fuel Type']; // Returns 'Turbo Fuel'
spaceship['numCrew']; // Returns 5
spaceship['!!!!!!!!!!!!!!!']; // Returns undefined
当属性名中包含特殊字符的时候(比如空格),只能用这种方法 ,不能用dot notation。该有的引号不能少。
我们还可以编写一个函数来得到希望的属性的值:
let returnAnyProp = (objectName, propName) => objectName[propName];
returnAnyProp(spaceship, 'homePlanet'); // Returns 'Earth'
函数接受两个参数,分别代表希望得到属性的对象和希望得到的属性。
3.增删改属性
const spaceship = {type: 'shuttle'};
spaceship = {type: 'alien'}; // TypeError: Assignment to constant variable.
spaceship.type = 'alien'; // Changes the value of the type property
spaceship.speed = 'Mach 5'; // Creates a new key of 'speed' with a value of 'Mach 5'
4.给对象添加方法
可以用下面的两种语法来给对象写一个方法
const alienShip = {
invade: function () {
console.log('Hello! We have come to dominate your planet. Instead of Earth, it shall be called New Xaculon.')
}
};
const alienShip = {
invade () {
console.log('Hello! We have come to dominate your planet. Instead of Earth, it shall be called New Xaculon.')
}
};
alienShip.invade(); // Prints 'Hello! We have come to dominate your planet. Instead of Earth, it shall be called New Xaculon.'
当我们写多个方法时,不要忘记方法和方法之间的逗号:
let alienShip = {
retreat() {
console.log(retreatMessage)
},
takeOff() {
console.log('Spim... Borp... Glix... Blastoff!')
}
};
5.Nested Objects
const spaceship = {
telescope: {
yearBuilt: 2018,
model: '91031-XLT',
focalLength: 2032
},
crew: {
captain: {
name: 'Sandra',
degree: 'Computer Engineering',
encourageTeam() { console.log('We got this!') }
}
},
engine: {
model: 'Nimbus2000'
},
nanoelectronics: {
computer: {
terabytes: 100,
monitors: 'HD'
},
'back-up': {
battery: 'Lithium',
terabytes: 50
}
}
};
如果我们要访问属性:
spaceship.nanoelectronics['back-up'].battery; // Returns 'Lithium'
6.按引用传递
let spaceship = {
homePlanet : 'Earth',
color : 'red'
};
let tryReassignment = obj => {
obj = {
identified : false,
'transport type' : 'flying'
}
console.log(obj) // Prints {'identified': false, 'transport type': 'flying'}
};
tryReassignment(spaceship) // The attempt at reassignment does not work.
spaceship // Still returns {homePlanet : 'Earth', color : 'red'};
spaceship = {
identified : false,
'transport type': 'flying'
}; // Regular reassignment still works.
`tryReassignment` 的函数接受一个对象作为参数。在 `tryReassignment` 函数中,尝试重新分配(reassignment)传入的对象 `obj`,将其设置为一个新的对象,改变原来的属性为新的属性: `{ identified: false, 'transport type': 'flying' }`。函数的参数为 `spaceship` 对象,因此尝试重新分配的是 `spaceship` 对象。
在这段代码中,`obj` 是一个函数参数,它是一个局部变量,只在函数中有效。当函数被调用时,`obj` 参数被赋值为传递给函数的实参 `spaceship` 的值,也就是 `spaceship` 对象的引用。因此,`obj` 和 `spaceship` 实际上引用了同一个对象。
在 `tryReassignment` 函数中,尝试重新分配 `obj`,将其设置为一个新的对象 `{ identified: false, 'transport type': 'flying' }`。这实际上是将 `obj` 的引用指向了一个新的对象,而不是修改了原始的 `spaceship` 对象。
因此,即使在 `tryReassignment` 函数中重新分配了 `obj`,原始的 `spaceship` 对象仍然保持不变。
因此,尽管在 `tryReassignment` 函数中重新分配了 `obj`,但原始的 `spaceship` 对象仍然保持不变。在函数调用后,`spaceship` 对象仍然是 `{ homePlanet: 'Earth', color: 'red' }`。
7.Looping Through Objects
js提供了for循环来直接遍历对象的属性。
let spaceship = {
crew: {
captain: {
name: 'Lily',
degree: 'Computer Engineering',
cheerTeam() { console.log('You got this!') }
},
'chief officer': {
name: 'Dan',
degree: 'Aerospace Engineering',
agree() { console.log('I agree, captain!') }
},
medic: {
name: 'Clementine',
degree: 'Physics',
announce() { console.log(`Jets on!`) } },
translator: {
name: 'Shauna',
degree: 'Conservation Science',
powerFuel() { console.log('The tank is full!') }
}
}
};
// Write your code below
for (let crewMember in spaceship.crew) {
console.log(`${crewMember}: ${spaceship.crew[crewMember].name}`)
};
for (let crewMember in spaceship.crew) {
console.log(`${spaceship.crew[crewMember].name}: ${spaceship.crew[crewMember].degree}`)
};
captain: Lily chief officer: Dan medic: Clementine translator: Shauna Lily: Computer Engineering Dan: Aerospace Engineering Clementine: Physics Shauna: Conservation Science
let实际上是对各个属性重命名,for循环会自动把各个属性的名字赋给let后的crewMember
如何通过这种方法准确找到希望的属性非常重要!
如果把第二个for循环改成:
for (let crewMember in spaceship.crew) {
console.log(`${crewMember.name}: ${spaceship.crew[crewMember].degree}`)
};
undefined: Computer Engineering
undefined: Aerospace Engineering
undefined: Physics
undefined: Conservation Science
原因是crewMember= captain,chief officer,而不是spaceship.crew[captain],spaceship.crew[chief officer],所以直接打印crewMember.name等于打印caption.name,可是最外层并没有caption这个对象,最外层只有spaceship对象,所以结果是undefined。
而第一个for循环里,我们只希望打印captain和chief officer,相当于打印两个字符串,而不是通过caption的地址打印其他内容,所以可以不需要加外层的索引(spaceship.crew[~~~~])
8.review
- Objects store collections of key-value pairs.
- Each key-value pair is a property—when a property is a function it is known as a method.
- An object literal is composed of comma-separated key-value pairs surrounded by curly braces.
- You can access, add or edit a property within an object by using dot notation or bracket notation.
- We can add methods to our object literals using key-value syntax with anonymous function expressions as values or by using the new ES6 method syntax.
- We can navigate complex, nested objects by chaining operators.
- Objects are mutable—we can change their properties even when they’re declared with
const
. - Objects are passed by reference— when we make changes to an object passed into a function, those changes are permanent.
- We can iterate through objects using the
For...in
syntax.
9.this
我们可以用this关键字来访问本对象的其他属性:
const robot = {
model:'1E78V2',
energyLevel:100,
provideInfo(){
return `I am ${this.model} and my current energy level is ${this.energyLevel}.`
}
};
console.log(robot.provideInfo());
I am 1E78V2 and my current energy level is 100.
注意:Arrow functions inherently bind, or tie, an already defined this
value to the function itself that is NOT the calling object. In the code snippet above, the value of this
is the global object, or an object that exists in the global scope, which doesn’t have a dietType
property and therefore returns undefined
.
const goat = {
dietType: 'herbivore',
makeSound() {
console.log('baaa');
},
diet: () => {
console.log(this.dietType);
}
};
goat.diet(); // Prints undefined
10.Privacy
One common convention is to place an underscore _
before the name of a property to mean that the property should not be altered. Here’s an example of using _
to prepend a property.
const bankAccount = {
_amount: 1000
}
In the example above, the _amount
is not intended to be directly manipulated.
Even so, it is still possible to reassign _amount
:
bankAccount._amount = 1000000;
所以有-并不是强制不给更改了,只是表明我不希望你更改。
11.get方法
const person = {
_firstName: 'John',
_lastName: 'Doe',
get fullName() {
if (this._firstName && this._lastName){
return `${this._firstName} ${this._lastName}`;
} else {
return 'Missing a first name or a last name.';
}
}
}
// To call the getter method:
person.fullName; // 'John Doe'
注意,get方法有自己的关键字get,当我们调用get方法的时候,我们不需要写括号,就好像我们在访问person的一个属性一样。
12.setter
const person = {
_age: 37,
set age(newAge){
if (typeof newAge === 'number'){
this._age = newAge;
} else {
console.log('You must assign a number to age');
}
}
};
person.age = 40;
console.log(person._age); // Logs: 40
person.age = '40'; // Logs: You must assign a number to age
setter也有自己的关键字,用setter赋值的时候,也不需要括号。
用getter和setter的一个好处是,可以对输入的类型做限定。
当然,我们也可以直接更改属性的内容,但是这样无法保证属性的类型:
person._age = 'forty-five'
console.log(person._age); // Prints forty-five
13.Factory Functions
我们可以用这种方式一次创建多个对象,有些像构造器
function robotFactory(model,mobile){
return {
model:model,
mobile:mobile,
beep(){
console.log('Beep Boop');
}
}
}
const tinCan=robotFactory('P-500',true)
tinCan.beep();
Beep Boop
我们还可以做如下简化:
const robotFactory = (model, mobile) => {
return {
model,
mobile,
beep() {
console.log('Beep Boop');
}
}
}
14.Object.keys()
The Object.keys()
static method returns an array of a given object's own enumerable string-keyed property names.
const object1 = {
a: 'somestring',
b: 42,
c: false
};
console.log(Object.keys(object1));
// Expected output: Array ["a", "b", "c"]
15.The Object.entries()
The Object.entries()
static method returns an array of a given object's own enumerable string-keyed property key-value pairs.
const object1 = {
a: 'somestring',
b: 42
};
for (const [key, value] of Object.entries(object1)) {
console.log(`${key}: ${value}`);
}
// Expected output:
// "a: somestring"
// "b: 42"
16.Object.assign()
The Object.assign()
static method copies all enumerable own properties from one or more source objects to a target object. It returns the modified target object.
const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };
const returnedTarget = Object.assign(target, source);
console.log(target);
// Expected output: Object { a: 1, b: 4, c: 5 }
console.log(returnedTarget === target);
// Expected output: true
17.review
- The object that a method belongs to is called the calling object.
- The this keyword refers to the calling object and can be used to access properties of the calling object.
- Methods do not automatically have access to other internal properties of the calling object.
- The value of
this
depends on where thethis
is being accessed from. - We cannot use arrow functions as methods if we want to access other internal properties.
- JavaScript objects do not have built-in privacy, rather there are conventions to follow to notify other developers about the intent of the code.
- The usage of an underscore before a property name means that the original developer did not intend for that property to be directly changed.
- Setters and getter methods allow for more detailed ways of accessing and assigning properties.
- Factory functions allow us to create object instances quickly and repeatedly.
- There are different ways to use object destructuring: one way is the property value shorthand and another is destructured assignment.
- As with any concept, it is a good skill to learn how to use the documentation with objects!