javascript - unexpected - módulo.exportaciones vs exportaciones en Node.js
node js unexpected identifier (20)
por qué ambos se utilizan aquí
Creo que solo quieren dejar en claro que el module.exports
. exports
, exports
y nano
apuntan a la misma función, permitiéndole usar cualquiera de las dos variables para llamar a la función dentro del archivo. nano
proporciona algún contexto a lo que hace la función.
exports
no se exportarán (solo module.exports
hará el module.exports
), entonces, ¿por qué molestarse en sobrescribir eso también?
La compensación de verbosidad limita el riesgo de futuros errores, como el uso de exports
lugar de module.exports
dentro del archivo. También proporciona una aclaración de que el module.exports
y exports
de hecho están apuntando al mismo valor.
module.exports
vs exports
Mientras no reasigne module.exports
o exports
(y en su lugar agregue valores al objeto al que ambos se refieren), no tendrá ningún problema y puede usar las exports
forma segura para ser más conciso.
Al asignar cualquiera de ellos a un no-objeto, ahora están apuntando a diferentes lugares que pueden ser confusos, a menos que intencionalmente desee que el module.exports
sea algo específico (como una función).
Configurar las exports
a un no-objeto no tiene mucho sentido, ya que tendrá que configurar module.exports = exports
al final para poder usarlo en otros archivos.
let module = { exports: {} };
let exports = module.exports;
exports.msg = ''hi'';
console.log(module.exports === exports); // true
exports = ''yo'';
console.log(module.exports === exports); // false
exports = module.exports;
console.log(module.exports === exports); // true
module.exports = ''hello'';
console.log(module.exports === exports); // false
module.exports = exports;
console.log(module.exports === exports); // true
¿Por qué asignar module.exports
a una función?
¡Más conciso! Compara cuánto más corto es el segundo ejemplo:
helloWorld1.js:module.exports.hello = () => console.log(''hello world'');
app1.js: let sayHello = require(''./helloWorld1''); sayHello.hello; // hello world
let sayHello = require(''./helloWorld1''); sayHello.hello; // hello world
module.exports = () => console.log(''hello world'');
app2.js: let sayHello = require(''./helloWorld2''); sayHello; // hello world
let sayHello = require(''./helloWorld2''); sayHello; // hello world
He encontrado el siguiente contrato en un módulo Node.js:
module.exports = exports = nano = function database_module(cfg) {...}
Me pregunto module.exports
las diferencias entre module.exports
exports
y exports
y por qué se utilizan aquí.
JavaScript pasa objetos por copia de una referencia
Es una diferencia sutil que ver con la forma en que los objetos se pasan por referencia en JavaScript.
exports
y module.exports
apuntan al mismo objeto. exports
es una variable y module.exports
es un atributo del objeto de módulo.
Digamos que escribo algo como esto:
exports = {a:1};
module.exports = {b:12};
exports
y module.exports
ahora apuntan a diferentes objetos. La modificación de las exportaciones ya no modifica module.exports.
Cuando la función de importación inspecciona module.exports
se obtiene {b:12}
Tanto el
module.exports
exports
como los deexports
apuntan a la mismafunction database_module(cfg) {...}
.1| var a, b; 2| a = b = function() { console.log("Old"); }; 3| b = function() { console.log("New"); }; 4| 5| a(); // "Old" 6| b(); // "New"
Puede cambiar
b
en la línea 3 aa
, la salida es inversa. La conclusión es:b
son independientes.Entonces
module.exports = exports = nano = function database_module(cfg) {...}
es equivalente a:var f = function database_module(cfg) {...}; module.exports = f; exports = f;
module.js
que lo anterior esmodule.js
, que es requerido porfoo.js
Los beneficios demodule.exports = exports = nano = function database_module(cfg) {...}
están claros ahora:En
foo.js
, dado quemodule.exports
esrequire(''./module.js'')
:var output = require(''./modules.js'')();
En
moduls.js
: puede utilizar lasexports
lugar demodule.exports
.
Por lo tanto, estará contento si tanto las exports
como el module.exports
apuntan a lo mismo.
"Si desea que la raíz de la exportación de su módulo sea una función (como un constructor) o si desea exportar un objeto completo en una asignación en lugar de construirlo una propiedad a la vez, asígnelo a module.exports en lugar de exportaciones ". - http://nodejs.org/api/modules.html
1.exports -> use como utilidad singleton
2. módulo-exportaciones -> utilizar como objetos lógicos como servicio, modelo, etc.
A pesar de que la pregunta ha sido respondida y aceptada hace mucho tiempo, solo quiero compartir mis 2 centavos:
Puedes imaginar que al principio de tu archivo hay algo como (solo para explicación):
var module = new Module(...);
var exports = module.exports;
Entonces, haga lo que haga, tenga en cuenta que el module.exports
y NO exports
se devolverán de su módulo cuando necesite ese módulo de otra parte.
Así que cuando haces algo como:
exports.a = function() {
console.log("a");
}
exports.b = function() {
console.log("b");
}
También está agregando 2 funciones ''a'' y ''b'' al objeto en el que módulo.exporta puntos, por lo que el tipo del resultado devuelto será un object
: { a: [Function], b: [Function] }
Por supuesto, este es el mismo resultado que obtendrá si está utilizando module.exports
en este ejemplo en lugar de las exports
.
Este es el caso en el que desea que sus module.exports se comporten como un contenedor de valores exportados. Mientras que, si solo desea exportar una función de constructor, hay algo que debe saber sobre el uso de module.exports
o exports
(recuerde nuevamente que module.exports se devolverá cuando necesite algo, no exportar).
module.exports = function Something() {
console.log(''bla bla'');
}
Ahora, typeof return results es ''function''
y puede solicitarlo e invocar inmediatamente como:
var x = require(''./file1.js'')();
Porque sobreescribes el resultado que regresa para ser una función.
Sin embargo, usando las exports
no puedes usar algo como:
exports = function Something() {
console.log(''bla bla'');
}
var x = require(''./file1.js'')(); //Error: require is not a function
Debido a que con las exports
, la referencia ya no ''apunta'' al objeto donde module.exports
puntos, por lo que ya no existe una relación entre exports
y module.exports
. En este caso, module.exports aún apunta al objeto vacío {}
que se devolverá.
La respuesta aceptada de otro tema también debería ayudar: ¿Pasa Javascript por referencia?
Aquí está el resultado de
console.log("module:");
console.log(module);
console.log("exports:");
console.log(exports);
console.log("module.exports:");
console.log(module.exports);
También:
if(module.exports === exports){
console.log("YES");
}else{
console.log("NO");
}
//YES
Nota: La especificación CommonJS solo permite el uso de la variable de exportaciones para exponer a los miembros públicos. Por lo tanto, el patrón de exportación nombrado es el único que es realmente compatible con la especificación CommonJS. El uso de module.exports es una extensión proporcionada por Node.js para admitir una gama más amplia de patrones de definición de módulos.
Aquí hay una buena descripción escrita sobre los módulos de nodo en node.js en el libro de acciones de la publicación Manning .
Lo que finalmente se exporta en su aplicación es module.exports.
Las exportaciones se configuran simplemente como una referencia global a module.exports , que inicialmente se define como un objeto vacío al que puede agregar propiedades. Así que exports.myFunc es solo una abreviatura de module.exports.myFunc .
Como resultado, si las exportaciones se configuran como cualquier otra cosa, rompe la referencia entre módulo.exportaciones y exportaciones . Debido a que module.exports es lo que realmente se exporta, las exportaciones ya no funcionarán como se esperaba, ya no hace referencia al módulo .exports . Si desea mantener ese enlace, puede hacer que las exportaciones de referencia de module.exports se realicen de la siguiente manera:
module.exports = exports = db;
Básicamente, la respuesta está en lo que realmente sucede cuando se requiere un módulo a través de require
declaración de require
. Suponiendo que esta es la primera vez que se requiere el módulo.
Por ejemplo:
var x = require(''file1.js'');
contenido de file1.js:
module.exports = ''123'';
Cuando se ejecuta la instrucción anterior, se crea un objeto de Module
. Su función constructora es:
function Module(id, parent) {
this.id = id;
this.exports = {};
this.parent = parent;
if (parent && parent.children) {
parent.children.push(this);
}
this.filename = null;
this.loaded = false;
this.children = [];
}
Como ves, cada objeto de módulo tiene una propiedad con nombre de exports
. Esto es lo que finalmente se devuelve como parte de la require
.
El siguiente paso para requerir es envolver el contenido de file1.js en una función anónima como la siguiente:
(function (exports, require, module, __filename, __dirname) {
//contents from file1.js
module.exports = ''123;
});
Y esta función anónima se invoca de la siguiente manera, el module
aquí se refiere al objeto de Module
creado anteriormente.
(function (exports, require, module, __filename, __dirname) {
//contents from file1.js
module.exports = ''123;
}) (module.exports,require, module, "path_to_file1.js","directory of the file1.js");
Como podemos ver dentro de la función, los argumentos de exports
refieren a module.exports
. En esencia, es una conveniencia proporcionada al programador de módulos.
Sin embargo esta conveniencia debe ser ejercitada con cuidado. En cualquier caso, si intenta asignar un nuevo objeto a las exportaciones, asegúrese de hacerlo de esta manera.
exports = module.exports = {};
Si lo hacemos de la manera incorrecta , module.exports
seguirá apuntando al objeto creado como parte de la instancia del módulo.
exports = {};
Como resultado, agregar algo al objeto de exportaciones anterior no tendrá ningún efecto en el objeto module.exports y nada se exportará ni se devolverá como parte de require.
De los docs
La variable de exportación está disponible dentro del alcance a nivel de archivo de un módulo y se le asigna el valor de module.exports antes de que se evalúe el módulo.
Permite un acceso directo, por lo que module.exports.f = ... puede escribirse de manera más sucinta como exportaciones.f = .... Sin embargo, tenga en cuenta que como cualquier variable, si se asigna un nuevo valor a las exportaciones, es Ya no está vinculado a module.exports:
Es solo una variable que apunta a module.exports.
En el archivo node js module.js se usa para ejecutar el sistema de module.load. Cada vez que el nodo ejecuta un archivo, envuelve el contenido de su archivo js de la siguiente manera
''(function (exports, require, module, __filename, __dirname) {'',+
//your js file content
''/n});''
Debido a este ajuste dentro del código fuente de ur js, puede acceder a las exportaciones, los requisitos, el módulo, etc. Este enfoque se utiliza porque no hay otra forma de escribir las funciones en el archivo js a otro.
luego el nodo ejecuta esta función envuelta usando c ++. en ese momento se rellenará el objeto exportado que haya pasado a esta función.
Puedes ver dentro de esta función los parámetros de exportación y módulo. en realidad las exportaciones es un miembro público de la función constructor de módulos.
mira el siguiente código
Copia este código en b.js
console.log("module is "+Object.prototype.toString.call(module));
console.log("object.keys "+Object.keys(module));
console.log(module.exports);
console.log(exports === module.exports);
console.log("exports is "+Object.prototype.toString.call(exports));
console.log(''----------------------------------------------'');
var foo = require(''a.js'');
console.log("object.keys of foo: "+Object.keys(foo));
console.log(''name is ''+ foo);
foo();
Copia este código a a.js
exports.name = ''hello'';
module.exports.name = ''hi'';
module.exports.age = 23;
module.exports = function(){console.log(''function to module exports'')};
//exports = function(){console.log(''function to export'');}
ahora ejecuta el nodo
esta es la salida
module is [object Object]
object.keys id,exports,parent,filename,loaded,children,paths
{}
true
exportaciones es [objeto objeto]
object.keys of foo: name is function () {console.log (''función a las exportaciones de módulos'')} función a las exportaciones de módulos
ahora elimine la línea comentada en a.js y comente la línea sobre esa línea y elimine la última línea de b.js y ejecute.
en javascript world no puede reasignar el objeto que pasó como parámetro, pero puede cambiar el miembro público de la función cuando el objeto de esa función se establece como un parámetro para otra función
recuerda
use module.exports on y solo si desea obtener una función cuando usa la palabra clave require. en el ejemplo anterior, var foo = require (a.js); Puedes ver que podemos llamar a foo como una función;
así es como lo explica la documentación del nodo "El sistema de Módulo crea el objeto de exportación. A veces esto no es aceptable, muchos quieren que su módulo sea una instancia de alguna clase. Para ello, asigne el objeto de exportación deseado a module.exports".
Esto muestra cómo require()
funciona en su forma más simple, extraído de Eloquent JavaScript
Problema No es posible que un módulo exporte directamente un valor que no sea el objeto de exportación, como una función. Por ejemplo, un módulo podría querer exportar solo el constructor del tipo de objeto que define. En este momento, no puede hacerlo porque require siempre usa el objeto de exports
que crea como el valor exportado.
Solución Proporcione módulos con otra variable, module
, que es un objeto que tiene una propiedad que se exports
. Esta propiedad apunta inicialmente al objeto vacío creado por require pero se puede sobrescribir con otro valor para exportar otra cosa.
function require(name) {
if (name in require.cache)
return require.cache[name];
var code = new Function("exports, module", readFile(name));
var exports = {}, module = {exports: exports};
code(exports, module);
require.cache[name] = module.exports;
return module.exports;
}
require.cache = Object.create(null);
He encontrado este enlace útil para responder a la pregunta anterior.
http://timnew.me/blog/2012/04/20/exports-vs-module-exports-in-node-js/
Para agregar a las otras publicaciones El sistema de módulos en el nodo hace
var exports = module.exports
Antes de ejecutar tu código. Entonces, cuando quieras exportar = foo, probablemente quieras hacer module.exports = exports = foo pero usar exports.foo = foo debería estar bien
Inicialmente, module.exports=exports
, y la función require
devuelve el objeto module.exports
refiere.
si agregamos propiedades al objeto, digamos exports.a=1
, entonces module.exports y exportaciones aún se refieren al mismo objeto. Entonces, si llamamos a require y asignamos el módulo a una variable, entonces la variable tiene una propiedad a y su valor es 1;
Pero si anulamos uno de ellos, por ejemplo, exports=function(){}
, ahora son diferentes : exportaciones se refieren a un nuevo objeto y module.exports se refieren al objeto original. Y si requerimos el archivo, no devolverá el nuevo objeto, ya que module.exports no se refiere al nuevo objeto.
Para mí, seguiré agregando nuevas propiedades, o las anularé a un nuevo objeto. Simplemente anular uno no es correcto. Y tenga en cuenta que module.exports
es el verdadero jefe.
La configuración de module.exports
permite que la función database_module
se llame como una función cuando sea required
. La simple configuración de las exports
no permitiría exportar la función porque el nodo exporta las referencias del objeto module.exports
. El siguiente código no permitiría al usuario llamar a la función.
módulo.js
Lo siguiente no funcionará.
exports = nano = function database_module(cfg) {return;}
Lo siguiente funcionará si se establece module.exports
.
module.exports = exports = nano = function database_module(cfg) {return;}
consola
var func = require(''./module.js'');
// the following line will **work** with module.exports
func();
Básicamente, node.js no exporta el objeto que exports
actualmente las referencias, sino que exporta las propiedades de lo que las exports
originalmente hacen referencia. Aunque Node.js sí exporta las referencias del objeto module.exports
, lo que le permite llamarlo como una función.
2da razón menos importante
Establecen tanto las exports
module.exports
como las exports
para garantizar que las exports
no module.exports
referencia al objeto exportado anterior. Al configurar tanto las exports
como las abreviaturas y evitar posibles errores más adelante en el futuro.
El uso de module.exports.prop = true
exports.prop = true
lugar de module.exports.prop = true
guarda los caracteres y evita la confusión.
Pasé por algunas pruebas y creo que esto puede arrojar algo de luz sobre el tema ...
app.js
:
var ...
, routes = require(''./routes'')
...;
...
console.log(''@routes'', routes);
...
Versiones de /routes/index.js
:
exports = function fn(){}; // outputs "@routes {}"
exports.fn = function fn(){}; // outputs "@routes { fn: [Function: fn] }"
module.exports = function fn(){}; // outputs "@routes function fn(){}"
module.exports.fn = function fn(){}; // outputs "@routes { fn: [Function: fn] }"
Incluso agregué nuevos archivos:
./routes/index.js
:
module.exports = require(''./not-index.js'');
module.exports = require(''./user.js'');
./routes/not-index.js
:
exports = function fn(){};
./routes/user.js
:
exports = function user(){};
Obtenemos la salida "@routes {}"
./routes/index.js
:
module.exports.fn = require(''./not-index.js'');
module.exports.user = require(''./user.js'');
./routes/not-index.js
:
exports = function fn(){};
./routes/user.js
:
exports = function user(){};
Obtenemos la salida "@routes {fn: {}, usuario: {}}"
./routes/index.js
:
module.exports.fn = require(''./not-index.js'');
module.exports.user = require(''./user.js'');
./routes/not-index.js
:
exports.fn = function fn(){};
./routes/user.js
:
exports.user = function user(){};
Obtenemos la salida "@routes {user: [Function: user]}" Si cambiamos user.js
por { ThisLoadedLast: [Function: ThisLoadedLast] }
, obtenemos la salida "@routes {ThisLoadedLast: [Function: ThisLoadedLast]} ".
Pero si modificamos ./routes/index.js
...
./routes/index.js
:
module.exports.fn = require(''./not-index.js'');
module.exports.ThisLoadedLast = require(''./user.js'');
./routes/not-index.js
:
exports.fn = function fn(){};
./routes/user.js
:
exports.ThisLoadedLast = function ThisLoadedLast(){};
... obtenemos "@routes {fn: {fn: [Función: fn]}, ThisLoadedLast: {ThisLoadedLast: [Function: ThisLoadedLast]}}"
Por lo tanto, sugiero usar siempre module.exports
en las definiciones de sus módulos.
No entiendo completamente lo que está pasando internamente con Node, pero comente si puede darle más sentido a esto ya que estoy seguro de que esto ayuda.
- feliz codificacion
Solo hago algunas pruebas, resulta que, dentro del código del módulo de nodejs, debería algo como esto:
var module.exports = {};
var exports = module.exports;
asi que:
1:
exports = function(){}; // this will not work! as it make the exports to some other pointer
module.exports = function(){}; // it works! cause finally nodejs make the module.exports to export.
2:
exports.abc = function(){}; // works!
exports.efg = function(){}; // works!
3: pero, mientras que en este caso
module.exports = function(){}; // from now on we have to using module.exports to attach more stuff to exports.
module.exports.a = ''value a''; // works
exports.b = ''value b''; // the b will nerver be seen cause of the first line of code we have do it before (or later)
Vamos a crear un módulo de 2 maneras:
De una sola mano
var aa = {
a: () => {return ''a''},
b: () => {return ''b''}
}
module.exports = aa;
Segunda vía
exports.a = () => {return ''a'';}
exports.b = () => {return ''b'';}
Y así es como require () integrará el módulo.
Primera forma:
function require(){
module.exports = {};
var exports = module.exports;
var aa = {
a: () => {return ''a''},
b: () => {return ''b''}
}
module.exports = aa;
return module.exports;
}
Segunda vía
function require(){
module.exports = {};
var exports = module.exports;
exports.a = () => {return ''a'';}
exports.b = () => {return ''b'';}
return module.exports;
}
exports
y module.exports
son las mismas a menos que reasigne exports
dentro de su módulo.
La forma más fácil de pensarlo es pensar que esta línea está implícitamente en la parte superior de cada módulo.
var exports = module.exports = {};
Si, dentro de su módulo, reasigna exports
, entonces lo reasigna dentro de su módulo y ya no es igual a module.exports
. Por esta razón, si desea exportar una función, debe hacer:
module.exports = function() { ... }
Si simplemente asignó su function() { ... }
a las exports
, estaría reasignando exports
para que ya no apunten a module.exports
.
Si no quiere referirse a su función por module.exports
cada vez, puede hacer:
module.exports = exports = function() { ... }
Observe que module.exports
es el argumento más a la izquierda.
Adjuntar propiedades a las exports
no es lo mismo, ya que no lo está reasignando. Es por eso que esto funciona.
exports.foo = function() { ... }
var a = {},md={};
// En primer lugar, las exportaciones y module.exports apuntan al mismo objeto vacío
exp = a;//exports =a;
md.exp = a;//module.exports = a;
exp.attr = "change";
console.log(md.exp);//{attr:"change"}
// Si apunta exp a otro objeto en lugar de apuntar, es propiedad de otro objeto. El md.exp estará vacío Objeto {}
var a ={},md={};
exp =a;
md.exp =a;
exp = function(){ console.log(''Do nothing...''); };
console.log(md.exp); //{}