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

Включить JS файл в закрытой области

Я просто хочу включить JS файл, но не оценивать его в глобальной области.

Я просмотрел labjs и requirejs, и хотя они могут делать 1000 других вещей, похоже, что они не могут решить эту проблему.

Мне известно, что я могу обернуть код foo.js таким образом, чтобы он ожидал определенный контекст и мог действовать внутри, но это не то, что я ищу (нужно изменить исходные файлы). Скорее, я хотел бы, чтобы исходные JS файлы оставались как любой другой JS файл, который не нуждается в каких-либо метаданных или каком-либо разрешении контекста исполнения во время выполнения через код во включенном файле; вне включенного файла, это нормально.

Некоторые простые демонстрации для ясности:

/*
 * Example 1 - apply to current context
 */
function x() {  
    include('foo.js'); // provides foo()
    foo(); // ok!
}
foo(); // not ok!


/*
 * Example 2 - apply to namespace context
 */
include.apply(ns, ['foo.js']); // provides foo()
ns.foo(); // ok!
foo(); // not ok!

Я знаю, что это может быть достигнуто с помощью eval() или путем создания new Function со строкой, но я надеюсь, что есть лучшее решение.

4b9b3361

Ответ 1

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

Ответ 2

Нет чистого способа сделать это, не полагаясь на включенные исходные файлы, чтобы они соответствовали некоторому шаблону (я могу думать о возможности ввода каждого файла в свой собственный iframe, поэтому они запускаются со своим собственным window, но я не думаю, что этот идеал).

Это не обязательно означает, что вы не можете добиться развязки включенных файлов (без понимания контекста среды выполнения, как вы говорите), но файлы все равно должны быть хорошо себя вести.

Система CommonJS Module (которая RequireJS поддерживает) показывает один из способов достижения этой цели. Обертывая код в функции, предоставляющей объект exports, и назначая все (ранее) глобальные свойства этому объекту, RequireJS может затем вернуть этот объект для назначения любому объекту в любой области.

Например:

function x() {  
    var foo = require('foo.js').foo; // provides foo()
    foo(); // ok!
}
foo(); // not ok!

var ns = require('foo.js');
ns.foo(); // ok!
foo(); // not ok!

Да, это требует редактирования исходных файлов, но оно по-прежнему обеспечивает преимущества, которые вы после.

Ответ 3

Я не думаю, что это можно сделать иначе, чем то, что вы наметили сами.

Одним из решений является обертка кода в функции на стороне сервера и запись функции include, которая загружает js файл и отвечает пространством имен функции. Я думаю о решении, аналогичном требуемой функции в node.js.

Обернутый код на серверах

require.response('foo', function(exports) {

    // Content in foo.js
    exports.a = function() { return 'A'; }
    this.b = function() { return 'B'; }
    function c() { return 'c'); }

});

Клиентская сторона js:

window['require'] = (function() {

    var list = {};
    function require(name, cb) {
        if (list[name]) {
            if (list[name].ns) {
                cb(list[name].ns);
            }
            else {
                list[name].cb.push(cb);
            }
        }
        else {
            list[name] = {cb: [cb]};

            // Code to load js file

        }
    }

    require.response = function(name, func) {
        var ns = {};
        list[name].ns = ns;
        func.call(ns);
        for(var i = 0, l = list[name].cb; i < l; i++) {
            list[name].cb[i](ns);
        }
    }

    return require;

}());

Пример использования:

require('foo', function(foo) {
    foo.a(); // ok
    foo.b(); // ok
    foo.c(); // error
};

foo.a(); // error
this.a(); // error
c(); // error

Ответ 4

clientside-require package использует iframe, чтобы содержать область загруженного javascript.

После загрузки script на вашу страницу:

<script src = "path/to/clientside-require/src/index.js"></script>

Вы можете выполнить требуемую функциональность следующим образом:

/*
 * Example 1 - apply to current context
 */
require("foo.js")
  .then((foo)=>{
     foo(); // ok
  })
foo(); // not ok


/*
 * Example 2 - apply to namespace context
 */
var promise_foo_attached = require("foo.js")
  .then((foo)=>{
    window.ns.foo = foo; // provides foo to ns
  })

// then, as long as promise_foo_attached has resolved:
ns.foo(); // ok!
foo(); // not ok!

Обратите внимание: поскольку браузеры не позволяют синхронную загрузку ресурсов (из-за плохой работы с пользователем), любая попытка загрузки внешнего script с помощью javascript обязательно будет асинхронной (и, следовательно, использовать promises).

Если браузер не поддерживает синхронную загрузку, этот формат будет самым близким к тому, что мы ищем.


В качестве дополнительного бонуса функциональность require(), которая загружает script, может использоваться для загрузки html, css, json и даже node_modules (до тех пор, пока модули способны работая с require() в качестве обещания).