Взломать JS: Мысли о смешивании в некотором объекте в качестве аргументов (или внутренних переменных) для внешних функций (таких как ** kwargs) без использования этого - PullRequest
1 голос
/ 08 февраля 2012

В SO действительно много вопросов, которые кажутся похожими на это, но на самом деле каждый из этих вопросов касается немного разных вещей. И также я знаю, что вещи, которые я описываю, являются хакерским и нерекомендованным способом, но в моем случае это действительно необходимо (размер кода ДЕЙСТВИТЕЛЬНО важен для меня, каждые пять байтов имеют значение):

У меня есть объект, который динамически заполняется некоторыми переменными (я подготавливаю его для внутреннего использования, но он заполняется переменными, определенными пользователем):

var scope = { 'a': 0, 'b': 12, 'c': 64 };

И у меня есть пользовательская анонимная функция, которой нужен прямой доступ к этой области, без использования this (я бы действительно предпочел) , и она определена , а не в мой var -обзор :

function anonymousFunc() { // user don't knows any names of arguments
  console.log(a, b, c); // I expect '0, 12, 64'
}

На самом деле, scope это даже не объект, а сложный массив, в котором хранятся уровни контекстов, так что, по правде говоря, на самом деле это выглядит примерно так: [ { 'a': 0 }, { 'b': 12, 'c': 64 } ], а затем я выбираю уровень для конкретного функция для доступа. И, чтобы быть еще более правдивым, у меня есть несколько подобных объектов, которые можно смешать в область действия функции.

Таким образом, лучший другой способ сделать без взлома (eval или with) (путь ООП), я вижу, это заставить пользователя вести себя так:

(function() {

    function prepareAndCall(f) {
        c = this.ctx[level];
        l = currentLabels();
        m = makeChunk();
        f();
    }

    var c, l, m; 

    // it is injected from user code
    function anonymousFunc() {
        console.log(c.a, c.b, l.g, m.pos);
    }

    prepareAndCall(anonymousFunc);

})();

Но я хочу, чтобы пользователь не думал о том, где ему нужно взять эти переменные. Я могу смешать их в одном объекте, но в моем случае это тоже не очень удобно: большинство этих переменных определяются самим пользователем во внешнем месте, поэтому он ожидает, что они будут находиться непосредственно в его области видимости, и я ' Мне нравится, если он ничего не знает о тех c - m - l переменных, даже если это просто c. Я хочу подражать тому, что у него есть эти переменные на руках. И он знает, что может случайно переопределить их.


Итак, я нашел несколько методов:

One С eval, и требует строкового источника функции

( Upd. , я удалил предыдущий плохой пример после @ Gijs комментировал и обновил его новым )

А второй загрязняет глобальный контекст ( при jsfiddle )

(function(global_ctx) { 

    // here is the user context, variables
    // defined here are accessible to user 

    var __g = global_ctx;
    __g.__test_var = 5;
    if (__test_var !== 5) alert('__g is not global context');

    var __f = (function() {

        // here is the inner context, variables
        // defined here are not accessible to user   

        var scope = [
            { a: 16 },
            { oo: 12 },
            { b: 17, c: 20 } 
        ]; 

        function callUserFunc(f) {
            //console.log('call user func');
            loadVars(__g, 2);
            f();
        }
        // __g.__f = callUserFunc;

        function loadVars(g, level) {
            for (name in scope[level]) {
                g[name] = scope[level][name];
            }
        }

        return callUserFunc;

    })();

    if (typeof scope !== 'undefined') alert('scope is visible, error');
    if (typeof loadVars !== 'undefined') alert('loadVars is visible, error');

    __f(function() { // user function will be inserted here
        if (typeof oo !== 'undefined') alert('user function sees what it must not see');
        alert(b + ', ' + c);
    }); 

})(this);

В результате, я думаю, что это, вероятно, не вопрос, а скорее предмет для обсуждения: действительно ли это плохой способ использования with или eval в данном случае ? Потому что я не знаю другого способа сделать это так.

Связанная литература:

1 Ответ

2 голосов
/ 08 февраля 2012

По сути, вы хотите изменить область, в которой выполняется заданная пользователем функция. Проблема в том, что область действия функции не может быть изменена (в ссылке: «эти объекты области не могут быть напрямую доступны из вашего кода JavaScript»); Вы можете изменить привязку this, используя .call и .apply, но это не то же самое, что изменение области видимости.

Из этого правила есть только три исключения:

  1. Глобальный объект области (в среде браузера, обычно window, или область DOM Worker (self) (!)). Поскольку это глобальная область, вы знаете, где она находится, и вы можете изменить ее, и изменения в ней повлияют на код, который выполняется в той же глобальной области.
  2. Объявление его внутри with блока вне ES5 строгого
  3. Использование eval вне ES5 строго

На самом деле, если пользовательский код не нуждается в доступе к DOM, работники DOM могут помочь. В работнике глобальная область видимости обозначена как self. К сожалению, postMessage поддерживает только строки и JSON-сериализуемые объекты, что означает, что функции отсутствуют. Что означает, что вам все равно придется передать строку, а затем вызвать с ней new Function или eval. Положительным моментом является то, что вы относительно изолированы от всего того, что сгенерированный пользователем код будет портить вашу собственную страницу (конечно, это означает, что вам нужно не доверять всему, что вы получаете в обработчиках onmessage и onerror ...) .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...