ホームページ  >  記事  >  ウェブフロントエンド  >  Vue を知らなくても大丈夫ですが、Proxy の使用方法は知っておく必要があります。

Vue を知らなくても大丈夫ですが、Proxy の使用方法は知っておく必要があります。

藏色散人
藏色散人転載
2023-04-14 17:23:301703ブラウズ

この記事を書こうと思ったのは数か月前ですが、このナレッジポイントを思いついたとき、VueJs はよく使われており、私は React です。 開発者。または、別のフレームワークを選択するように求められたら、angular を選択するかもしれませんが、最近 NestJs を学習していて、Reflect# であることに気づきました。 ## は、次のように最下層で広く使用されています:

Vue を知らなくても大丈夫ですが、Proxy の使用方法は知っておく必要があります。## さて、今日この記事を書いた理由を説明します。この記事は

Object に基づいています。

-> Proxy -> Reflect は順番に説明しますので、すぐに覚えてください! Object

In

ES5

、次のコードに示すように、オブジェクトを定義し、そのオブジェクトに対して操作 (追加または検索) を実行できます。 <pre class="brush:php;toolbar:false">const moment = { age: 18, address: &quot;西安&quot;, }; moment[&quot;hobby&quot;] = &quot;basketball&quot;; moment.hight = 1.59; console.log(moment.age); // 18</pre> したがって、オブジェクトを監視したい場合は、次のようになります。このオブジェクトのプロパティを監視できます。設定または取得のプロセスで、

Attribute Descriptor

に保存された属性を通じてこの機能を実現できます。 属性記述子

ES5

では、すべての属性に属性記述子があり、具体的な使用方法は次の図に示すとおりです。 ##上の図に示すように、この通常のオブジェクト プロパティに対応するプロパティ記述子は 18

だけでなく、他の 3 つの特性も含まれています。

##writableVue を知らなくても大丈夫ですが、Proxy の使用方法は知っておく必要があります。;

enumerable;

  • configurable;
  • 通常の住宅タイプの場合、プロパティ記述子はデフォルト値を使用します。Object.defineProperty(...) を使用して、新しいプロパティを追加したり、既存のプロパティを変更したりできます (属性 ## の値が変更された場合) #Configurable
  • true) で特性を設定します。詳細は次のコードに示されています。
    const moment = {
      age: 18,
      address: "西安",
    };
    
    Object.defineProperty(moment, "address", {
      value: "肇庆",
      writable: true,
      configurable: true,
      enumerable: true,
    });
    
    console.log(moment.address); // 肇庆
  • このメソッドは 3 つのパラメーターを受け取ります。

属性を定義するオブジェクト;定義または変更する属性の名前、または シンボル;

定義または変更する属性 記述子;

    Getter と Setter
  • これまでに非常に多くの基本的なことについて説明しましたが、プロパティの変更を受け取る方法についてはまだ説明していません。ここでは、プロパティ記述子
  • Object .defineProperty には、set
  • get
  • という 2 つのプロパティが用意されています。これら 2 つのプロパティの使用法は次のとおりです:
const moment = {
  age: 18,
  address: "西安",
};

Object.keys(moment).forEach((key) => {
  let value = moment[key];
  Object.defineProperty(moment, key, {
    get: function () {
      console.log(`监听到了对象的 ${key} 属性被访问了`);
      return value;
    },

    set: function (params) {
      console.log(`监听到了对象的 ${key} 属性被修改了`);
      value = params;
    },
  });
});

moment.age = 22;
const foo = moment.address;

When 値を割り当てるとき

moment.age

に対して、set 属性のメソッドを呼び出します。最終的に出力は オブジェクトの年齢属性が変更されましたになります。

moment.address

の値を取得すると、get 属性のメソッドが呼び出され、最終的に出力は The address 属性になります。オブジェクトの監視対象です。 を訪問しました。 これら 2 つの方法は実行できますが、属性の追加や属性のフェードアウトなど、よりリッチな操作を監視する場合は実行できません。

Object.defineProperty(. ..)## を使用します。 # それはできません

最終結果は上の図に示すとおりで、ターミナルの出力は、上の丸で囲ったコードの実行に対応します。 そこで、

Proxy

の登場により、この問題点は非常によく解決されます。 Proxy

Vue を知らなくても大丈夫ですが、Proxy の使用方法は知っておく必要があります。ES6

では、新しい

Proxy

クラスが追加されました。このクラスは名前からわかり、私たちを助けるために使用されます。プロキシを作成します。これは、ユーザーが作成した特別なオブジェクトです。別の通常のオブジェクトまたはこの通常のオブジェクトの前にあるブロックをカプセル化します。たとえば、オブジェクトを変更する場合、主に次のフローチャートがあります:

#あなたの操作を妨害するレベルのようなものです。

このクラスの基本的な使用法は次のとおりです。

const moment = {
  age: 18,
  address: "西安",
};

const proxy = new Proxy(moment, {});

console.log(proxy); // { age: 18, address: &#39;西安&#39; }
同じオブジェクトを返しますが、メモリ アドレスが異なるため、厳密な等価比較によって返される値は # であることがわかります。 # #間違い###。 Peoxy のキャプチャーラー 13 種類

