在Node.js,如何从我的其他文件中“包含”函数?

假设我有一个名为app.js.的文件非常简单:

var express = require('express');var app = express.createServer();app.set('views', __dirname + '/views');app.set('view engine', 'ejs');app.get('/', function(req, res){res.render('index', {locals: {title: 'NowJS + Express Example'}});});
app.listen(8080);

如果我在“tools.js”中有一个函数怎么办?我如何导入它们以在apps.js?

或者……我应该把“工具”变成一个模块,然后需要它吗?<<似乎很难,我宁愿做tools.js文件的基本导入。

1059526 次浏览

你可以把你的函数放在全局变量中,但更好的做法是把你的工具脚本变成一个模块。这真的不太难——只需将你的公共API附加到exports对象。看看理解Node.js导出模块了解更多细节。

你可以要求任何js文件,你只需要声明你想要公开的内容。

// tools.js// ========module.exports = {foo: function () {// whatever},bar: function () {// whatever}};
var zemba = function () {}

在您的应用程序文件中:

// app.js// ======var tools = require('./tools');console.log(typeof tools.foo); // => 'function'console.log(typeof tools.bar); // => 'function'console.log(typeof tools.zemba); // => undefined

如果,尽管有所有其他答案,你仍然想传统上包括一个文件在一个node.js的源文件,你可以使用:

var fs = require('fs');
// file is included here:eval(fs.readFileSync('tools.js')+'');
  • 空字符串连接+''是作为字符串而不是对象获取文件内容所必需的(如果您愿意,也可以使用.toString())。
  • 不能在函数内部使用,并且在全局范围内调用必须,否则将无法访问任何函数或变量(即您不能创建include()实用函数或类似的东西)。

请注意,在大多数情况下,这是不好的做法,您应该改为编写一个模块。然而,在极少数情况下,您真正想要的是本地上下文/命名空间的污染。

更新2015-08-06

还请注意,这不适用于"use strict";(当您在“严格模式”时),因为“导入”文件无法访问中的函数和变量定义由导入的代码执行。严格模式强制执行由较新版本的语言标准定义的一些规则。这可能是这里描述的解决方案避免的另一个原因。

Udo G.说:

  • 不能在函数内部使用ava(),必须在函数内部调用全局范围,否则不会有函数或变量可访问的(即您不能创建包含()实用函数或类似的东西)。

他是对的,但是有一种方法可以从函数中影响全局范围。改进他的例子:

function include(file_) {with (global) {eval(fs.readFileSync(file_) + '');};};
include('somefile_with_some_declarations.js');
// the declarations are now accessible here.

希望,这有帮助。

Node.js中的vm模块提供了在当前上下文(包括全局对象)中执行JavaScript代码的能力。

请注意,从今天开始,vm模块中有一个bug可以防止runInThisContext在从新上下文调用时执行正确的操作。只有当您的主程序在新上下文中执行代码然后该代码调用runInThisContext时,这才重要。请参阅https://github.com/joyent/node/issues/898

可悲的是,Fernando建议的with(全局)方法不适用于命名函数,例如“函数foo(){}”

简而言之,这是一个适用于我的包含()函数:

function include(path) {var code = fs.readFileSync(path, 'utf-8');vm.runInThisContext(code, path);}

这是我迄今为止创造的最好的方式。

