何がProxyですか

5958 ワード

他のブログを見ていると、栄養のある文章を共有してくれます.
何がProxyですか
通常、JavaScript言語について言及すると、ES 6標準で提供される新しい特性について議論します.本文も例外ではありません.JavaScriptエージェントとその役割について議論しますが、私たちが深く研究する前に、まずProxyの定義を見てみます.
MDNで定義されているのは、プロキシオブジェクトは、基本的な動作を定義するためのカスタム挙動(例えば、属性検索、割当、列挙、関数呼び出しなど)である.
言い換えれば、プロキシオブジェクトは私たちの目標対象の包装器であり、その属性を操作して直接的なアクセスを阻止することができます.実際のコードに適用するのは難しいということが分かります.この概念をよく読むことを奨励します.あなたの観点を変えるかもしれません.
専門用語
ハンドル
罠(traps)を含むプレースホルダの対象です.
traps
属性アクセスの方法を提供します.これはオペレーティングシステムにおけるトラッピング装置の概念と類似している.
タージ
仮想化されたオブジェクトを代行します.(代理人による包装と操作の実際の対象)
本論文では、私はgetsetのトラップのための簡単な使用例を提供します.最後に、APIなどのより複雑な機能をどのように使用するかを考えてみます.
文法と用例
let p = new Proxy(target, handler);
ターゲットと処理プログラムをProxyコンストラクションに伝達して、このようにproxyオブジェクトを作成しました.今はどうやって利用するかを見てみましょう.Proxyのメリットをより明確にするためには、まず、コードがないものを作成する必要があります.
想像してください.いくつかの属性を持つユーザーオブジェクトがあります.もし属性が存在するなら、ユーザー情報を印刷したいです.存在しないなら、例外を捨てればいいです.プロキシオブジェクトを使用しない場合、属性値が存在するかどうかを判断するコードもプリントユーザ情報の関数である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方法を設定した.この方法はブロックとして機能し、値を返す前にまず属性値をチェックします.存在しない場合は異常を投げます.
出力は第一の場合と同じであるが、このときprintUser関数は論理に集中し、メッセージのみを処理する.
セット
エージェントが有用であるかもしれない他の例は、属性値の検証である.この場合、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メソッドを呼び出します.誰も私たちの代理店(ここのappi)から任意の属性を削除することができます.通常は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!'); 
    
    結論
    データをより多く制御する必要がある場合、代理は役に立ちます.制御された規則に従って元のデータへのアクセスを拡張したり、拒否したりすることができます.