一、对象常量,不可修改、删除和添加属性
(1)通过Object.defineProperty设置不可修改和删除的属性。
(2)通过Object.preventExtensions(禁止拓展增加属性),可以通过Object.isExtensible来判断拓展性
let obj = {
a : 2
}
Object.preventExtensions(obj)
obj.b = 321
console.log(obj) // => {a : 2}
console.log( Object.isExtensible(obj) ) // => false
**给对象添加属性的时候,推荐使用Object.defineProperty**.因为对象不可拓展的时候,通过直接给对象属性赋值的方式在非严格模式下会**静默失败但不报错**,使用**Object.defineProperty的方式就会有报错提示(obj is not extensible)**。
(3)密封对象, Object.seal,阻止对象添加新属性,原有属性configurable改为false,不改变writable属性
可通过Object.isSealed来判断是否被密封。
(4)Object.freeze用来冻结对象,禁止添加、修改、删除对象属性,但是引用类型值可以修改,需要递归冻结引用类型值
(5)Object.preventExtensions、Object.defineProperty、Object.freeze区别
a. Object.defineProperty 设置属性是否可修改和删除,针对对象属性
b. Object.preventExtensions 用来禁止给对象属性添加新属性,针对对象
c. Object.seal 禁止添加新属性,将属性configurable改为false,不改变原有属性writable,针对对象
d. Object.freeze 用来冻结对象,禁止添加、修改、删除对象属性,但是引用类型值可以修改,需要递归冻结引用类型值,针对对象。
功力排行榜:Object.preventExtensions < Object.seal < Object.freeze
二、es6中Object新增方法
(1)Object.is
es5中有两种相等运算符, ‘==’和’===’,前者会转化数据类型,后者严格相等但是NaN和NaN、+0 和 -0不相等。
es6中新增一种相等判断,只要值相等就返回true,出了NaN和NaN, +0 和 -0两种情况,和es5严格相等没区别。
Object.is(NaN, NaN) // => true
Object.is(+0, -0) // => true
Object.is(undefined , null) // => false, 相等运算符中,undefined和null不转化,直接相等。
三、Object.assign
用于对象合并,将源对象(source)自身且可枚举属性浅拷贝到目标对象上。参数为 目标对象 + 源对象s
let target = {},
a = {a : 'a'},
b = {b : 'b'};
Object.assign(target, a, b);
console.log(target)
(1)同名属性情况:后者属性替换前者。
let target = { a: {b : 'b', c :'c'} },
source = { a: { b: 'c' } };
Object.assign( target, source ) // => { a: { b: 'c' } }
(2)如果参数为非对象,系统会将参数转化为对象
a.如果null和undefined作为目标对象参数,没有对应包装类,会报错
b.如果null和undefined作为源对象参数,系统会跳过不会报错
c.非对象值作为源对象参数时,只有字符串会以数组形式,合并到目标对象,因为只有字符串包装类会产生可枚举属性。
(3)数组处理,下标元素替换
let arr1 = [1, 2, 3],
arr2 = [4, 5];
Object.assign(arr1, arr2) // => [4, 5, 3]
(4)取值函数(getter)<br />Object.assign会先取值函数求值,再拷贝属性
let target = {},
a = {
get foo (){
return 123
}
};
Object.assign(target, a) // => {foo: 123}
(5)用处<br />a.给对象添加属性
class Super{
constructor(x, y){
Object.assign(this, {x, y})} // 给Super实例添加x,y属性
}
b.给对象添加方法
function call(val){
console.log(call)
}
function say(val){
console.log(val)
}
Object.assign(Super.prototype,{call,val})
c.合并多个对象
const options = Object.assign({}, defaultOptions, this.options)
//合并多个源对象属性返回新对象'
const merge = (target, ...sources) => Object.assign(target,...sources)
d.设置默认选项
const defaulOptions = {
url: 'google',
port:'80'
}
myOptions = {
url : 'otherUrl'
}
const UltimateOption = Object.assign({}, defaultOptions, myOptions)
//////////////////////////////
//如果配置项包含对象,默认配置项可能会被覆盖
const defaulOptions2 = {
url: {
address: 'baidu',
port:'80'
}
}
myOptions2 = {
url : {
address: 'baidu'
}
}
const UltimateOption2 = Object.assign({}, defaultOptions2, myOptions2)
// url : {address: 'baidu'} ,默认端口号消失,失效
设置默认值时,需要注意,配置项尽量为原始值,不然源对象属性会把默认值对象属性覆盖,导致默认值失效。
四、Object.defineProperties,给对象定义多个属性
(1)Object.defineProperties,参数:
object,
descriptors,包含一个或多个属性的描述对象。
let o = {};
Object.defineProperties(o,{
key1:{
value: 123,
enumerable : true,
wirtable : true,
configurable : true
},
key2: {
value: 321
}
});
console.log(o)
(2)Object.getOwnPropertyDescriptors 获取对象所有自身的属性描述对象
let o = {};
Object.defineProperties(o,{
key1:{
value: 123,
enumerable : true,
wirtable : true,
configurable : true
},
key2: {
value: 321
}
});
console.log(Object.getOwnPropertyDescriptors(o))
(3)拷贝对象getter和setter的方法<br />思路:通过Object.defineProperties定义属性
let o = {
set name(val){
console.log('name')
}
}
//如果直接查找setter,获取到的是setter函数执行的结果
//如果通过Object.assign,属性赋值的是setter函数执行返回值
const copyObj = {};
Object.defineProperties(copyObj, Object.getOwnPropertyDescriptors(o))
五、浅克隆并实现原型链继承的方式
Object.create有两个参数,
prototype, 对象原型
desciptors 属性描述对象
新对象属性也是浅拷贝来的
let a = {
set name (val){
console.log(123)
},
obj : {
age:123,
hobby : 'drinking'
}
}
let newA = Object.create(Object.getPrototypeOf(a), Object.getOwnPropertyDescriptors(a));
console.log(newA)