JS 中的拦截器 Object.defineProperty
使用拦截器定义的对象属性, 在该属性操作(读取或赋值)时, 会拦截这一操作, 执行一个操作, 用于指定数据的读取操作(例如限制数据的赋值)
拦截器也可以给对象声明一个不可枚举或不可删除的属性
Object.defineProperty使用语法
Object.defineProperty(obj, attr, options);
- obj: 操作的对象, 给那个对象声明属性
- attr: 给对象声明的属性的属性名
- options: 配置参数
- value: 属性的值, 一个任意类型的值
- writable: Boolean, 指定属性是否可以使用赋值运算符"="改变属性值(即是否可写), 默认为false, 不可写
- enumerable: Boolean, 指定属性是否可以被枚举, 默认为false, 不可枚举
- configurable: Boolean, 指定属性是否可以被删除, 默认为false, 不可删除
- get: Function, 读取属性值时会调用该函数, 该函数返回值即为属性值
- set: Function, 该属性被赋值时会调用该函数, 接收一个参数, 即赋值语句右边的值, 没有该函数或该函数内不会改变get函数返回结果是, 赋值语句无效
注意: 可以使用 value + writable 定义属性的值和写入状态, 也可以使用 get + set 定义属性的值和写入状态, 但是不能同时使用 vale + writable 和 get + set, 这样会报错
使用示例
定义一个对象obj, 并写入一个属性name, 只定义options中的value, (writable, enumerable, configurable默认为false, 该属性不可写, 不可枚举, 不可删除)
var obj = {}
Object.defineProperty(obj, 'name', {
value: 'eno',
});
console.log('name: ', obj.name); // eno
obj.name = 'zeng'; // 尝试使用赋值语句改变name的值
console.log('name: ', obj.name); // eno, name属性的值没有被改变
// 尝试遍历obj的属性
var arr = [];
for(var key in obj) { // ES6语法, 用于遍历对象
arr.push(obj[key]);
}
console.log('arr: ', arr); // arr为空数组, 证明obj中的属性无法被枚举
delete obj.name;
console.log('name', obj.name); // eno, 属性无法使用delete删除
定义一个对象obj, 并写入一个属性name, 定义name属性可赋值, 可枚举, 可删除
var obj = {}
Object.defineProperty(obj, 'name', {
value: 'eno',
writable: true,
enumerable: true,
configurable: true
});
console.log('name: ', obj.name); // eno
obj.name = 'zeng'; // 尝试使用赋值语句改变name的值
console.log('name: ', obj.name); // zeng, name属性的值被改变
// 尝试遍历obj的属性
var arr = [];
for(var key in obj) {
arr.push(obj[key]);
}
console.log('arr: ', arr); // ['zeng'], 证明obj中的name属性可以被枚举
delete obj.name;
console.log('name', obj.name); // undefined, 属性可以使用delete删除
使用 get 和 set 函数定义一个可读可写属性, 并在读写操作是执行一个打印输出
var obj = {
_name: 'eno'
}
Object.defineProperty(obj, 'name', {
get() {
console.log('读取obj的name属性值');
return obj.name;
},
set(newVal) {
console.log('改变obj的name属性值, 新属性值为: ', newVal);
obj._name = newVal;
}
});
console.log('name: ', obj.name); // eno, 输出eno前会执行get函数中的 console.log 语句
obj.name = 'zeng';
console.log('name: ', obj.name); // zeng, 输出zeng前会依次执行 set 和 get 函数中的 console.log 语句
没有 set 函数, 只有 get 函数, 属性只读
var obj = {
_name: 'eno'
}
Object.defineProperty(obj, 'name', {
get() {
console.log('读取obj的name属性值');
return obj._name;
}
});
console.log('name: ', obj.name); // eno, 输出eno前会执行 get 函数中的 console.log 语句
obj.name = 'zeng';
console.log('name: ', obj.name); // eno, 属性不可写