HomeLập trìnhJavaScriptCách hoạt động...

Cách hoạt động của đối tượng proxy của JavaScript – Được giải thích bằng các trường hợp sử dụng ví dụ


Trong hướng dẫn này, bạn sẽ tìm hiểu đối tượng proxy là gì, cùng với những hạn chế của nó.

Chúng tôi cũng sẽ xem xét một số trường hợp sử dụng minh họa cách bạn có thể sử dụng các đối tượng proxy để giải quyết các vấn đề khác nhau.

Không chần chừ nữa, chúng ta hãy bắt đầu.

Mục lục

điều kiện tiên quyết

Tôi thực sự khuyên bạn nên xem qua các chủ đề sau để làm theo cùng với hướng dẫn này:

Proxy là gì?

Từ merriam-webster:

Người được ủy quyền có thể đề cập đến một người được ủy quyền hành động thay cho người khác hoặc có thể chỉ định chức năng hoặc quyền hạn phục vụ thay cho người khác.

Vì vậy, người đại diện không là gì khác ngoài người hòa giải nói hoặc hoạt động thay mặt cho bên nhất định.

Về mặt lập trình, từ proxy còn có nghĩa là một thực thể hoạt động thay mặt cho một đối tượng hoặc một hệ thống. Vì chúng ta đã sắp xếp thuật ngữ này, nên hãy hiểu ý nghĩa của nó trong JavaScript.

Trong JavaScript, có một đối tượng đặc biệt được gọi là Proxy. Nó giúp bạn tạo một đối tượng khác thay cho đối tượng ban đầu.

Đối tượng proxy mới này sẽ đóng vai trò trung gian giữa thế giới thực và đối tượng ban đầu. Bằng cách này, chúng ta sẽ có nhiều quyền kiểm soát hơn đối với sự tương tác với đối tượng ban đầu.

Sử dụng proxy là một cách mạnh mẽ để tương tác với đối tượng hơn là tương tác trực tiếp với nó.

Đây là cú pháp để khai báo một đối tượng proxy:

new Proxy(<object>, <handler>)

Các Proxy nhận hai tham số:

  • <object>: Đối tượng cần proxy.
  • <handler>: Một đối tượng xác định danh sách các phương thức có thể bị chặn. Đây cũng được gọi là bẫy.

Hãy cùng xem một ví dụ đơn giản:

const books = {
	"Deep work": "Cal Newport",
	"Atomic Habits": "James Clear"
}
const proxyBooksObj = new Proxy(books, {
	get: (target, key) => {
		console.log(`Fetching book ${key} by ${target[key]}`);
		return target[key];
	}
})

Ở đây chúng tôi muốn chặn get chức năng của đối tượng books để chúng tôi có thể đăng nhập tên sách và tác giả của cuốn sách vào bảng điều khiển.

Để đạt được điều này, chúng tôi đã tạo một đối tượng proxy mới được gọi là proxyBooksObj. Đối tượng này được xây dựng bằng cách sử dụng Proxy chức năng mà chúng ta đã thấy trước đó. phải mất books là đối tượng được ủy quyền và một đối tượng bao gồm các hàm xử lý cần được giữ lại.

Vì chúng ta cần chặn get chức năng, chúng tôi đã thêm một get tài sản chấp nhận một chức năng. Chức năng xử lý này sẽ chấp nhận một chức năng đưa vào target key.

Đây là một ví dụ khá đơn giản về proxy trong JavaScript. Có nhiều trường hợp sử dụng proxy khác nhau – ví dụ: nó có thể giúp xác thực, định dạng, thông báo và gỡ lỗi.

Để tìm hiểu thêm về các trình xử lý/bẫy có sẵn, đây là danh sách.

Bây giờ hãy xem một ví dụ sẽ giúp chúng ta hiểu rõ hơn về cách hoạt động của proxy.

Đọc thêm  Sắp xếp mảng JavaScript – Cách sử dụng các phương thức sắp xếp JS (Có ví dụ về mã)

