【訳】Proxyとその利点


劉小夕
テキストリンク:https://devinduct.com/blogpos...
Proxyとは
通常、JavaScript言語については、ES 6規格が提供する新しい特性について議論しますが、本明細書も例外ではありません.JavaScriptエージェントとその役割について議論しますが、深く研究する前に、Proxyの定義を見てみましょう.
MDNの定義は、プロキシオブジェクトが基本操作を定義するためのカスタム動作(たとえば、属性検索、割り当て、列挙、関数呼び出しなど)です.
すなわち、エージェントオブジェクトはターゲットオブジェクトのパッケージであり、そのプロパティを操作し、直接アクセスを阻止することができます.実際のコードに適用するのは難しいことに気づくかもしれませんが、この概念をよく読むことを奨励します.それはあなたの観点を変える可能性があります.
用語
handler
トラップを含むプレースホルダオブジェクト.
traps
プロパティ・アクセスの方法を指定します.これは、オペレーティングシステムのキャプチャの概念に似ています.
target
エージェント仮想化されたオブジェクト.(エージェントオブジェクトによってラッピングおよび操作される実際のオブジェクト)
本明細書では、getおよびsetトラップの簡単な例を提供し、最後に、APIのようなより複雑な機能を含むそれらをどのように使用するかを考慮する.
構文と使用例
let p = new Proxy(target, handler);

ターゲットおよびプロセッサをProxyコンストラクタに渡し、proxyオブジェクトを作成します.では、それをどのように利用するかを見てみましょう.Proxyのメリットをより明確に見るためには、まず、それがないコードを書く必要があります.
想像してみてください.いくつかの属性を持つユーザーオブジェクトがあります.属性が存在する場合は、ユーザー情報を印刷したいと思っています.存在しない場合は、例外を放出します.エージェントオブジェクトを使用しない場合、属性値が存在するか否かを判断するコードは、次のdemoに示すように、ユーザ情報を印刷する関数であるprintUserにも置かれる.
let user = {
    name: 'John',
    surname: 'Doe'
};

let printUser = (property) => {
    let value = user[property];
    if (!value) {
        throw new Error(`The property [${property}] does not exist`);
    } else {
        console.log(`The user ${property} is ${value}`);
    }
}

printUser('name'); //   : 'The user name is John'
printUser('email'); //     : The property [email] does not exist

get
上記のコードを表示すると、条件と例外を他の場所に移動し、printUserではユーザー情報を表示する実際の論理だけに注目するとより良いことがわかります.これはエージェントオブジェクトを使用できる場所です.この例を更新しましょう.
let user = {
    name: 'John',
    surname: 'Doe'
};

let proxy = new Proxy(user, {
    get(target, property) {
        let value = target[property];
        if (!value) {
            throw new Error(`The property [${property}] does not exist`);
        }
        return value;
    }
});

let printUser = (property) => {
    console.log(`The user ${property} is ${proxy[property]}`);
};

printUser('name'); //   : 'The user name is John'
printUser('email'); //     : The property [email] does not exist

上記の例では、userオブジェクトをパッケージし、getメソッドを設定した.このメソッドはブロッキングとして機能し、値を返す前にプロパティ値を最初にチェックし、存在しない場合は例外を放出します.
出力は第1の場合と同じであるが、printUser関数は論理に専念し、メッセージのみを処理する.
set
エージェントが役立つ別の例は、属性値の検証です.この場合、setメソッドを使用して検証する必要があります.たとえば、ターゲットタイプを確保する必要がある場合、これは非常に有用なフックです.実際の使用方法を見てみましょう.
let user = new Proxy({}, {
    set(target, property, value) {
        if (property === 'name' && Object.prototype.toString.call(value) !== '[object String]') { //     string   
            throw new Error(`The value for [${property}] must be a string`);
        };
        target[property] = value;
    }
});

user.name = 1; //     : The value for [name] must be a string