var fs = require('fs'),includedFiles_ = {};
global.include = function (fileName) {var sys = require('sys');sys.puts('Loading file: ' + fileName);var ev = require(fileName);for (var prop in ev) {global[prop] = ev[prop];}includedFiles_[fileName] = true;};
global.includeOnce = function (fileName) {if (!includedFiles_[fileName]) {include(fileName);}};
global.includeFolderOnce = function (folder) {var file, fileName,sys = require('sys'),files = fs.readdirSync(folder);
var getFileName = function(str) {var splited = str.split('.');splited.pop();return splited.join('.');},getExtension = function(str) {var splited = str.split('.');return splited[splited.length - 1];};
for (var i = 0; i < files.length; i++) {file = files[i];if (getExtension(file) === 'js') {fileName = getFileName(file);try {includeOnce(folder + '/' + file);} catch (err) {// if (ext.vars) {//   console.log(ext.vars.dump(err));// } else {sys.puts(err);// }}}}};
includeFolderOnce('./extensions');includeOnce('./bin/Lara.js');
var lara = new Lara();

您仍然需要通知您要导出的内容

includeOnce('./bin/WebServer.js');
function Lara() {this.webServer = new WebServer();this.webServer.start();}
Lara.prototype.webServer = null;
module.exports.Lara = Lara;

我还在寻找NodeJS的“包含”函数,我检查了udog提出的解决方案-请参阅消息https://stackoverflow.com/a/8744519/2979590。他的代码不适用于我包含的JS文件。最后我这样解决了问题:

var fs = require("fs");
function read(f) {return fs.readFileSync(f).toString();}function include(f) {eval.apply(global, [read(f)]);}
include('somefile_with_some_declarations.js');

当然,这有帮助。

这里有一个简单明了的解释:

Server.js内容:

// Include the public functions from 'helpers.js'var helpers = require('./helpers');
// Let's assume this is the data which comes from the database or somewhere elsevar databaseName = 'Walter';var databaseSurname = 'Heisenberg';
// Use the function from 'helpers.js' in the main file, which is server.jsvar fullname = helpers.concatenateNames(databaseName, databaseSurname);

Helpers.js内容:

// 'module.exports' is a node.JS specific feature, it does not work with regular JavaScriptmodule.exports ={// This is the function which will be called in the main file, which is server.js// The parameters 'name' and 'surname' will be provided inside the function// when the function is called in the main file.// Example: concatenameNames('John,'Doe');concatenateNames: function (name, surname){var wholeName = name + " " + surname;
return wholeName;},
sampleFunctionTwo: function (){
}};
// Private variables and functions which will not be accessible outside this filevar privateFunction = function (){};

您不需要新功能或新模块。如果你不想使用命名空间,你只需要执行你正在调用的模块。

在tools.js

module.exports = function() {this.sum = function(a,b) { return a+b };this.multiply = function(a,b) { return a*b };//etc}

在app.js

或者在任何其他. js中,如myController.js:

而不是

var tools = require('tools.js')这迫使我们使用命名空间并调用像tools.sum(1,2);这样的工具

我们可以简单地称之为

require('tools.js')();

然后

sum(1,2);

在我的情况下,我有一个带有控制器ctrls.js的文件

module.exports = function() {this.Categories = require('categories.js');}

我可以在每个上下文中使用Categories作为require('ctrls.js')()之后的公共类

包含文件并在给定(非全局)上下文中运行它

fileToInclude.js

define({"data": "XYZ"});

main.js

var fs = require("fs");var vm = require("vm");
function include(path, context) {var code = fs.readFileSync(path, 'utf-8');vm.runInContext(code, vm.createContext(context));}

// Include file
var customContext = {"define": function (data) {console.log(data);}};include('./fileToInclude.js', customContext);

假设我们要调用lib.js文件中的函数ping()加(30,20)main.js

main.js

lib = require("./lib.js")
output = lib.ping();console.log(output);
//Passing Parametersconsole.log("Sum of A and B = " + lib.add(20,30))

lib.js

this.ping=function (){return  "Ping Success"}
//Functions with parametersthis.add=function(a,b){return a+b}

我也在寻找一个选项,可以在不编写模块的情况下包含代码,使用来自不同项目的相同测试过的独立源代码进行Node.js服务-jmparatte的答案为我做了这件事。

好处是,你不会污染命名空间,我在"use strict";上没有问题,而且效果很好。

这里有一个充分样本:

要加载的脚本- /lib/foo.js

"use strict";
(function(){
var Foo = function(e){this.foo = e;}
Foo.prototype.x = 1;
return Foo;
}())

示例模块-index.js

"use strict";
const fs = require('fs');const path = require('path');
var SampleModule = module.exports = {
instAFoo: function(){var Foo = eval.apply(this, [fs.readFileSync(path.join(__dirname, '/lib/foo.js')).toString()]);var instance = new Foo('bar');console.log(instance.foo); // 'bar'console.log(instance.x); // '1'}
}

希望这在某种程度上有所帮助。

它和我一起工作,如下…

Lib1.js

//Any other private code here
// Code you want to exportexports.function1 = function(params) {.......};exports.function2 = function(params) {.......};
// Again any private code

现在在Main.js文件中,您需要包含Lib1.js

var mylib = requires('lib1.js');mylib.function1(params);mylib.function2(params);

请记住把Lib1.jsnode_modules文件夹

就像你有一个文件abc.txt和更多?

创建2个文件:fileread.jsfetchingfile.js,然后在fileread.js中编写以下代码:

function fileread(filename) {var contents= fs.readFileSync(filename);return contents;}
var fs = require("fs");  // file system
//var data = fileread("abc.txt");module.exports.fileread = fileread;//data.say();//console.log(data.toString());}

fetchingfile.js中写这段代码:

function myerror(){console.log("Hey need some help");console.log("type file=abc.txt");}
var ags = require("minimist")(process.argv.slice(2), { string: "file" });if(ags.help || !ags.file) {myerror();process.exit(1);}var hello = require("./fileread.js");var data = hello.fileread(ags.file);  // importing module hereconsole.log(data.toString());

现在,在终端中:fetchingfile.js--file=abc.txt

您将文件名作为参数传递,此外还包括readfile.js中的所有文件,而不是传递它。

谢了

使用node.js和express.js框架时的另一种方法

var f1 = function(){console.log("f1");}var f2 = function(){console.log("f2");}
module.exports = {f1 : f1,f2 : f2}

将其存储在名为s的js文件和文件夹statics中

现在要使用该功能

var s = require('../statics/s');s.f1();s.f2();

在我看来,另一种方法是在使用(函数(/*这里的东西 */){})();调用需要()函数时执行lib文件中的所有内容,这样做将使所有这些函数成为全局范围,就像ava()解决方案一样

src/lib.js

(function () {funcOne = function() {console.log('mlt funcOne here');}
funcThree = function(firstName) {console.log(firstName, 'calls funcThree here');}
name = "Mulatinho";myobject = {title: 'Node.JS is cool',funcFour: function() {return console.log('internal funcFour() called here');}}})();

然后在主代码中,您可以按名称调用函数,例如:

main.js

require('./src/lib')funcOne();funcThree('Alex');console.log(name);console.log(myobject);console.log(myobject.funcFour());

将使此输出

bash-3.2$ node -vv7.2.1bash-3.2$ node main.jsmlt funcOne hereAlex calls funcThree hereMulatinho{ title: 'Node.JS is cool', funcFour: [Function: funcFour] }internal funcFour() called hereundefined

当你调用我的object.func四()时,请注意未定义,如果你加载ava(),它将是相同的。希望它有帮助:)

你可以简单地require('./filename')

例如。

// file: index.jsvar express = require('express');var app = express();var child = require('./child');app.use('/child', child);app.get('/', function (req, res) {res.send('parent');});app.listen(process.env.PORT, function () {console.log('Example app listening on port '+process.env.PORT+'!');});
// file: child.jsvar express = require('express'),child = express.Router();console.log('child');child.get('/child', function(req, res){res.send('Child2');});child.get('/', function(req, res){res.send('Child');});
module.exports = child;

请注意:

  1. 您无法在子文件上侦听PORT,只有父Express模块具有PORT侦听器
  2. 孩子使用的是“路由器”,而不是父母的快递嘴。

创建两个js文件

// File cal.jsmodule.exports = {sum: function(a,b) {return a+b},multiply: function(a,b) {return a*b}};

主js文件

// File app.jsvar tools = require("./cal.js");var value = tools.sum(10,20);console.log("Value: "+value);

控制台输出

Value: 30

我只是想补充一下,如果您只需要从tools.js导入某些函数,那么您可以使用自版本6.4以来node.js支持的解构分配-请参阅node.green


示例(两个文件都在同一个文件夹中)

tools.js

module.exports = {sum: function(a,b) {return a + b;},isEven: function(a) {return a % 2 == 0;}};

main.js

const { isEven } = require('./tools.js');
console.log(isEven(10));

输出:true


这也避免了您将这些函数分配为另一个对象的属性,就像以下(常见)分配中的情况一样:

const tools = require('./tools.js');

在这里你需要调用tools.isEven(10)


注:

不要忘记在文件名前加上正确的路径——即使两个文件都在同一个文件夹中,也需要用./作为前缀

Node.js文档

如果没有前导 '/', './', 或'…/'来指示文件,则模块必须是核心模块或从node_modules文件夹加载。

app.js

let { func_name } = require('path_to_tools.js');func_name();    //function calling

tools.js

let func_name = function() {...//function body...};
module.exports = { func_name };

用途:

var mymodule = require("./tools.js")

app.js:

module.exports.<your function> = function () {<what should the function do>}

创建两个文件,例如app.jstools.js

app.js

const tools= require("./tools.js")

var x = tools.add(4,2) ;
var y = tools.subtract(4,2);

console.log(x);console.log(y);

tools.js

 const add = function(x, y){return x+y;}const subtract = function(x, y){return x-y;}    
module.exports ={add,subtract}

输出

62

要把“工具”变成一个模块,我一点也不难。尽管有所有其他答案,我仍然建议使用module.exports:

//util.jsmodule.exports = {myFunction: function () {// your logic in herelet message = "I am message from myFunction";return message;}}

现在我们需要将此导出分配给全局范围(在应用|index|server.js中)

var util = require('./util');

现在您可以引用和调用函数:

//util.myFunction();console.log(util.myFunction()); // prints in console :I am message from myFunction

创建两个JavaScript文件。例如。import_functions.jsmain.js

1.import_functions.js

// Declaration --------------------------------------
module.exports ={add,subtract// ...}

// Implementation ----------------------------------
function add(x, y){return x + y;}
function subtract(x, y){return x - y;}    

// ...

2.main.js

// include ---------------------------------------
const sf= require("./import_functions.js")
// use -------------------------------------------
var x = sf.add(4,2);console.log(x);
var y = sf.subtract(4,2);console.log(y);
    

输出

62

为了在Unix环境中以交互方式测试模块./test.js,可以使用这样的方法:

    >> node -e "eval(''+require('fs').readFileSync('./test.js'))" -i...

Node基于通用js模块和最近的esm模块工作。基本上,您应该在单独的. js文件中创建模块并使用导入/导出(module.exports和需要)。

浏览器上的Javascript工作方式不同,基于范围。有全局范围,通过clojures(其他函数中的函数),您有私有范围。

因此,在node中,导出您将在其他模块中使用的函数和对象。

国际海事组织最干净的方式如下,在tools.js:

function A(){...}
function B(){...}
module.exports = {A,B}

然后,在app.js,只需要tools.js如下:const tools = require("tools");

使用ESM模块系统:

a.js

export default function foo() {};
export function bar() {};

b.js

import foo, {bar} from './a.js';