Cách hạn chế đối tượng có thuộc tính cụ thể

Đôi khi có thể hữu ích khi hạn chế người dùng để họ chỉ có một thuộc tính cụ thể, giống như những gì useRef làm trong React. Nó chỉ cho phép chỉnh sửa current thuộc tính của đối tượng được trả về bởi useRef.

Hãy tạo một chức năng proxy cho phép người dùng chỉ cập nhật current thuộc tính và không cho phép chúng tạo bất kỳ thuộc tính nào khác.

const data = {};

const newProxy = new Proxy(data, {
  set: function (target, key, value) {
    if (key === "current") {
      Reflect.set(target, key, value);
      return true;
    }
    return false;
  }
});

newProxy.current = 1;
newProxy.point = 1; // Throws error

Ở đây, vì chúng ta đang xử lý việc gán một giá trị mới cho một thuộc tính hiện có hoặc tạo một thuộc tính mới, nên chúng ta sử dụng set chức năng bẫy. Chúng ta cần khai thác hành vi bên trong của đối tượng.

Các set chức năng xử lý sẽ đưa vào target, keyvalue trong đó mục tiêu sẽ là đối tượng đích, khóa và giá trị là thuộc tính và giá trị thực.

Chúng tôi đảm bảo rằng chìa khóa là current. Khi có, chúng tôi đặt giá trị cho thuộc tính đó và trả về true.

Điều quan trọng là chúng tôi trở lại true bởi vì chức năng xử lý này dự kiến ​​​​sẽ tuân theo một số bất biến. Nếu chúng ta không muốn đặt giá trị thì chúng ta nên quay lại false.

Ngoài ra còn có một số điều cần lưu ý về mỗi chức năng bẫy có sẵn bên trong proxy là bất biến. Bất biến không là gì ngoài một điều kiện cần được tuân theo bởi mọi chức năng bẫy để chức năng cơ bản không thay đổi.

Trích dẫn từ hướng dẫn lập trình Meta của MDN:

Ngữ nghĩa không thay đổi khi thực hiện các hoạt động tùy chỉnh được gọi là bất biến

Một đường vòng nhỏ – Reflect API là gì?

Chúng tôi cũng có thể sử dụng API Reflect tại đây. JavaScript cung cấp một đối tượng tích hợp sẵn có một tập hợp các chức năng có thể giúp chặn các hoạt động của JavaScript. Đây có thể là các hoạt động như set, get, applyvà như thế.

Để biết thêm về các phương thức mà Reflect API cung cấp, bạn có thể truy cập liên kết sau.

Với API này, việc thao tác với đối tượng mục tiêu có trong proxy thực sự đơn giản. Một sự thật thú vị về Reflect API là nó không phải là một đối tượng có thể được khởi tạo. Tất cả các phương pháp được cung cấp bởi nó là tĩnh.

Trong ví dụ trước, chúng tôi đã cố gắng trả về giá trị hiện có tại thuộc tính của đối tượng một cách trực tiếp bằng cách truy cập vào đối tượng ban đầu như thế này: target[key].

Thay vào đó, ở đây chúng ta có thể sử dụng get phương pháp Phản ánh. Vì vậy, bây giờ ví dụ trên của chúng tôi sẽ giống như thế này:

const books = {
	"Deep work": "Cal Newport",
	"Atomic Habits": "James Clear"
}
const proxyBooksObj = new Proxy(books, {
	get: (target, key) => {
		console.log(`Fetching book ${key} by ${target[key]}`);
		return Reflect.get(target, key);
	}
})

Bây giờ chúng tôi biết rằng chúng tôi có thể sử dụng Reflect, nhưng một câu hỏi đặt ra – tại sao lại sử dụng Reflect?

Đọc thêm  Nguyên mẫu JavaScript và tính kế thừa – và tại sao họ nói mọi thứ trong JS là một đối tượng

Chúng tôi sử dụng Reflect vì nó cho phép chúng tôi triển khai hành vi mặc định của các chức năng đã có trên đối tượng ban đầu. Viết lại theo thuật ngữ kỹ thuật, điều này cho phép chúng tôi triển khai hành vi chuyển tiếp mặc định bên trong các hàm bẫy.

