You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
function Student(name) {
// 构造函数参数初始化属性值,需要注意的是:
// 这个初始化的值没有经过校验,可能会出错
let _name = name;
Object.defineProperty(this, "name", {
get: () => _name,
set: val => _name = val
});
}
const s = new Student("Wango");
// 只能通过setter和getter设置和访问属性
console.log(s.name);
// Wango
s.name = "Tom";
console.log(s.name);
// Tom
// 无法直接访问私有属性
console.log(typeof s._name === "undefined");
// true
// 在类中使用这个方法同样有效
class Student {
constructor(name) {
// 构造函数参数初始化属性值,需要注意的是:
// 这个初始化的值没有经过校验,可能会出错
let _name = name;
Object.defineProperty(this, "name", {
get: () => _name,
set: val => _name = val
});
}
}
const s = new Student("Wango");
console.log(s.name);
// Wango
s.name = "Tom";
console.log(s.name);
// Tom
console.log(typeof s._name === "undefined");
// true
1.2 使用setter和getter校验属性值
function Student() {
// 直接定义初始值,不由外界输入,确保安全
let _age = 0;
Object.defineProperty(this, "age", {
get: () => _age,
set: val => {
// 检查输入是否是整数
if(!Number.isInteger(val)) {
throw new TypeError("Age should be an Integer");
}
_age = val;
}
});
}
const s = new Student();
// 整数类型通过
s.age = 24
console.log(s.age);
// 24
// 字符串类型被拦截
s.age = "25";
// Uncaught TypeError: Age should be an Integer
使用setter还可以跟踪值的变化,提供性能日志,提供值发生变化的提示等
1.3 使用getter和setter定于如何计算属性值
class Student {
constructor() {
// 设置俩个公共属性
this.firstName;
this.lastName;
}
// 对参数分割并单独存放
set fullName(name) {
const segment = name.split(" ");
this.firstName = segment[0];
this.lastName = segment[1];
}
// 拼接两个属性
get fullName() {
return this.firstName + " " + this.lastName;
}
}
const s = new Student();
s.fullName = "Wango Liu";
console.log(s.firstName);
// Wango
console.log(s.lastName);
// Liu
2. 使用代理控制访问
const student = {
name: "Wango",
age: 24
}
// 初始化代理对象
// 第一个参数为目标对象
// 第二个参数为一个对象,其中定义了在对象执行特定行为时触发的函数
const proxy = new Proxy(student, {
// 获取属性时检测是否存在该属性
get: (target, key) => {
return key in target ? target[key] : "This property do not exist.";
},
set: (target, key, value) => {
// 在这里可以进行类型判断、数值追踪等操作
target[key] = value;
}
});
console.log(proxy.name);
// Wango
console.log(proxy.addr);
// This property do not exist.
proxy.addr = "China";
console.log(proxy.addr);
// China
console.log(student.addr);
// China
对象内部的getter和setter作用于某个属性,代理作用于整个代理目标
代理还有很多其他方法,包括但不限于:
调用函数时激活apply
使用new操作时激活construct
读取/写入属性时激活get/set
执行for-in语句时激活enumerate
2.1 使用代理记录日志
// 定义函数为每个参数对象提供代理
function makeLoggable(target) {
// 代理的工作为记录日志
return new Proxy(target, {
set: (target, key, value) => {
console.log(`Writing value: ${value} to ${key}`);
target[key] = value;
},
get: (target, key) => {
console.log(`Reading: ${key}`);
return target[key];
}
});
}
let student = {
name: "Wango",
age: 24
}
student = makeLoggable(student);
console.log(student.name);
// Reading: name
// Wango
student.age = 25;
// Writing value: 25 to age
2.2 使用代理检测性能
function isPrime(num) {
if(num < 2) { return false; }
for(let i = 2; i < num; i++) {
if(num % i === 0) {
return false;
}
}
return true;
}
isPrime = new Proxy(isPrime, {
apply: (target, thisArg, args) => {
// 启动计时器记录时间
console.time("isPrime");
const result = target.apply(thisArg, args);
console.timeEnd("isPrime");
// 要记得储存和返回函数的计算结果
return result;
}
});
isPrime(129982790);
// isPrime: 0.034931640625 ms
2.3 使用代理自动填充属性
function Address() {
return new Proxy({}, {
get: (target, key) => {
// 如果对象不具有该属性就创建该属性
if(!target[key]) {
target[key] = new Address();
}
return target[key];
}
});
}
const addr = new Address();
// 自动创建属性,不会报错
addr.Asia.China.Chongqing = "Hot-pot";
console.log(addr.Asia.China.Chongqing);
// Hot-pot
1. 使用getter和setter控制属性访问
1.1 定义getter和setter
通过对象字面量定义,或在ES6的class中定义
通过内置的Object.defineProperty方法
1.2 使用setter和getter校验属性值
1.3 使用getter和setter定于如何计算属性值
2. 使用代理控制访问
代理还有很多其他方法,包括但不限于:
2.1 使用代理记录日志
2.2 使用代理检测性能
2.3 使用代理自动填充属性
2.4 使用代理实现负数索引
2.5 代理的性能消耗
代理的效率不高,在需要执行多次的代码中需要谨慎使用
The text was updated successfully, but these errors were encountered: