Proxy Pattern trong Javascript
Dinh Vo
Posted on July 30, 2022
Với một Proxy object, chúng ta có quyền kiểm soát các tương tác với một object nhất định, ví dụ: getting một value hoặc setting một value.
Hãy tạo một object person
, đại diện là John Doe.
const person = {
name: "John Doe",
age: 42,
nationality: "American"
};
Thay vì tương tác trực tiếp với object này, tôi muốn tương tác với một proxy object
. Trong javascript, tôi có thể tạo một proxy bằng cách sử dụng từ khóa new Proxy
const person = {
name: "John Doe",
age: 42,
nationality: "American"
};
const personProxy = new Proxy(person, {});
Argument thứ 2 của proxy là một object đại diện được gọi là handler
. Trong handler object, tôi có thể xác định các hành vi cụ thể dựa trên loại tương tác. Mặc dù có nhiều methods mà tôi có thể thêm vào Proxy handler, 2 method phổ biến nhất là get
và set
:
-
get
: được gọi khi cố gắng access một property -
set
được gọi khi muốn modify một property Quy trình sẽ xảy ra như xau: Thay vì tương tác trực tiếp với object person, tôi sẽ tương tác vớipersonProxy
. Hãy thêm các handlers vào proxyHandler. Khi muốn modify một property, do đó gọi methodset
trên proxy, tôi muốn proxy in value cũ và value mới, sau đó thực hiện ghi đè value của property. Khi cố gắng access một property, hãy gọi methodget
trên Proxy, tôi muốn proxy ghi lại một contains chứa key và value của property.
const personProxy = new Proxy(person, {
get: (obj, prop) => {
console.log(`The value of ${prop} is ${obj[prop]}`);
},
set: (obj, prop, value) => {
console.log(`Changed ${prop} from ${obj[prop]} to ${value}`);
obj[prop] = value;
}
});
Tuyệt hãy xem đoạn code dưới dây, điều gì sẽ xảy ra?
const person = {
name: "John Doe",
age: 42,
nationality: "American"
};
const personProxy = new Proxy(person, {
get: (obj, prop) => {
console.log(`The value of ${prop} is ${obj[prop]}`);
},
set: (obj, prop, value) => {
console.log(`Changed ${prop} from ${obj[prop]} to ${value}`);
obj[prop] = value;
return true;
}
});
personProxy.name; //The value of name is John Doe
personProxy.age = 43; //Changed age from 42 to 43
Khi access name
, proxy trả về một câu: The value of name is John Doe
khi modify age
, proxy in Changed age from 42 to 43
Ngoài ra có thể bắt các validation của method proxy
const personProxy = new Proxy(person, {
get: (obj, prop) => {
if (!obj[prop]) {
console.log(
`Hmm.. this property doesn't seem to exist on the target object`
);
} else {
console.log(`The value of ${prop} is ${obj[prop]}`);
}
},
set: (obj, prop, value) => {
if (prop === "age" && typeof value !== "number") {
console.log(`Sorry, you can only pass numeric values for age.`);
} else if (prop === "name" && value.length < 2) {
console.log(`You need to provide a valid name.`);
} else {
console.log(`Changed ${prop} from ${obj[prop]} to ${value}.`);
obj[prop] = value;
}
}
});
Hãy xem đoạn code dưới dây, điều gì sẽ xảy ra?
const person = {
name: "John Doe",
age: 42,
nationality: "American"
};
const personProxy = new Proxy(person, {
get: (obj, prop) => {
if (!obj[prop]) {
console.log(`Hmm.. this property doesn't seem to exist`);
} else {
console.log(`The value of ${prop} is ${obj[prop]}`);
}
},
set: (obj, prop, value) => {
if (prop === "age" && typeof value !== "number") {
console.log(`Sorry, you can only pass numeric values for age.`);
} else if (prop === "name" && value.length < 2) {
console.log(`You need to provide a valid name.`);
} else {
console.log(`Changed ${prop} from ${obj[prop]} to ${value}.`);
obj[prop] = value;
}
return true;
}
});
personProxy.nonExistentProperty; //Hmm.. this property doesn't seem to exist
personProxy.age = "44"; //Sorry, you can only pass numeric values for age.
personProxy.name = ""; //You need to provide a valid name.
Proxy made sure tôi không sủa đổi object person với các value không hợp lệ, điều này giúp tôi giữ cho dữ liệu của tôi tinh khiết(data pure)
Reflect
Js cung cấp một object gọi là Reflect
, giúp tôi thao tác với đối tượng đích dễ dàng hơn khi làm việc với proxy.
Trước đây, tôi muốn modify và acces property trên một object bên trong proxy thông qua get
, set
bằng ky hiệu {}. Thay vào đó, tôi có thể sử dụng Reflect. Methods trên Reflect có cùng tên với các methods trên object đang xử lý.
Thay vì access property thông qua obj[prop]
, tôi có thể access hoặc modify property thông qua Reflect.get()
và Reflect.set()
. Các methods nhận các arguments dưới dạng methods trên handle obejct.
const personProxy = new Proxy(person, {
get: (obj, prop) => {
console.log(`The value of ${prop} is ${Reflect.get(obj, prop)}`);
},
set: (obj, prop, value) => {
console.log(`Changed ${prop} from ${obj[prop]} to ${value}`);
Reflect.set(obj, prop, value);
}
});
Hãy xem đoạn code dưới dây:
const person = {
name: "John Doe",
age: 42,
nationality: "American"
};
const personProxy = new Proxy(person, {
get: (obj, prop) => {
console.log(`The value of ${prop} is ${Reflect.get(obj, prop)}`);
},
set: (obj, prop, value) => {
console.log(`Changed ${prop} from ${obj[prop]} to ${value}`);
return Reflect.set(obj, prop, value);
}
});
personProxy.name; //The value of name is John Doe
personProxy.age = 43; //The value of name is John Doe
personProxy.name = "Jane Doe"; //The value of name is John Doe
Proxy là một cách hiệu quả để control các behavior của một object. Một proxy có thể có nhiều use-cases: nó giúp validation, formatting, notifications, hoặc debugging.
Việc lạm dụng proxy hoặc thực hiện các thao tác nặng trên mỗi handler method có thể ảnh hưởng đến performance của app. Tốt nhất cũng không nên sử dụng proxy cho các đoạn code quan trọng về hiệu suất.
Posted on July 30, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.