Ngoài ra với Reflect, chúng ta có thể truy cập các chức năng bên trong và áp dụng chúng cho đối tượng được bao bọc bởi proxy.

Vì vậy, việc sử dụng API Reflect bên trong proxy của chúng tôi sẽ có lợi cho chúng tôi.

Cắt mảng như Python

Python là một ngôn ngữ thực sự tuyệt vời. Một tính năng thực sự tuyệt vời mà nó cung cấp là cách bạn có thể cắt các mảng của mình. Ngay cả thư viện NumPy của Python cũng cung cấp tính năng cắt mảng này.

Bạn có thể chỉ cần cung cấp chỉ mục bắt đầu (tùy chọn) và chỉ mục kết thúc (tùy chọn) được phân tách bằng dấu hai chấm. Đây là cú pháp để cắt một mảng trong Python:

arr[<start>:<end>]

Từ cú pháp trên rõ ràng là startend biểu thị startend (độc quyền) vị trí chỉ mục để cắt.

Đây là một ví dụ về cách bạn có thể cắt một mảng trong Python:

data = [1,2,3,4]
print(data[1:3]) # Output: [2, 3]

Đây là cách bạn có thể làm tương tự trong JavaScript:

const data = [1,2,3,4]
console.log(data.slice(1,3)) // Output: [2, 3]

Bạn cần sử dụng slice chức năng cắt lát data mảng từ vị trí chỉ mục 1 đến vị trí chỉ mục 3.

Lưu ý rằng việc cắt một mảng không bao gồm chỉ mục kết thúc được cung cấp trong hàm slice hoặc trong cơ chế cắt của Python.

Sẽ thật tuyệt nếu chúng ta cũng có thể đạt được cơ chế cắt lát của Python trong JavaScript phải không?

Chúng tôi lại có đối tượng Proxy trong JavaScript để giải cứu. Như chúng ta đã thiết lập trong phần trước, proxy là một trình bao bọc xung quanh đối tượng ban đầu. Chúng giúp bạn quản lý tương tác với đối tượng ban đầu.

Hãy tạo lại đối tượng proxy này – nhưng lần này để nó có cơ chế cắt. Dưới đây là mã để triển khai cơ chế cắt trong JavaScript:

const arr = [1,2,3,4];

const arrProxy = new Proxy(arr, {
  get: function (target, key) {
    if (typeof key === "string" && key.includes(":")) {
      let [start, end] = key.split(":");
      if (start === "") {
        start = 0;
      } else if (end === "") {
        end = target.length;
      } else {
        start = parseInt(start, 10);
        end = parseInt(end, 10);
      }

      return Reflect.apply(Array.prototype.slice, target, [start, end]);
    }
    return Reflect.get(target, key);
  }
});

console.log(arrProxy["1:3"]) // [2,3] 

Ok, rất nhiều mã ở đây, nhưng hãy lùi lại một bước và hiểu điều gì đang xảy ra:

  • Chúng tôi đã tạo một cái mới proxy đối tượng trên đầu mảng arr. Vì chúng tôi đang lập kế hoạch để đạt được việc cắt bằng cách cung cấp vị trí bắt đầu và kết thúc được phân tách bằng dấu hai chấm, nên chúng tôi cần thực hiện một số sửa đổi về cách thực hiện chức năng nhận của một mảng.
  • Để làm được điều này, chúng ta sẽ sử dụng get chức năng bẫy sửa đổi cơ chế lấy cho một mảng. Chúng tôi đảm bảo thêm chức năng bẫy này dưới dạng get tài sản bên trong handler đối tượng của Proxy.
  • Hàm get bẫy chấp nhận targetkey như nó lập luận. Chúng tôi sử dụng điều này để viết logic của chúng tôi.
  • Vì chúng tôi đang làm một cái gì đó như thế này arrProxy["1:3"]trong trường hợp này, khóa sẽ thuộc loại chuỗi và nó sẽ bao gồm: trong đó. Điều kiện chính của chúng tôi sẽ là phân biệt trên cùng điều kiện này.
