JavaScript Proxy

概要: このチュートリアルでは、ES6のJavaScript Proxyオブジェクトについて学習します。

JavaScript Proxyオブジェクトとは

JavaScript Proxyは、別のオブジェクト(ターゲット)をラップし、ターゲットオブジェクトの基本操作をインターセプトするオブジェクトです。

基本操作とは、プロパティのルックアップ、代入、列挙、関数呼び出しなどです。

プロキシオブジェクトの作成

新しいプロキシオブジェクトを作成するには、次の構文を使用します

let proxy = new Proxy(target, handler);
Code language: JavaScript (javascript)

この構文では

  • target – ラップするオブジェクトです。
  • handlertargetの動作を制御するメソッドを含むオブジェクトです。 handlerオブジェクト内のメソッドはトラップと呼ばれます。

簡単なプロキシの例

まず、userというオブジェクトを定義します

const user = {
    firstName: 'John',
    lastName: 'Doe',
    email: '[email protected]',
}
Code language: JavaScript (javascript)

次に、handlerオブジェクトを定義します

const handler = {
    get(target, property) {
        console.log(`Property ${property} has been read.`);
        return target[property];
    }
}
Code language: JavaScript (javascript)

3番目に、proxyオブジェクトを作成します

const proxyUser = new Proxy(user, handler);
Code language: JavaScript (javascript)

proxyUserオブジェクトは、userオブジェクトを使用してデータを格納します。 proxyUserは、userオブジェクトのすべてのプロパティにアクセスできます。

JavaScript Proxy

4番目に、proxyUserオブジェクトを介してuserオブジェクトのfirstNameおよびlastNameプロパティにアクセスします

console.log(proxyUser.firstName);
console.log(proxyUser.lastName);
Code language: CSS (css)

出力

Property firstName has been read.
John
Property lastName has been read.
Doe

proxyUserオブジェクトを介してuserオブジェクトのプロパティにアクセスすると、handlerオブジェクトのget()メソッドが呼び出されます。

5番目に、元のオブジェクトuserを変更すると、変更はproxyUserに反映されます

user.firstName = 'Jane';
console.log(proxyUser.firstName);
Code language: JavaScript (javascript)

出力

Property firstName has been read.
Jane

同様に、proxyUserオブジェクトの変更は、元のオブジェクト(user)に反映されます

proxyUser.lastName = 'William';
console.log(user.lastName);
Code language: JavaScript (javascript)

出力

William    

プロキシのトラップ

get()トラップ

get()トラップは、プロキシオブジェクトを介してtargetオブジェクトのプロパティにアクセスされたときに起動されます。

前の例では、proxyUserオブジェクトによってuserオブジェクトのプロパティにアクセスされると、メッセージが出力されます。

一般的に、プロパティにアクセスされたときにget()トラップでカスタムロジックを開発できます。

たとえば、get()トラップを使用して、ターゲットオブジェクトの計算プロパティを定義できます。 計算プロパティとは、既存のプロパティの値に基づいて値が計算されるプロパティです。

userオブジェクトにはfullNameプロパティがありませんが、get()トラップを使用して、firstNameおよびlastNameプロパティに基づいてfullNameプロパティを作成できます

const user = {
    firstName: 'John',
    lastName: 'Doe'
}

const handler = {
    get(target, property) {
        return property === 'fullName' ?
            `${target.firstName} ${target.lastName}` :
            target[property];
    }
};

const proxyUser = new Proxy(user, handler);

console.log(proxyUser.fullName);
Code language: JavaScript (javascript)

出力

John Doe

set()トラップ

set()トラップは、targetオブジェクトのプロパティが設定されたときの動作を制御します。

ユーザーのageは18歳以上でなければならないとします。 この制約を適用するには、次のようにset()トラップを開発します

const user = {
    firstName: 'John',
    lastName: 'Doe',
    age: 20
}

const handler = {
    set(target, property, value) {
        if (property === 'age') {
            if (typeof value !== 'number') {
                throw new Error('Age must be a number.');
            }
            if (value < 18) {
                throw new Error('The user must be 18 or older.')
            }
        }
        target[property] = value;
    }
};

const proxyUser = new Proxy(user, handler);
Code language: JavaScript (javascript)

まず、ユーザーのageを文字列に設定します

proxyUser.age = 'foo';
Code language: JavaScript (javascript)

出力

Error: Age must be a number.
Code language: JavaScript (javascript)

次に、ユーザーの年齢を16に設定します

proxyUser.age = '16';    
Code language: JavaScript (javascript)

出力

The user must be 18 or older.

3番目に、ユーザーの年齢を21に設定します

proxyUser.age = 21;

エラーは発生しませんでした。

apply()トラップ

handler.apply()メソッドは、関数呼び出しのトラップです。 構文は次のとおりです

let proxy = new Proxy(target, {
    apply: function(target, thisArg, args) {
        //...
    }
});
Code language: JavaScript (javascript)

次の例を参照してください

const user = {
    firstName: 'John',
    lastName: 'Doe'
}

const getFullName = function (user) {
    return `${user.firstName} ${user.lastName}`;
}


const getFullNameProxy = new Proxy(getFullName, {
    apply(target, thisArg, args) {
        return target(...args).toUpperCase();
    }
});

console.log(getFullNameProxy(user)); // 
Code language: JavaScript (javascript)

出力

JOHN DOE

その他のトラップ

以下は、その他のトラップです

  • constructnew演算子の使用をトラップします
  • getPrototypeOf[[GetPrototypeOf]]への内部呼び出しをトラップします
  • setPrototypeOfObject.setPrototypeOfへの呼び出しをトラップします
  • isExtensibleObject.isExtensibleへの呼び出しをトラップします
  • preventExtensionsObject.preventExtensionsへの呼び出しをトラップします
  • getOwnPropertyDescriptorObject.getOwnPropertyDescriptorへの呼び出しをトラップします

このチュートリアルでは、別のオブジェクトをラップしてそのオブジェクトの基本的な動作を変更するために使用されるJavaScript Proxyオブジェクトについて学習しました。

このチュートリアルは役に立ちましたか?