对象定义
ECMA-262将对象定义为一组属性的无序集合。意味着对象就是一组没有特定顺序的值。 对象的每个属性或方法都由一个名称来标识,这个标识映射到一个值。我们可以想象对象就是一组散列的表,内容就是键值对,值可以是数据或者函数。
1. 实例化对象
const person = new Object()
person.name = 'tom'
person.sayName = function () {
console.log(this.name)
}
# OR
// 对象字面量方式更为常见
const person = {
name: 'tom',
sayName () {
console.log(this.name)
}
}
2. 属性的类型
ECMA-262使用一些内部特性来描述属性的特征,这些特征是有javascript实现引擎的规范定义的,因此,开发者不能在javascript中直接访问这些特性。为了将某个特性标识成内部特性, 规范用两个中括号把特性的名称包括起来。属性分为数据属性和访问器属性。
-
数据属性
a. 数据属性包含一个保存数据值的位置。 值会从这个位置读取, 也会写入到这个位置。有四个特性描述它们的行为:
-
[[Configurable]]: 属性是否可通过 delete 来删除或者重新定义,是否可以修改他的特性。以及是否可以改为访问器属性,默认为 true
-
[[Enumberable]]: 是否可以通过 for-in 来遍历,默认true
-
[[Writable]]: 是否可以被修改,默认 true
-
[[Value]]: 包含属性的实际值。 就是那个读取和写入属性值的位置, 默认 undefined
b. 要修改默认属性,就必须使用 Object.defineProperty()方法。 接收三个参数: 要给其添加属性的对象, 属性的名称, 一个描述符对象(即描述符对象上的属性可以包括: configable, enumable, writable, vlaue; 跟相关特性的名称一一对应)。
const person = new Object()
Object.defineProperty(person, 'name', {
writable: false,
value: 'tom'
})
// 声明一个person对象,并且添加一个不能修改的 name 属性, 属性值是 tom
// 在调用 Object.defineProperty() 方法时, 如果不指定 configable, writable, enumable的值, 则默认为 false.
-
访问器属性
a. 访问器属性不包含数据值。 而是包含一个获取(getter)函数和一个设置(setter)函数。不过这两个函数并不是必须的。在读取访问器属性时, 会调用 getter 函数, getter 函数负责返回一个有效的值。 在写入访问器属性时, 会调用 setter 函数并传入新值, setter 函数决定对数据做什么样的修改。访问器属性有4个特性描述它们的行为:
- [[Configurable]]: 属性是否可通过 delete 来删除或者重新定义,是否可以修改他的特性。以及是否可以改为访问器属性,默认为 true
- [[Enumberable]]: 是否可以通过 for-in 来遍历,默认true
- [[Get]]: getter函数, 在读取属性时调用, 默认 undefined
- [[Set]]: setter函数, 在写入属性时调用, 默认undefined
b. 访问器属性不能直接定义的,必须使用 Object.defineProperty()方法来实现, getter和setter不一定都要定义。指定要 getter 则默认为属性是只读。
const book = { year_: 2017, edition: 1 } Object.deinfineProperty(book, 'year', { get () { return this.year_ // year_ 这样的下划线通常用来表示该属性不希望在对象的外部被访问 }, set (newValue) { if (newValue > 2017) { this.year_ = newValue this.eidtion += newValue - 2017 } } }) book.year = 2018 console.log(book.edition) // 2 // book 定义了两个默认属性 year_, edition. // 另一个属性year定义为访问器属性,getter函数返回 year_ 的值, setter函数则是通过一些计算确定 edition的值。 // 把year属性修改成2018,或导致year_也是2018,edition成为2.
3. 定义多个属性
const book = new Object()
Object.defineProperties(book, {
year_: { value: 2017 },
edition: { value: 1 },
year: {
get () {
return this.year_
},
set (newValue) {
if (newValue > 2017) {
this.year_ = newValue
this.eidtion += newValue - 2017
}
}
}
})
// 上述代码一次性为book对象定义两个数据属性year_和edition, 还定义了一个访问器属性 year
4. 读取属性的特性
a. 使用 Object.getOwnPropertyDescriptor()方法可以取得指定属性的属性描述符。
// 用 3.定义多个属性的代码示例
const descriptor = Object.getOwnPropertyDescriptor(book, 'year_') // 数据属性
descriptor.value // 2017
descriptor.configable // false
typeof descriptor.get // undefined
const desYear = Object.getOwnPropertyDescriptor(book, 'year') // 访问器属性
desYear.value // undefined
desYear.enumable // false
type desYear.get // function
b. ECMA-2017提供了一个 Object.getOwnPropertyDescriptors()静态方法。
// 使用 3.定义多个属性的代码示例
console.log(Object.getOwnPropertyDescriptors(book))
{
edition: { // 数据属性
configable: false,
enumable: fasle,
value: 1,
writable: false
},
year_: { // 数据属性
configable: false,
enumable: fasle,
value: 2017,
writable: false
},
year: { // 访问器属性
configable: false,
enumable: fasle,
get: f(),
set: f(newVlaue)
}
}
5. 合并对象
javascript开发者经常觉得 “合并(merge)” 两个对象很有用。就是把源对象所有的本地属性一起复制到目标对象上。 有时候这种操作也被称为 “混入(mixin)” 目标对象通过混入源对象的属性得到了增强。ES6提供了 专门用来合并对象的方法Object.assgin(). 接收一个目标对象和一个或者多个源对象作为参数, 然后将源对象中每个可枚举(Objct.propertyIsEnumerable()返回true)和自有(Object.hasOwnProperty()返回true)的属性复制到目标对象。以字符串和符号为键的属性会被复制。对每个符合条件的属性,都会使用源对象上的getter取得属性的值, 然后使用目标对象上的setter设置属性的值。
const target = { id: 'target', value: 123 }
const source1 = { id: 'source1', a: 'foo' }
const source2 = { id: 'source2', a: 'bar', c: {}}
const result = Object.assgin(target, source1, source2)
console.log(result) // {id: 'source2', value: 123, a: 'bar', c: {}} 重复的属性会被后面定义的所覆盖
console.log(result.c === source2.c) // true, 表示是浅复制(只会复制对象的引用)
6. 对象标识以及相等判断
true === 1 // false
Object.is(true, 1) // false
{} === {} // false
Object.is({}, {}) // false
'2' === 2 // false
Object.is('2', 2) // false
+0 === -0 // true
Object.is(+0, -0) // false
0 === +0 // true
Object.is(0, +0) // true
0 === -0 // true
Object.is(0, -0) // false
NaN === NaN // false
isNaN(NaN) // true
Object.is(NaN, NaN) // true
7. 增强对象语法(同样适用ES6的类)
- 属性值简写
let name = 'tom'
const person = {
name
}
console.log(person) // {name: 'tom'}
- 可计算属性
// 使用可计算属性之前
const nameKey = 'name'
cosnt ageKey = 'age'
const jobKey = 'job'
let person = new Object()
person[nameKey] = 'tom'
person[ageKey] = 18
persion[jobKey] = 'student'
// 使用计算属性
let person = {
[nameKey]: 'tom',
[ageKey]: 18,
[jobKey]: 'student'
}
-
简写方法名
const obj = { sayName: function (n) {console.log('say hello' + n)} // 没有简写 sayNmae (n) { console.log('say hello' + n) } // 简写 }
8. 对象的解构
对象解构就就是使用与对象匹配的结构来实现对象属性赋值。
const person = {
name: 'tom',
age: 19,
desc: {
title: 'hello student'
}
}
const {name, age: personAge, desc, job = 'student', score} = person
console.log(name, personAge, job, score) // tom, 19, {title: 'hello student'}, student, undefined
const { desc:{title} } = person // 嵌套解构
console.log(title) // 'hello student'
网友评论