Giới thiệu Javascript Proxy object

132

Bài viết được sự cho phép của tác giả Lưu Bình An

Một object Proxy sẽ bọc một object khác, và can thiệp trước khi truyền xử lý đó xuống object chính chủ, giống như một middleware

let proxy = new Proxy(target, handler)
  • target là object chính chủ
  • handler khai báo các phương thức sẽ bị can thiệp
let target = {}
let proxy = new Proxy(target, {})

proxy.test = 5;
alert(target.test); // 5
alert(proxy.test); // 5

Do không truyền một handler nào, nên test sẽ không thay đổi

  10 câu hỏi javascript để nâng cao trình độ
  10 trình quản lý file hàng đầu trong JavaScript

Xem thêm việc làm JavaScript lương cao trên TopDev

Giờ chúng ta muốn can thiệp vào phương thức get (khi chúng ta gọi object.prop)

let number = [0,1,2]

numbers = new Proxy(numbers, {
    get(target, prop) {
        if (prop in target) {
            return target[prop];
        } else {
            return 0
        }
    }
})

alert(numbers[1]); // 1
alert(numbers[123]); // 0

Ví dụ khác, chúng ta có một dãy số, chỉ cho phép thêm vào kiểu number, nếu cố tình thêm vào một kiểu dữ liệu khác sẽ không thực hiện được và trả về lỗi

let numbers = [];

numbers = new Proxy(numbers,
    set(target, prop, val) {        if (typeof val == 'number') {
            target[prop] = val;
            return true;
        } else {
            // trả về lỗi
            return false;        }
    }
})

numbers.push(1); // ok
numbers.push('test'); // TypeError ('set' on proxy returned false)

Một ứng dụng khác, bảo vệ các thuộc tính internal của một object, ví dụ chúng ta có một số property bắt đầu bằng _, chúng ta không cho phép truy cập các property

let user = {
    name: "John",
    _password: "****"
}

user = new Proxy(user, {
    get(target, prop) {        if(prop.startWith('_')) {
            throw new Error("Access denied");
        }
        let value = target[prop];
        return (typeof value === 'function') ? value.bind(target) : value;
    },
    set(target, prop, val) {        if (prop.startsWith('_')) {
          throw new Error("Access denied");
        } else {
          target[prop] = val;
          return true;
        }
    },
    deleteProperty(target, prop) {        if (prop.startsWith('_')) {
          throw new Error("Access denied");
        } else {
          delete target[prop];
          return true;
        }
    },
    ownKeys(target) {        return Object.keys(target).filter(key => !key.startsWith('_'));
    }
})

alert(user._password); // Error: Access denied
delete user._password; // Error: Access denied

Nếu object của chúng ta là một function thì sao nhỉ?

Ví dụ với hàm delay sau, hàm này cho phép delay thời gian hàm được thực thi bằng setTimeout

function delay(f, ms) {
    return function() {
        setTimeout(() => f.apply(this, arguments), ms)
    };
}

function sayHi(user) {
    alert(`Hello, ${user}!`)
}

sayHi = delay(sayHi, 3000)

sayHi("John");

Chúng ta sẽ có một cách viết khác với Proxy, điểm khác biệt là Proxy sẽ chuyển tiếp luôn tất cả những property khác của function (như namelength)

function delay(f, ms) {
    return new Proxy(f, {
        apply(target, thisArg, args) {            setTimeout(() => target.apply(thisArg, args), ms);
        }
    })
}

function sayHi(user) {
    alert(`Hello, ${user}!`);
}

sayHi = delay(sayHi, 3000);
alert(sayHi.length); // 1sayHi("John");

Chúng đã đề cập đến các phương thức tiền xử lý ownKeysdeletePropertygetsetapply. Ngoài ra nó còn có các phương thức khác các bạn có thể thảm khảo thêm

Ví dụ lấy từ Javascript.info

Bài viết gốc được đăng tải tại vuilaptrinh.com

Có thể bạn quan tâm:

Xem thêm Việc làm IT hấp dẫn trên TopDev