简体   繁体   English

如何获得 JavaScript 代理的目标?

[英]How to get the target of a JavaScript Proxy?

How to access the target (which is myArray ) of myProxy here?如何在这里访问myProxy的目标(即myArray )?

function createProxy() {
  const myArray = [Math.random(), Math.random()];
  return new Proxy(myArray, {});
}

const myProxy = createProxy();

You can make a copy of the data returned by the proxy using Object.assign() :您可以使用Object.assign()代理返回的数据的副本:

const target_copy = Object.assign({}, my_proxy);

This will work for all enumerable own properties existing on the proxy/target.这将适用于代理/目标上存在的所有可枚举自己的属性

There is a clever way to do this - You can add a get trap to the proxy and have it return the target conditionally.有一个聪明的方法可以做到这一点 - 您可以向代理添加一个get陷阱并让它有条件地返回目标 Like so..像这样..

let resolveMode = false;  // Switch that controls if getter returns target or prop. 

function resolve(obj) {
    resolveMode = true;  // Turn on our switch
    let target = obj.anything;  // This gets the target not the prop!
    resolveMode = false;  // Turn off the switch for the getter to behave normally
    return target;  // Return what we got!
}

function createProxy() {
    const myArray = [Math.random(), Math.random()];
    return new Proxy(myArray, {
        get: function(target, prop) {
            if (resolveMode) return target;  // This is where the magic happens!
            else return target[prop];        // This is normal behavior..
        }
    });
}

const myProxy = createProxy();
let target = resolve(myProxy);

Remember that the more lines of code you add to traps, the slower the object's performance gets.请记住,添加到陷阱的代码行越多,对象的性能就越慢。 Hope this helps.希望这可以帮助。

Like the other answers already said a proxy get trap can be an elegant solution.就像已经说过的其他答案一样,代理获取陷阱可能是一个优雅的解决方案。

const IDENTITY = Symbol('proxy_target_identity')
const handler = {
  get: (target, property, receiver) => {
    if (property === IDENTITY) {
      return target
    }
    return Reflect.get(target, property, receiver)
  }
}
function createProxy() {
    const myArray = [Math.random(), Math.random()];
    return new Proxy(myArray, handler);
}
const myProxy = createProxy();
const orignal_target = myProxy[IDENTITY]

This code sample should be quite robust as it:此代码示例应该非常健壮,因为它:

  • avoids property name conflicts by using a Symbol通过使用Symbol避免属性名称冲突
  • covers all get-scenarios by using Reflect.get instead of target[property]通过使用Reflect.get而不是target[property]涵盖所有获取场景
  • WARNING: be careful about prototype-inheritance - in case your proxy ends up being used as a prototype the not_itself_a_proxy[IDENTITY] call will not return not_itself_a_proxy but the "identity" of the prototype!警告:注意原型继承 - 如果您的代理最终被用作原型,则not_itself_a_proxy[IDENTITY]调用将不会返回not_itself_a_proxy而是原型的“身份”!

The other answers gave some good solutions.其他答案给出了一些很好的解决方案。 Here is @Yuci's answer distilled down for classes, in which case, it's as simple as defining an instance variable of some special name.这是@Yuci 为类提炼出来的答案,在这种情况下,它就像定义一些特殊名称的实例变量一样简单。 The Proxy get function returns it, and so does the underlying target. Proxy get 函数返回它,底层目标也是如此。

class Foo {
    constructor() {
        this.__target__ = this;
        return new Proxy(this, {
            get: function (target, name) {
                if (name in target) return target[name];
                // your code here
            }
        });
    }
}

let foo = new Foo();
let target = foo.__target__;
console.log('proxied Foo', foo);
console.log('recovered target', target, target.__target__.__target__);

I find that (using Vue.js where sometimes Proxy objects are involved, eg when watching a component prop) I can obtain the target both if it is an Object and if it is an Array using JSON.stringify :我发现(使用 Vue.js 有时会涉及 Proxy 对象,例如在观看组件道具时)我可以使用JSON.stringify获取目标,如果它是一个对象,如果它是一个数组:

