Подтвердить что ты не робот

Как проверить, является ли объект прокси?

Я хотел бы проверить, является ли объект JavaScript Proxy. Тривиальный подход

if (obj instanceof Proxy) ...

здесь не работает и не пересекает цепочку прототипов для Proxy.prototype, так как все соответствующие операции эффективно поддерживаются основной целью.

Можно ли проверить, является ли произвольный объект прокси?

4b9b3361

Ответ 1

В моем текущем проекте мне также нужен способ определения, если что-то уже было прокси, главным образом потому, что я не хотел запускать прокси-сервер на прокси-сервере. Для этого я просто добавил getter к моему обработчику, который вернет true, если запрошенная переменная была "__Proxy":

function _observe(obj) {
  if (obj.__isProxy === undefined) {
    var ret = new Proxy(obj || {}, {
      set: (target, key, value) => {
        /// act on the change
        return true;
      },
      get: (target, key) => {
        if (key !== "__isProxy") {
          return target[key];
        }

        return true;
      }
    });
    return ret;
  }

  return obj;
}

Ответ 2

Из http://www.2ality.com/2014/12/es6-proxies.html:

Невозможно определить, является ли объект прокси-сервером или нет (прозрачная виртуализация).

Ответ 3

В Node.js 10 вы можете использовать util.types.isProxy.

Например:

const target = {};
const proxy = new Proxy(target, {});
util.types.isProxy(target);  // Returns false
util.types.isProxy(proxy);  // Returns true

Ответ 4

Лучший способ, который я нашел, - создать слабый набор прокси-объектов. Вы можете сделать это рекурсивно, когда создаете и проверяете свои проксированные объекты.

    var myProxySet = new WeakSet();
    var myObj = new Proxy({},myValidator);
    myProxySet.add(myObj);

    if(myProxySet.has(myObj)) {
        // Working with a proxy object.
    }

Ответ 5

Фактически, есть обходной путь для определения, является ли объект прокси, который основан на нескольких предположениях. Во-первых, определение прокси может быть легко решено для среды node.js помощью расширений C++ или привилегированной веб-страницы в браузере, когда страница может запускать незащищенные расширения. Во-вторых, Proxy - это относительно новая функциональность, поэтому она не существует в старых браузерах, поэтому решение работает только в современных браузерах.

Движок JS не может клонировать функции (поскольку у них есть привязки к контексту активации и некоторым другим причинам), но объект Proxy по определению состоит из обработчиков обертки. Таким образом, чтобы определить, является ли объект прокси-сервером, достаточно инициировать принудительное клонирование объекта. Это можно сделать с помощью функции postMessage.

Если объект является прокси, он не сможет скопировать, даже если он не содержит никаких функций. Например, Edge и Chrome выдают следующие ошибки при попытке опубликовать объект Proxy: [object DOMException]: {code: 25, message: "DataCloneError", name: "DataCloneError"} и не Failed to execute 'postMessage' on 'Window': [object Object] could not be cloned. ,

Ответ 6

Создайте новый символ:

let isProxy = Symbol("isProxy")

Внутри метода get вашего обработчика прокси вы можете проверить, является ли key вашим символом, а затем return true:

get(target, key)
{
    if (key === isProxy)
        return true;

    // normal get handler code here
}

Затем вы можете проверить, является ли объект одним из ваших прокси, используя следующий код:

if (myObject[isProxy]) ...

Ответ 7

Кажется, что нет стандартного способа, но для привилегированного кода Firefox вы можете использовать

Components.utils.isProxy(object);

Например:

Components.utils.isProxy([]); // false
Components.utils.isProxy(new Proxy([], {})); // true

Ответ 8

 class MyProxy{
    constructor(target,desc,self=this){
            var 
            old_get=('get' in desc)?desc.get:function(target,prop){return target[prop];},
            old_has=('has' in desc)?desc.has:function(target,prop){ return (prop in target);};
        desc.get=function(target,prop){


            if(prop=='getOwnPrototypeOf'){
                return function() {
                    return Object.getPrototypeOf(self); 
                    /* //if "getOwnPrototypeOf" is defined in "target", then do not override it.
                        if('getOwnPrototypeOf' in target){ //if "target" is MyProxy object.
                            return target.getOwnPrototypeOf();
                        } else{
                            return Object.getPrototypeOf(self);
                        }
                    */
                }
            } else if(prop=='getOwnProxyObjectOf') {
                return function(){
                    return self;
                }
            }
          return old_get(target,prop);
        }
        desc.has=function (target,prop){
            if(prop=='getOwnPrototypeOf'|| prop=='getOwnProxyObjectOf'){
                return true;
            } 
            return old_has(target,prop);
        }
        return new Proxy(target,desc);
    }
}

// Exemple
class AsdProxy{
    constructor(target,desc,self=this){
        self=this;
        return new MyProxy(target,desc,self);
    }

}
class AsdProxy2{
    constructor(target,desc,self=this){
        return new MyProxy(target,desc,self);
    }

}
class AsdProxy3 {
    constructor(target,desc,self=this){
        return new AsdProxy2(target,desc,self);
    }

}

ss=new MyProxy({},{});
console.log('getOwnPrototypeOf' in ss && MyProxy.prototype===ss.getOwnPrototypeOf());//true
console.log(ss.getOwnProxyObjectOf() instanceof MyProxy); //true