if (typeof key === "string" && key.includes(":")) 

Tiếp theo, chúng tôi viết một số điều kiện là yêu cầu đối với cơ chế cắt lát trong Python. Dưới đây là các yêu cầu:

  • Bất cứ khi nào start chỉ mục không được cung cấp, chúng ta nên đặt start đến 0.
  • Bất cứ khi nào end chỉ mục không được cung cấp, chúng ta nên đặt end theo chiều dài của mảng ban đầu.
  • Nếu cả hai đều được cung cấp, thì chúng tôi chuyển đổi chúng thành số nguyên.
Đọc thêm  JavaScript 日期格式——如何在 JS 中格式化日期

Để làm điều này, chúng ta cần sử dụng hàm slice trong JavaScript.

Chúng tôi sẽ sử dụng phương thức áp dụng của Reflect API để thực thi chức năng slice với bối cảnh này (target) là mảng ban đầu và đối số cho slice chức năng là [start, end].

Cuối cùng, nếu key đối số thuộc bất kỳ loại dữ liệu nào khác ngoài chuỗi, thì chúng tôi trực tiếp trả về mảng với sự trợ giúp của Reflect.get.

Nhược điểm của việc sử dụng proxy

Bây giờ chúng ta biết cách proxy hoạt động cùng với các trường hợp sử dụng của nó. Nhưng điều quan trọng là phải biết một số nhược điểm của việc sử dụng proxy.

Trước hết, mặc dù sử dụng proxy rất tuyệt, nhưng đó thực sự là một lựa chọn tồi tệ trong các tình huống mà hiệu suất là một yếu tố quan trọng.

Thứ hai, chuyển tiếp proxy không hoạt động là cơ chế chuyển tiếp tất cả các chức năng của mục tiêu bằng cách sử dụng proxy. Đây là cách chuyển tiếp proxy trông như thế nào:

const data = {};
const newData = new Proxy(data, {}); // No trap function.
    
data.point = { x: 1, y: 2};
    
console.log(data);

Điều này chỉ hoạt động tốt trên các đối tượng thông thường nhưng sẽ không hoạt động đối với các đối tượng như các nút DOM hoặc các đối tượng có các vị trí bên trong.

Ví dụ: thực hiện thao tác như bên dưới sẽ phát sinh lỗi:

const x = document.createElement("div")
x.className = "hello"
        
const domProxy = new Proxy(x, {});
        
console.log(domProxy.getAttribute("class")); // Throws typeError

Điều này xảy ra bởi vì this giá trị đề cập đến đối tượng proxy thay vì đề cập đến đối tượng ban đầu. Chúng ta có thể giải quyết vấn đề này bằng hàm get bẫy giúp tham chiếu đến đối tượng ban đầu.

const y = new Proxy(x, {
  get(target, key) {
    const value = Reflect.get(target, key);
    if(typeof value === "function"){
      return value.bind(target)
    }
    return value;
  }
});
        
console.log(y.getAttribute("class")); // Output: hello

Tóm lược

Trong bài viết này, chúng ta đã tìm hiểu về proxy trong JavaScript cùng với các trường hợp sử dụng của chúng. Chúng tôi cũng đã xem qua một số nhược điểm của proxy.

Nếu bạn thích ý tưởng sử dụng proxy, thì bạn có thể nâng cấp nó lên và thử sử dụng chúng trong các tình huống xác thực khác nhau hoặc sao chép một số hàm thư viện, chẳng hạn như hàm get và set của lodash.

Đó là tất cả. Cảm ơn vì đã đọc.

theo tôi trên TwitterGitHub và LinkedIn.





Zik.vn – Biên dịch & Biên soạn Lại

spot_img

Create a website from scratch

Just drag and drop elements in a page to get started with Newspaper Theme.

Buy Now ⟶

Bài viết liên quang

DMCA.com Protection Status