let myTarget = JSON.parse(JSON.stringify(myProxy))

This approach works also with Array targets, whereas Object.assign({}, myProxy) works only if the target is an Object.这种方法也适用于 Array 目标,而Object.assign({}, myProxy)仅适用于目标是 Object 的情况。

But I am very new to JavaScript proxies and my knowledge is limited.但是我对 JavaScript 代理很陌生,而且我的知识有限。 I may not understand the limitations and caveats of this approach.我可能不理解这种方法的局限性和注意事项。 Nevertheless, maybe it helps someone!尽管如此,也许它可以帮助某人!

You can if the target is an object.如果目标是对象,则可以。

You will have to create a function in target to retrieve it, that's all.您必须在 target 中创建一个函数来检索它,仅此而已。

Example:例子:

class AnyClass {
   constructor() {
      this.target = this;

      return new Proxy(this, this);
   }

   get(obj, prop) {
      if (prop in obj)
          return this[prop];

      // your stuff here
   }

   getTarget() {
      return this.target;
   }
}

And then when you call:然后当你打电话时:

let sample = new AnyClass;
console.log(sample.getTarget());

Will return you the target as you expect :)会像你期望的那样返回目标:)

How about adding the following get trap:添加以下获取陷阱如何:

const handler = {
  get: (target, property, receiver) => {
    if (property === 'myTarget') {
      return target
    }
    return target[property]
  }
}

const myArray = [Math.random(), Math.random()];

function createProxy() {
//     const myArray = [Math.random(), Math.random()];
    return new Proxy(myArray, handler);
}

const myProxy = createProxy();

And you can get the target of the proxy by myProxy.myTarget :您可以通过myProxy.myTarget获取代理的myProxy.myTarget

console.log(myProxy.myTarget) // [0.22089416118932403, 0.08429264462405173]
console.log(myArray === myProxy.myTarget) // true

I found a great way to get the original target by defining the getPrototypeOf handler:我找到了一种通过定义getPrototypeOf处理程序来获取原始目标的好方法:

function createProxy() {
  const myArray = [Math.random(), Math.random()];
  return new Proxy(myArray, {
    getPrototypeOf(target) {
      return target;
    }
  });
}

const myProxy = createProxy();
const target = Object.getPrototypeOf(myProxy); // will get the original array

As the proxy contain an object you can also do由于代理包含一个对象,您也可以这样做

Object.keys( my_proxy )

And then it become easy to retrieve thing such as Object.keys( my_proxy ).length然后很容易检索诸如Object.keys( my_proxy ).length

Use a private Symbol to trap a property.使用私有 Symbol 来捕获属性。 Then give a public function to test if the object return true for this Symbol.然后给出一个公共函数来测试对象是否为这个 Symbol 返回 true。

var sym_Test = Symbol('test')
let proxyHandler = {        
    get: function(pValues:any, prop:any, receiver:any){
        if(prop == sym_Test)
            return true;
        
        return getValue(pValues, prop)
    },    
}



export function IsMyProxy(some:any){
    return some[sym_Test]
}

If you are using Vue 3 and dealing with Proxies, Vue provides some methods to help with this:如果您使用 Vue 3 并处理代理,Vue 提供了一些方法来帮助解决这个问题:

import { isProxy, toRaw } from 'vue';

Using these, you can check if an object is a proxy with isProxy , for example:使用这些,您可以使用isProxy检查对象是否是代理,例如:

isProxy(reactiveObjectOrArray) ? 'yup' : 'nope'

And you can extract the raw data using toRaw :您可以使用toRaw提取原始数据:

const rawObjectOrArray = toRaw(reactiveObjectOrArray)

More info on toRaw and isProxy有关toRawisProxy的更多信息

I found Array.from seems work.我发现 Array.from 似乎有效。

function createProxy() {
    const myArray = [Math.random(), Math.random()];
    return new Proxy(myArray, {});
}

const myProxy = createProxy();
const l=Array.from(myProxy)
console.assert(l.every(it=>!isNaN(it)));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM