前言
昨天谈到了这些问题,发现认识比较片面。决定仔细看看并总结一下。
研究Object的部分ES5 API。可能会提到部分ES6内容。
Object
属性描述符
即描述对象属性特性的描述符
四个特性描述符
value
值writable
只读性enumerable
可枚举性configurable
可配置性(属性的删除与重新配置)
value
默认为undefined
在使用Object.create()
和Object.defineProperty
时writable
、enumerable
、configurable
默认均为false
两个访问器
get
不可与value
同时使用,会由属性的读取触发。set
不可与writable
同时使用,会由属性的写入触发。
将会在其他的api中介绍属性描述符的用法
对象的创建与属性修改
Object.create()
Object.create(proto, [ propertiesObject ])
此api的作用是以proto
为原型,以propertiesObject
中自有属性(不包含propertiesObject
的原型上的属性,包含所有不可枚举属性)为属性创建一个新的对象。
// 非严格模式下运行,严格模式下会抛出异常
const proto = {
saySize () {
console.log(this.size)
}
}
const propertiesObject = {
size: {
enumerable: false,
configurable: false,
value: 'large'
},
color: {
writable: true,
enumerable: true,
configurable: true,
value: 'red'
}
}
let newObj = Object.create(proto, propertiesObject)
// 原型
newObj.saySize()
// "large"
// writable
newObj.size = 'small'
newObj.color = 'green'
console.log(newObj.size, newObj.color)
// "large,green"
// enumerbale
for(key in newObj){
console.log(key)
}
// "color"
// "saySize"
delete newObj.size
// false
delete newObj.color
// true
上述代码中的
proto
使用Fun.prototype
即可实现原型链的继承。那么要怎样才能枚举出
enumerable:false
的属性呢?
Object.defineProperty()
Object.defineProperty(obj, prop, descriptor)
此api允许修改或向obj
添加属性 obj
为目标对象,prop
为要修改或添加的属性,descriptor
为属性描述符
let tempObj1 = {}
Object.defineProperty(tempObj, 'name', {
value: 'temp',
writable: false,
enumerable: true,
configurable: false
})
console.log(tempObj)
// Object {name: "temp"}
// 抛出异常
Object.defineProperty(tempObj, 'name', {
value: temp,
writable: true
})
对于configurable: false
的属性禁止修改属性描述符,会抛出异常。
let tempObj2 = {_name: 'temp2'}
Object.defineProperty(tempObj2, 'name', {
get () {
return `名字为${this._name}`
},
set (value) {
console.log(`新名字为${value}`)
}
})
console.log(tempObj2.name)
// "名字为temp2"
tempObj2.name = 'temp2.0'
// "新名字为temp2.0"
可以观察到 读属性值与 写属性值分别触发了get
和set
属性访问器。
代码中所用到的"`名字为${this._name}`" 为es6模板字符串,实现拼串
Object.defineProperties()
Object.defineProperties(obj, props)
此api方便了属性的批量修改,第二个参数与Object.create()
的第二个参数结构相同。
let tempObj3 = {name:'temp'}
Object.defineProperties(tempObj3, {
name: {
value: 'newTemp',
writable: true
},
color: {
value: 'red',
writable: true,
enumerable: true
}
})
console.log(tempObj3)
// Object {name: "newTemp", color: "red"}
对象属性的检测与检索
我们也看到了对于enumerable:false
的属性是不可枚举的。甚至ES6中还有“隐蔽性”更高的Symbol()
可以作为属性键。那么怎么才能正确的检测与获取对象的属性呢?
我们先创建一个对象用于实验后续的所有方法。
原型和自身都各包含三种属性:enumerable: false
,enumerable: true
,Symbol()
const proto = Object.create(null, {
supTrue: {
value: 'value1',
enumerable: true
},
supFalse: {
value: 'value2',
enumerable: false
}
})
proto[Symbol('supSymbol')] = 'supSymbol'
console.log(proto)
// {
// supTrue: "value",
// Symbol(supSymbol): "supSymbol",
// supFalse: "value2"
// }
let obj = Object.create(proto, {
ownTrue: {
value: 'value1',
enumerable: true
},
ownFalse: {
value: 'value2',
enumerable: false
}
})
obj[Symbol('ownSymbol')] = 'ownSymbol'
// ok,obj可用
for-in
for (const key in obj) {
console.log(key)
}
// subTrue, ownTrue
可以看到for in
枚举了包括原型链在内的所有可枚举属性
Object.keys()
Object.keys(obj)
// ["ownTrue"]
可以看到返回了一个只包含自身可枚举属性键的数组。
Object.getOwnPropertyNames()
Object.getOwnPropertyNames(obj)
// ["ownTrue", "ownFalse"]
可以看到返回了一个包含自身所有非symbol
的属性键的数组。
由此也可以看到symbol
类型的属性的“隐蔽性”
Object.getOwnPropertySymbols()
针对 获取symbol
可使用此方法。
Reflect.ownKeys()
虽然这个不是Object
的方法
但是可以用来获取自身所有属性键
Reflect.ownKeys(obj)
// ["ownTrue", "ownFalse", Symbol(ownSymbol)]
把对象关起来
按照权限从大到小排列
Object.preventExtensions()
作用:将对象变的不可扩展,不可添加新的属性。
Object.seal()
作用:将对象“密封”,不可添加新属性,属性的configurable
置为false
,writable
为true
的属性仍然可以被重新赋值。
权限:仅可对writable
为true
的属性进行赋值。
Object.freeze()
作用:完全“锁死”,不能做任何修改。
权限:0。
需要注意的是,上述三个api都是对原有对象的操作,并不会返回一个新的对象。
let obj = {}
Object.preventExtensions(obj) === obj // true
Object.seal(obj) === obj // true
Object.freeze(obj) === obj // true
可以说writable
,configurable
这些属性描述符是针对对象的属性做出的限制或者保护。
那么Object.seal()
,Object.preventExtensions()
,Object.freeze()
就是对对象本身做出限制或者保护。
同时我们也知道在ES6中使用const
可以声明一个"常量",但是要注意的是const
确保的只是指针的不可更改。比如:
const obj = {key: 'value1'}
obj.key = 'value2' // 可完成
obj = {key2: 'value2'} // 更改指针,抛出异常
针对对象,此时就可以使用上述三个把对象关起来的api。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。