2011-02-14 11 views
11

Simplemente quiero la capacidad de incluir un archivo JS, pero no tenerlo evaluado en el ámbito global.Incluir archivo JS dentro del ámbito privado

He robado over labjs and requirejs, y aunque pueden hacer otras 1000 cosas, parece que tampoco es capaz de resolver este problema.

Soy consciente de que podría envolver el código de foo.js de modo que espere un cierto contexto, y pueda actuar dentro, pero eso no es lo que estoy buscando (tener que alterar los archivos de origen). Más bien, me gustaría que los archivos JS fuente permanezcan como cualquier otro archivo JS que no necesite ningún tipo de metadato o cualquier resolución del contexto de ejecución en tiempo de ejecución mediante el código en el archivo incluido; fuera del archivo incluido, eso está bien.

Algunas demostraciones sencillas para mayor claridad:

/* 
* 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! 

sé que esto probablemente se puede lograr utilizando eval() o creando un new Function con la cadena, pero estoy esperando que hay una solución mejor.

+0

Caja puede valer la pena mirar: https://code.google.com/p/google-caja/ – ide

+2

+1 pregunta interesante, digo ir con eval. Sí eval puede ser peligroso si se usa mal, pero si hace bien el trabajo y le das un buen uso ... – Zevan

Respuesta

1

va a cerrar a cabo esta vieja pregunta, por desgracia no se encontraron soluciones aceptables . Algunas buenas sugerencias, pero todas rompieron los requisitos que tenía. Supongo que puede ser imposible con el conjunto de características actual del idioma.

3

No hay limpia manera de hacer esto sin depender de los archivos de origen incluidos para ajustarse a algún tipo de patrón (No puedo pensar en la posibilidad de inyectar cada archivo en su propio marco flotante, por lo que corro con su propio window, pero no creo que sea ideal).

Eso no significa necesariamente que no pueda lograr el desacoplamiento de los archivos incluidos (sin tener en cuenta el contexto del tiempo de ejecución como usted dice), pero los archivos seguirán teniendo un buen comportamiento.

El sistema CommonJS Module (que RequireJS supports) muestra una forma de lograrlo. Al envolver el código en una función que proporciona un objeto exports, y al asignar todas las propiedades globales (previamente) a este objeto, RequireJS puede devolver este objeto para que lo asigne a cualquier objeto en cualquier ámbito.

Por ejemplo:

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! 

Sí, esto requiere la edición de los archivos de origen, pero todavía proporciona los beneficios que está buscando.

3

No creo que sea posible hacerlo de otra manera que no sea lo que describió usted mismo.

Una solución es ajustar el código en una función del lado del servidor y escribir una función de inclusión que carga el archivo js y responde con el espacio de nombre de la función. Pienso en una solución similar a la función require en node.js.

código envuelta en serverside js secundarios

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

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

}); 

Cliente: uso

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; 

}()); 

Ejemplo:

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

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

Parece que esta es básicamente la misma respuesta que da Box9, ¿no? Sé que ingresas tu respuesta al mismo tiempo, así que no estoy tratando de decir que lo copiaste, pero después de mirar los documentos RequireJS, creo que el código de node.js probablemente proviene del proyecto CommonJS. – ken

+0

Puede ser correcto, pero realmente no soy la persona adecuada para responder eso. Desde que publiqué la publicación, escribí un poco más de implementación del script anterior. Probablemente haya algo que utilizo en proyectos futuros. Puedo publicarlo si sería de interés? –

+0

No, gracias. Mi solución actual es básicamente lo que ya se ha publicado, que incluye el código "incluido" dentro de un código especial. El propósito de esta pregunta era ver si esto podría lograrse sin hacerlo. ¡Gracias de todos modos! – ken

0

El clientside-require package utiliza iframes para contener el alcance del javascript cargado.

Después de cargar el guión a su página:

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

Puede llevar a cabo la funcionalidad que quería de la siguiente manera:

/* 
* 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! 

Tenga en cuenta, ya que los navegadores no permiten la carga sincrónica de los recursos (debido a experiencia de usuario deficiente) cualquier intento de cargar un script externo con javascript será necesariamente asíncrono (y, por lo tanto, utilizar promesas).

A menos que los navegadores permitan la carga sincrónica, este formato será el más cercano a lo que estamos buscando.


Como una ventaja añadida, la funcionalidad require() que que las cargas de secuencia de comandos se pueden utilizar para cargar html, css, json, e incluso node_modules (siempre que los módulos son capaces de trabajar con require() como una promesa).

Cuestiones relacionadas