asd=new AsdProxy({},{});
asd2=new AsdProxy2({},{});
asd3 = new AsdProxy3({},{});
console.log(asd2.getOwnProxyObjectOf() instanceof MyProxy);// false
console.log(asd2.getOwnProxyObjectOf() instanceof AsdProxy);//false
console.log(asd2.getOwnProxyObjectOf() instanceof AsdProxy2); //true
console.log(asd3.getOwnProxyObjectOf() instanceof AsdProxy2);// false
console.log(asd3.getOwnProxyObjectOf() instanceof AsdProxy3); // true

Ответ 9

Мэтью Бричачек и Дэвид Калланан дают хорошие ответы на Proxy, который вы создаете сами, но если это не так, вот некоторые дополнения

Представьте, что у вас есть внешняя функция создания прокси, которую вы не можете изменить

const external_script = ()=>{
    return new Proxy({a:5},{})
}

Перед выполнением любого внешнего кода мы можем переопределить прокси-конструктор и использовать WeakSet для хранения прокси, как это делает Мэтью Бричачек. Я не использую класс, потому что в противном случае у Прокси будет прототип, и будет обнаружено, что Прокси был изменен.

const proxy_set = new WeakSet()
window.Proxy = new Proxy(Proxy,{
      construct(target, args) {
        const proxy = new target(...args)
        proxy_set.add(proxy)
        return proxy
      }
})
const a = external_script()
console.log(proxy_set.has(a)) //true

Тот же метод, но с символом, как Дэвид Калланан

  const is_proxy = Symbol('is_proxy')
  const old_Proxy = Proxy
  const handler = {
    has (target, key) {
      return (is_proxy === key) || (key in target)
    }
  }
  window.Proxy = new Proxy(Proxy,{
      construct(target, args) {
          return new old_Proxy(new target(...args), handler)
      }
  })
  const a = external_script()
  console.log(is_proxy in a) //true

Я думаю, что первое лучше, потому что вы изменяете только конструктор, а второе создает прокси прокси, в то время как цель вопроса состояла в том, чтобы избежать этого.

Это не работает, если прокси создается внутри iframe, потому что мы переопределили прокси только для текущего кадра.

Ответ 10

Я считаю, что нашел более безопасный способ проверить, является ли предмет прокси-сервером. Этот ответ был вдохновлен ответом Xabre.

function getProxy(target, property) {
    if (property === Symbol.for("__isProxy")) return true;
    if (property === Symbol.for("__target")) return target;
    return target[property];
}

function setProxy(target, property, value) {
    if (property === Symbol.for("__isProxy")) throw new Error("You cannot set the value of '__isProxy'");
    if (property === Symbol.for("__target")) throw new Error("You cannot set the value of '__target'");
    if (target[property !== value]) target[property] = value;
    return true;
}

function isProxy(proxy) {
    return proxy == null ? false : !!proxy[Symbol.for("__isProxy")];
}

function getTarget(proxy) {
    return isProxy(proxy) ? proxy[Symbol.for("__target")] : proxy;
}

function updateProxy(values, property) {
    values[property] = new Proxy(getTarget(values[property]), {
        set: setProxy,
        get: getProxy
    });
}

По сути, я вместо того, чтобы добавить поле __isProxy к цели, я добавил эту проверку: if (property === Symbol.for("__isProxy")) return true; в получателе прокси. Таким образом, если вы используете цикл for-in или Object.keys или Object.hasOwnProperty, __isProxy не будет существовать.

К сожалению, даже если вы можете установить значение __isProxy, вы никогда не сможете получить его из-за проверки на получателе. Поэтому вы должны выдать ошибку, когда поле будет установлено.

Вы также можете использовать Symbol чтобы проверить, является ли переменная прокси, если вы думаете, что, скорее всего, вы захотите использовать __isProxy в качестве другого свойства.

Наконец, я также добавил аналогичную функциональность для цели прокси, которую также довольно сложно получить.

Ответ 11

Существует два способа проксирования объекта. Один из них - new Proxy, другой - Proxy.revocable. Мы можем следить за ними, чтобы прокси-объект записывался в секретный список. Затем мы определяем, что объект является прокси-объектом, проверяя, он существует в секретном списке.

Чтобы заглянуть в функции, мы можем написать обертку или использовать встроенный прокси. Последнее означает, что для прочтения идеи использовать прокси-сервер для прокси-сервера new Proxy, а также Proxy.recovable, здесь fiddle.

Для обслуживания старого прокси-API, такого как прокси nodejs-v5.8.0, мы можем применить ту же идею, используя Proxy.createFunction to proxy Proxy.create и Proxy.createFunction.

Ответ 12

или

class MyProxy{
    constructor(target,desc,self=this){

        var getMyProxyObject=Symbol.for('getMyProxyObject'), old_get=('get' in desc)?desc.get:function(target,prop){return target[prop];}
        desc.get=function(target,prop){
            if(prop===getMyProxyObject){
                return self;
            }
            return old_get(target,prop);
        }
        return new Proxy(target,desc);
    }

}


class NewProxy extends MyProxy {
    constructor(target,desc){
        return super(target,desc);
    }
}
var getMyProxyObject=Symbol.for('getMyProxyObject'),
    asd=new MyProxy({},{}),
    bsd=new NewProxy({},{});
console.log(asd[getMyProxyObject] instanceof MyProxy); // true
console.log(bsd[getMyProxyObject] instanceof MyProxy); // true
console.log(bsd[getMyProxyObject] instanceof NewProxy); // true
console.log(NewProxy.prototype.isPrototypeOf(bsd[getMyProxyObject])); //true
console.log(MyProxy.prototype.isPrototypeOf(bsd[getMyProxyObject])); //true