把原始数据作为属性值传入新对象中,发生原始数据修改丢失的问题怎么办?
- 应该使用Object.defineProperty()设置该属性
- 用Object.defineProperty()设置的属性,默认writable、enumerable、configurable均为false
- 并且自定义提醒该属性设置了不可重写
let obj = {
a: 1
};
for (const key in obj) {
console.log(key);
}
let keys = Object.keys(obj);
console.log(keys);
let desc = Object.getOwnPropertyDescriptor(obj, 'a');
console.log(desc);
描述a:
值为1,可重写,可遍历
得到属性描述符
Object.getOwnPropertyDescriptor(obj, 'a');
重设属性描述符
Object.defineProperty(obj, 'a', { })
value: 23, //内容
writable: false, //不可重写
enumerable: false, //不可遍历
configurable: false //属性描述符本身可不可以重复修改
// 重新设置属性描述符
Object.defineProperty(obj, 'a', {
value: 23,
writable: false, //不可重写
enumerable: false, //不可遍历
configurable: false //属性描述符本身可不可以重复修改
})
/* 以下是无效的修改,因为上面的configurable: false */
Object.defineProperty(obj, 'a', {
value: 23,
writable: false, //不可重写
})
obj.a = 10;
console.log(obj.a);
getter读取器
读取属性值
setter设置器
属性值重新赋值,有一个形参
合称访问器
设置了get和set函数后,将来读取这个属性时,他不会去内存中找,而是运行get函数
get函数里是什么,属性值输出就是什么
Object.defineProperty()定义的属性,属性值被修改时实际上在执行什么代码?
let obj = {};
Object.defineProperty(obj, 'a', {
get: function () {
console.log('hello');
return 2
},
set: function (val) {
console.log('你好');
}
})
// obj.a = 10;
obj.a = 3 - 2; // set(3-2)
console.log(obj.a); // console.log(get())
输出结果:你好 hello 2
这里定义了一个空对象,用 defineProperty 定义了一个属性 a
obj.a = 3 - 2; 这句话意思是在重新赋值,所以属性值改变的时候,是调用set函数
console.log(obj.a); 得到属性 a 的值,其实就是读取属性值,调用get函数
利用set函数限定原始数据的属性不可重写
let obj = {
pic: './assets/g1.png',
title: '椰云拿铁',
desc: `1人份【年度重磅,一口吞云】`,
choose: 0,
sellNumber: 200,
favorRate: 95,
price: 32,
}
class UIGoods {
constructor(g) {
// this.data = g;
Object.defineProperty(this, 'data', {
get: function () {
return g;
},
set: function () {
throw new Error('data属性时是只读的,不能赋值和修改!')
},
configurable: false,
})
}
}
const g = new UIGoods(obj);
g.data = 'ab';
console.log(g.data);
利用set函数限定数值类型的属性,设置中间变量,判断它的值和类型
let internalChooseValue = 0;
Object.defineProperty(this, 'choose', {
get: function () {
return internalChooseValue;
},
set: function (val) {
if (typeof val !== 'number') {
throw new Error(`choose属性必须是数字!`);
}
let temp = parseInt(val);
if (temp !== val) {
throw new Error(`choose属性必须是整数!`);
}
if(val < 0) {
throw new Error(`choose属性必须大于等于0!`);
}
internalChooseValue = val;
},
configurable: false
})
利用get函数限定总价
Object.defineProperty(this, 'totalPrice', {
get: function () {
return this.choose * this.data.price;
}
})
er6语法糖简写,和constructor同级
get totalPrice () {
return this.choose * this.data.price;
}
利用get函数限定设置isChoose
get isChoose () {
return this.choose > 0;
}
Object.freeze()冻结原始数据的克隆版,让它的属性值也不能修改
尽量不要直接修改原始数据
避免新加属性进去 Object.freeze(this);
在最后冻结自己,可以防止新加属性改变数据,但是其他普通属性就不能改了
要使其他普通属性可修改,将freeze换成seal
这样使其他普通属性可修改,原始数据不可修改