PeoxyVue を知らなくても大丈夫ですが、Proxy の使用方法は知っておく必要があります。 キャプチャーラーは全部で 13 種類ありますが、よく使われるものはごく一部ですので、詳しく説明します。

MDN 公式 Web サイト

早速、コードに直接進みましょう:

const moment = {
  age: 18,
  address: "西安",
};

function foo(x, y) {
  return x + y;
}

const proxy = new Proxy(moment, {
  has: function (target, prop) {
    console.log(`使用 in 访问了 ${prop} 是否存在于 moment 对象`);
  },
  get: function (target, property, receiver) {
    console.log(`通过读取 moment 对象中的 ${property} 属性`);
  },
  set: function (target, property, value, receiver) {
    console.log(`通过设置 moment 对象中的 ${property} 属性为 ${value}`);
  },
});

const fProxy = new Proxy(foo, {
  apply: function (target, _, params) {
    return target(...params) * 10;
  },
  construct: function (target, argumentsList, newTarget) {
    console.log(target); // [Function: foo]
    console.log(argumentsList); // [ 1, 2 ]
    console.log(newTarget); // [Function: foo]
    return {};
  },
});

"age" in proxy; // 使用 in 访问了 age 是否存在于 moment 对象
proxy.age; // 通过读取 moment 对象中的 age 属性
proxy.address = "肇庆"; // 通过设置 moment 对象中的 address 属性为 肇庆

console.log(foo(1, 2)); // 3
console.log(fProxy(1, 2)); // 30

new fProxy(1, 2);

上記のコードでは、 target = == moment

receiver === proxy

はすべて

true

を返します。これは、target が変更対象のオブジェクトに対応し、receiver を意味します。

Proxy

または

Proxy

を継承するオブジェクトです。 <p>操作 <code>Proxy 的同时会修改 moment 对象。

可取消代理

普通对象总是陷入到目标对象,并且在创建之后不能改变,只要还保持着对这个代理的引用,代理的机制就将维持下去。

但是可能会存在这样的情况,比如你想要创建一个在你想要停止它作为代理时便可被停用的代理,解决的方案是创建可取消代理,具体代码如下所示:

const moment = {
  age: 18,
  address: "西安",
};

const { proxy, revoke } = Proxy.revocable(moment, {
  get: function (target, key, receiver) {
    console.log("get 捕获器");
  },
});

proxy.address;
revoke();
proxy.address;

最终的输出如下图所示:

Vue を知らなくても大丈夫ですが、Proxy の使用方法は知っておく必要があります。

一旦可取消代理被取消,任何对他的访问都会抛出 TypeError 错误。

Proxy的问题与不足

尽管现在 Proxy 已经做得很好了,但是在某些情况下,代理也不能与现在的 ECMAScript 机制很好地协同。

Proxy中的this

Peoxy 潜在的一个问题来源是 this 值,我们知道方法中的 this 通常执行调用这个方法的对象,具体代码如下所示:

const target = {
  moment() {
    return this === proxy;
  },
};

const proxy = new Proxy(target, {});

console.log(target.moment()); // false
console.log(proxy.moment()); // true

按照正常的理解这是没有问题的调用 Proxy 上的任何方法,而这个方法进而又会调用另一个方法,实际上都会调用 Proxy 内部的方法,这是符合预期的行为,但是,如果目标对象依赖于对象表示,那就可能碰到意料之外的问题。

举个例子:

const wm = new WeakMap();

class User {
  constructor(userId) {
    wm.set(this, userId);
  }

  set id(userId) {
    wm.set(this, userId);
  }
  get id() {
    return wm.get(this);
  }
}

由于这个实现依赖 User 实例的对象标识,在这个实例被代理的情况下就会出现问题:

const user = new User(1);
console.log(user.id); // 1

const proxy = new Proxy(user, {});
console.log(proxy.id); // undefined

这是因为 User 实例一开始使用目标对象作为 WeakMap 的键,代理对象却尝试从自身取得这个实例,要解决这个问题,就需要重新设置代理,把代理 User 实例改为代理 User 类本身,之后再创建代理的实例就会创建代理实例作为 WeakMap 的键了:

const UserProcess = new Proxy(User, {});
const proxy = new UserProcess(1);
console.log(proxy.id); // 1

Proxy与内部槽位

代理与内置引用类型的实例通常可以很好地协同,但有些 ECMAScript 内置类型可能会依赖代理无法控制的机制,结果导致在代理上调用某些方法会出错,具体代码如下所示:

const target = new Date();

const proxy = new Proxy(target, {});

console.log(proxy instanceof Date); // true
proxy.getDate(); // TypeError: this is not a Date object.

在上面的代码中,根据 ECMAScript 规范,Date 类型方法的执行依赖 this 值上的内部曹伟 [[NumberDate]],代理对象上不存在这个内部槽位,而且这个内部槽位的值也不能通过普通的 get()set() 操作访问到,于是代理拦截后本应该转发给目标对象的方法会抛出 TypeRrror 的错误。

这篇文章到此结束,下一篇将会详细讲解 Reflect,敬请期待。

以上がVue を知らなくても大丈夫ですが、Proxy の使用方法は知っておく必要があります。の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はjuejin.imで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。