これらはかなり簡単な例で、以下のシーンではproxyが役に立ちます.
  • フォーマット
  • 価値とタイプ修正
  • データバインディング
  • デバッグ
  • ...

  • より複雑な例を作成する時だ.
    エージェントを持つAPI-より複雑な例
    簡単な例の知識を使用することで、アプリケーションで使用するためのAPIパッケージを作成できます.現在、getおよびpostリクエストのみがサポートされていますが、容易に拡張できます.コードは以下の通りです.
    const api = new Proxy({}, {
        get(target, key, context) {
            return target[key] || ['get', 'post'].reduce((acc, key) => {
                acc[key] = (config, data) => {
    
                    if (!config && !config.url || config.url === '') throw new Error('Url cannot be empty.');
                    let isPost = key === 'post';
    
                    if (isPost && !data) throw new Error('Please provide data in JSON format when using POST request.');
    
                    config.headers = isPost ? Object.assign(config.headers || {}, { 'content-type': 'application/json;chartset=utf8' }) :
                        config.headers;
    
                    return new Promise((resolve, reject) => {
                        let xhr = new XMLHttpRequest();
                        xhr.open(key, config.url);
                        if (config.headers) {
                            Object.keys(config.headers).forEach((header) => {
                                xhr.setRequestHeader(header, config.headers[header]);
                            });
                        }
                        xhr.onload = () => (xhr.status === 200 ? resolve : reject)(xhr);
                        xhr.onerror = () => reject(xhr);
                        xhr.send(isPost ? JSON.stringify(data) : null);
                    });
                };
                return acc;
            }, target)[key];
        },
        set() {
            throw new Error('API methods are readonly');
        },
        deleteProperty() {
            throw new Error('API methods cannot be deleted!');
        }
    });

    簡単な実装を説明しましょう.setdeletePropertyです.保護レベルを追加し、任意のAPIプロパティに新しい値を設定しようとするたびに、例外が放出されることを確認しました.
    属性を削除しようとするたびにdeletePropertyメソッドが呼び出されます.通常、APIメソッドを失いたくないため、エージェント(ここのapi)からプロパティを削除できる人がいないことを確認できます.getはここでとても面白くて、いくつかのことをしました.targetは空のオブジェクトであり、getメソッドは、apiが初めて使用されたときにすべてのメソッド(現在のgetおよびpostリクエストなど)を作成し、reduceコールバックでは、提供された構成に基づいてAPI仕様の検証およびチェックを実行します.この例では、データを提供せずに空のURLとパブリッシュリクエストを許可しません.これらのチェックは拡張と修正が可能ですが、重要なのは私たちがこの場所で集中的に処理するしかないことです.reduceは、最初のAPI呼び出し時にのみ完了し、その後、reduceプロセス全体をスキップし、getはデフォルトの動作のみを実行し、属性値、すなわちAPIプロセッサを返す.各プロセッサは、要求を作成してサービスを呼び出すPromiseオブジェクトを返します.
    次の操作を行います.
    api.get({
        url: 'my-url'
    }).then((xhr) => {
        alert('Success');
    }, (xhr) => {
        alert('Fail');
    });
    delete api.get; //throw new Error('API methods cannot be deleted!'); 

    結論
    データをより多く制御する必要がある場合は、エージェントが役立ちます.制御されたルールに基づいて元のデータへのアクセスを拡張または拒否することで、オブジェクトを監視し、正しい動作を確保できます.
    この文章が好きなら、私の公衆番号に注目してください.以下のコメントセクションであなたの考えを伝えることができます.
    皆さん、貴重な時間をかけて本を読んでくれてありがとう.もしこの本があなたに少し助けたり啓発したりしたら、あなたの称賛とスターをけちけちしないでください.あなたのは私の前進の最大の原動力に違いありません.https://github.com/YvetteLau/...
    本人の公衆番号に注目することを推薦します