对象的属性
对象就是一些无序属性的集合,Javascript对象规定了这些属性的内部特性,对象中定义的每一个属性都要遵守这些内部特性的约束。
对象的属性的特性有两种:数据属性,访问器属性
数据属性
- [[Writable]]:属性的值是否可以被修改,默认为 true
- [[Enumerable]]:属性是否可被遍历
- [[Value]]:表示属性的值,默认为 undefined
- [[Configurable]]:属性是否可被重新定义或被修改特性,默认为true
访问器属性
- [[Get]] :在读取属性的值时调用的函数,默认值为undefined
- [[Set]] :在写入属性的值时调用的函数,默认值为undefined
查看属性的特性
为了表示这些特性与普通属性的区别,ECMAScript规范把它们都包裹在一对方括号中。我们可以用 Object.getOwnPropertyDescriptor() 来查看一个对象中某一个属性的特性:
const obj = {
msg: 'Hello World'
}
// 第一个参数是要查看的对象,第二个参数是要查看的属性,写成字符串形式
console.log(Object.getOwnPropertyDescriptor(obj, 'msg'))
打印的结果
常用的对象内置方法
Object.hasOwnProperty()
用来检查对象自身是否含有给定的属性(非继承而来的),它是Object.prototype 对象上的方法,所有对象都会继承这个方法。返回一个布尔值,表示检查的结果
const person = {
msg: 'Hello World'
}
person.hasOwnProperty('msg') // true
person.hasOwnProperty('name') // false
可以看到,msg 是 person 含有的属性,所以返回 true;person 没有 name 这个属性,故而返回 false
Object.defineProperty & Object.defineProperties
我们有时候真的需要自定义这些属性的特性,比如让它不可修改,或者让它不可被外界访问到。Object.defineProperty() 方法就可以做这些事情
const obj = {
msg: 'Hello World'
}
Object.defineProperty(obj, 'msg', {
writable: false
})
obj.msg = 'Good Morning'
console.log(obj.msg) // 'Hello World'
上面的代码通过 Object.defineProperty() 将 obj 对象的 msg 属性的 writable 特性设置为 false,表示它不可以被修改,所以再对 msg 赋值将是无效的
使用 delete 操作符可以删除对象的一个属性,它的返回值是布尔,表示删除是否成功
const obj = {
msg: 'Hello World'
}
Object.defineProperty(obj, 'msg', {
configurable: true
})
// 使用 delete 删除 msg 属性
delete obj.msg
console.log(delete obj.msg) // true
console.log(obj.msg) // undefined
注意: configurable 一旦设置为 false ,状态就冻结了,此后再也无法修改其值
const obj = {
msg: 'Hello World'
}
Object.defineProperty(obj, 'msg', {
configurable: false
})
// 使用 delete 删除 msg 属性将会失败
delete obj.msg
console.log(delete obj.msg) // false
// 试图改回 configurable 的值
Object.defineProperty(obj, 'msg', {
configurable: true
})
// 删除操作会报错,因为 configurable 的值已经被冻结为 false
delete obj.msg
console.log(delete obj.msg)
// Uncaught TypeError: Cannot redefine property: msg at Function.defineProperty
Object.defineProperties() 方法,property变成了复数形式,顾名思义是用来一次性定义多个属性的特性,下面是它的用法
const person = {
msg: 'Hello World'
name: 'Aelly',
age: 28
}
Object.defineProperty(person, {
'msg': {
value: 'Hello',
writable: true
},
'age': {
value: 25,
writable: false
},
'name': {
value: 'Aelly',
writable: false,
configurable: false
},
})
Object.keys() & Object.getOwnPropertyNames
这两个方法的作用都是遍历对象的属性,返回属性名组成的数组,它们的不同之处在于:Object.keys 只遍历可枚举的属性(enumerable 特性的值为 true),而 Object.getOwnPropertyNames 却可以遍历到不可枚举的属性
const obj = {
age: 2020,
msg: 'Hello World',
color: 'red'
}
console.log(Object.keys(obj)) // ["age", "msg", "color"]
console.log(Object.getOwnPropertyNames(obj)) // ["age", "msg", "color"]
const arr = [1, 2, 3, 4]
console.log(Object.keys(arr)) // ["0", "1", "2", "3"]
console.log(Object.getOwnPropertyNames(arr)) // ["0", "1", "2", "3", "length"]
function f(){
const name = "Hello World"
const age = 2020
}
console.log(Object.keys(f)) // []
console.log(Object.getOwnPropertyNames(f))
// ["length", "name", "arguments", "caller", "prototype"]
对于纯对象(Obejct)来说,这两个方法返回的结果无差别,不过对于数组(也是对象)来说,Object.getOwnPropertyNames 却遍历到了 length 属性;再看对函数遍历的结果,Object.getOwnPropertyNames返回了许多函数内部独有的不可被外部遍历到的属性
Object.getPrototypeOf()
获取一个对象的原型,返回值就是该对象的 prototype 对象
const obj = {
msg: 'Hello World'
}
console.log(Object.getPrototypeOf(obj))
打印结果
Object.create()
以一个对象为原型来创建另一个对象,相当于复制了其所有属性到另一个对象
const Person = {
age: 2020,
msg: 'Hello World',
color: 'red'
}
const Aelly = Object.create(Person)
console.log(Person)
console.log(Aelly)
通过查看打印结果我们可以发现,对象 Aelly 的 __ proto__ 属性正是对象 Person。基于 Object.create() 的这个功能,在面向对象编程中,常常用它来实现类式继承
Object.assign()
用于将一个或者多个对象的自身的(非继承而来的)可枚举的属性,浅复制到另一个目标对象;第一个参数是目标对象,后面接受一个参数列表,表示源对象。它的返回值就是完成了浅复制操作后的目标对象
const target = {}
const source1 = {
age: 2020,
msg: 'Hello World',
color: 'red'
}
const source2 = {
name: 'Andy',
color: 'Orange'
}
const result = Object.assign(target, source1, source2)
console.log(result) // {age: 2020, msg: "Hello World", color: "Orange", name: "Andy"}
如果源对象中存在与目标对象同名的属性,那么目标对象中的这个属性将会被覆盖,上面代码中,color 的值就被覆盖了
Object.assign() 复制的仅仅是值,而不是值的引用:
const result = Object.assign(target, source1, source2)
console.log(result) // {age: 2020, msg: "Hello World", color: "Orange", name: "Andy"}
source1.name = 'AKSJFKSFFLSNVKKFSDLJFFFEFNS'
console.log(result)
最后一个 console.log() 打印出来的值将不会发生任何变化,你可以去控制台实操一下
本文参考了 MDN 文档和《Javascript标准参考教程》,代码全部亲手实现,如有错误,欢迎指出!