一、属性描述符
1.获取对象的属性的描述
- 获取对象的某个属性描述符:Object.getOwnPropertyDescriptor(对象, "对象的某个属性");
const obj = {
uerId: "1001",
name: "张三",
age: 10,
sex: "男",
};
//获取属性描述,参数(对象,对象的某个属性)
const nameDesc = Object.getOwnPropertyDescriptor(obj, "name");
console.log(nameDesc)
//输出:{ value: '张三', writable: true, enumerable: true, configurable: true }
- 获取对象的所有属性描述符Object.getOwnPropertyDescriptors(对象名);
const obj = {
uerId: "1001",
name: "张三",
age: 10,
sex: "男",
};
const allDesc = Object.getOwnPropertyDescriptors(obj);
console.log(allDesc);
//输出所有属性描述符
{
uerId: {
value: '1001',
writable: true,
enumerable: true,
configurable: true
},
name: {
value: '王五',
writable: false,
enumerable: false,
configurable: true
},
age: { value: 10, writable: true, enumerable: true, configurable: true },
sex: { value: '男', writable: true, enumerable: true, configurable: true }
}
2.设置属性描述符
(1) value --- 属性值
const obj = {
uerId: "1001",
name: "张三",
age: 10,
sex: "男",
};
//可以通value属性修改值
Object.defineProperty(obj, "name", {
value: "李四",
});
console.log(obj);
//输出 { uerId: '1001', name: '李四', age: 10, sex: '男' }
(2) writable --- 是否可以修改value的值
- writable 为true --->obj对象的值改为了李四
Object.defineProperty(obj, "name", {
writable: true,//属性值可修改
});
console.log(obj);//{ uerId: '1001', name: '张三', age: 10, sex: '男' }
obj.name = "李四";
console.log(obj); //{ uerId: '1001', name: '李四', age: 10, sex: '男' }
//可以通过修改属性配置从而修改属性值
Object.defineProperty(obj, "name", {
writable: true,
});
obj.name = "李四";
console.log(obj); //{ uerId: '1001', name: '李四', age: 10, sex: '男' }
- writable 为false --->obj对象的值仍然为张三
const obj = {
uerId: "1001",
name: "张三",
age: 10,
sex: "男",
};
Object.defineProperty(obj, "name", {
writable: false,//属性值不可修改
});
console.log(obj); //{ uerId: '1001', name: '张三', age: 10, sex: '男' }
obj.name = "李四";
console.log(obj); //{ uerId: '1001', name: '张三', age: 10, sex: '男' }
(3)enumerable ---该属性是否可被遍历
- enumerable 为true --->obj属性可以被遍历
const obj = {
uerId: "1001",
name: "张三",
age: 10,
sex: "男",
};
//得到一个由对象键名形成的数组
Object.keys(obj) //[ 'uerId', 'name', 'age', 'sex' ]
//依次输出对象键名:uerId,name,age,sex
for (var key in obj) {
console.log(key);
}
- enumerable 为false --->obj属性不可以被遍历
Object.defineProperty(obj, "name", {
enumerable: false,
});
const objKeys = Object.keys(obj);
//没有属性name
console.log(objKeys); //["uerId", "age", "sex"];
////依次输出对象键名:uerId,age,sex
for (var key in obj) {
console.log(key);
}
(4)configurable ---是否可配置
- configurable为true,属性描述符可配置,默认为true
const obj = {
uerId: "1001",
name: "张三",
age: 10,
sex: "男",
};
const nameDesc = Object.getOwnPropertyDescriptor(obj, "name");
console.log(nameDesc);
//输出结果:{ value: '张三', writable: true, enumerable: true, configurable: true }
//设置属性描述符
Object.defineProperty(obj, "name", {
value: "王五",
writable: false,
enumerable: false,
configurable: false,
});
const nameDescChange = Object.getOwnPropertyDescriptor(obj, "name");
console.log(nameDescChange);
//输出结果:{
value: '王五',
writable: false,
enumerable: false,
configurable: false
}
- configurable为false,属性描述符不可配置
const obj = {
uerId: "1001",
name: "张三",
age: 10,
sex: "男",
};
const nameDesc = Object.getOwnPropertyDescriptor(obj, "name");
console.log(nameDesc);
//设置属性描述符
Object.defineProperty(obj, "name", {
configurable: false,
});
Object.defineProperty(obj, "name", {
value: "王五",
writable: true,
enumerable: true,
configurable: true,
});
const nameDescChange = Object.getOwnPropertyDescriptor(obj, "name");
console.log(nameDescChange);
结果会报错
(5)get,set--访问器
var obj = {};
Object.defineProperty(obj, "a", {
//getter读取器
get: function () {
return 123;
},
//setter设置器
set: function (val) {
console.log("hello");
},
});
obj.a = 3 + 2; // 相当于在执行set(3+2)
console.log(obj.a); // 相当于在执行get()
// 输出:先输出hello,在输出123
const g = {
pic: "./assets/g1.png",
title: "椰云拿铁",
desc: `1人份【年度重磅,一口吞云】
√原创椰云topping,绵密轻盈到飞起!
原创瑞幸椰云™工艺,使用椰浆代替常规奶盖
打造丰盈、绵密,如云朵般细腻奶沫体验
椰香清甜饱满,一口滑入口腔
【饮用建议】请注意不要用吸管,不要搅拌哦~`,
sellNumber: 200,
favorRate: 95,
price: 32,
};
class UIData {
constructor(g) {
Object.defineProperty(this, "data", {
get: function () {
return g;
},
set: function () {
throw new Error("只读属性不能赋值");
},
configurable: false,
});
let internalChooseValue = 0;
Object.defineProperty(this, "choose", {
get: function () {
return internalChooseValue;
},
set: function (val) {
if (typeof val !== "number") {
throw new Error("choose类型必须是数字");
} else if (parseInt(val) !== val) {
throw new Error("choose类型必须整数");
}
},
configurable: false,
});
//获取总价
// Object.defineProperty(this, "totalPrice", {
// get: function () {
// return this.choose * this.data.price;
// },
// });
}
//获取总价第二种方式,更简洁
get totalPrice() {
return this.choose * this.data.price;
}
get isChoose() {
return this.choose > 0;
}
}
const ui = new UIData(g);
// ui.data = 123;
// console.log(ui.data);
ui.choose = 3;
console.log(ui.isChoose);
3.限制对象修改的方法
(1) 放扩展:Object.preventExtensions()---> 防添加
(2)密封: Object.seal() --->防添加,防删除
(3) 冻结:Object.freeze() --->防添加,防删除,防修改
const g = {
pic: "./assets/g1.png",
title: "椰云拿铁",
desc: `1人份【年度重磅,一口吞云】
√原创椰云topping,绵密轻盈到飞起!
原创瑞幸椰云™工艺,使用椰浆代替常规奶盖
打造丰盈、绵密,如云朵般细腻奶沫体验
椰香清甜饱满,一口滑入口腔
【饮用建议】请注意不要用吸管,不要搅拌哦~`,
sellNumber: 200,
favorRate: 95,
price: 32,
};
class UIData {
constructor(g) {
// Object.seal(g); //密封后,不能添加属性,但能修改属性
// Object.freeze(g);//冻结后不能添加和修改属性
g = { ...g }; //克隆对象
Object.defineProperty(this, "data", {
get: function () {
return g;
},
set: function () {
throw new Error("只读属性不能赋值");
},
configurable: false,
});
let internalChooseValue = 0;
Object.defineProperty(this, "choose", {
get: function () {
return internalChooseValue;
},
set: function (val) {
if (typeof val !== "number") {
throw new Error("choose类型必须是数字");
} else if (parseInt(val) !== val) {
throw new Error("choose类型必须整数");
}
},
configurable: false,
});
Object.freeze(this);
//获取总价
// Object.defineProperty(this, "totalPrice", {
// get: function () {
// return this.choose * this.data.price;
// },
// });
}
//获取总价第二种方式,更简洁
get totalPrice() {
return this.choose * this.data.price;
}
get isChoose() {
return this.choose > 0;
}
}
const ui = new UIData(g);
// ui.data.name = "abc"; //使用seal或freeze后,不能添加属性
ui.data.price = 900; //使用seal可以修改值,使用freeze不能修改值
console.log(ui.data);