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

In Node.js, how do I "include" functions from my other files?

提问人:TIMEX 提问时间:4/27/2011 最后编辑:TIMEX 更新时间:10/24/2023 访问量:1116329

问:

假设我有一个名为 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文件的基本导入。

JavaScript 导入 标头 node.js

评论

5赞 Ben 8/3/2014
让我失望的是 Windows 上同一目录中的一个文件夹。你必须使用 unix 风格的寻址:而不是普通的 .require./mydirmydir
1赞 Nanang Mahdaen El-Agung 3/22/2015
我创建了一个模块来导入脚本、导出到文件以及从外部文件夹包含模块。npmjs.com/package/node-import希望能有所帮助。谢谢!node_modules

答:

10赞 Jimmy 4/27/2011 #1

你可以把你的函数放在全局变量中,但最好把你的工具脚本变成一个模块。这真的不是太难 - 只需将公共 API 附加到对象即可。有关更多详细信息,请查看了解Node.js的导出模块exports

评论

5赞 tno2007 5/16/2019
一个例子比一个链接更好
1737赞 masylum 4/27/2011 #2

你可以要求任何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

评论

130赞 Evan Plaice 1/21/2012
+1 做得很好,甚至将导入的代码限制在它自己的命名空间中。我必须记下这一点,以备后用。
8赞 Anderson Green 1/2/2013
我想知道是否可以导入外部脚本。 似乎没有正确导入模块。有没有其他方法可以导入外部脚本?require("http://javascript-modules.googlecode.com/svn/functionChecker.js")
7赞 Nishutosh Sharma 5/25/2013
如果我必须将变量传递到函数中怎么办 比如,bar: function(a, b){ //一些代码 }
6赞 Farm 12/15/2013
由于您公开了属性,因此我将使用 exports 而不是 module.exports。对于导出与模块导出:stackoverflow.com/questions/5311334/...
4赞 pitu 8/8/2014
如何调用函数 bar(),在 foo() 函数中,意味着如何访问一个函数和另一个函数
345赞 Udo G 4/28/2011 #3

如果尽管有所有其他答案,您仍然希望在传统上将文件包含在node.js源文件中,则可以使用以下命令:

var fs = require('fs');

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

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

更新 2015-08-06

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

评论

45赞 Kos 12/11/2011
很酷,这对于快速地将客户端设计的 JS 库放入node.js应用程序中非常有用,而无需维护 Node 样式的分支。
19赞 Udo G 1/22/2012
我只是回答了最初的问题,即包含代码,而不是编写模块。前者在某些情况下可能具有优势。此外,你对 require 的假设是错误的:代码肯定是 evalu'd,但它保留在它自己的命名空间中,并且没有办法“污染”调用上下文的命名空间,因此你需要自己 eval() 它。在大多数情况下,使用我的 anwer 中描述的方法是一种不好的做法,但不应该由我决定它是否适用于 TIMEX。
16赞 jalf 4/21/2012
@EvanPlaice:你有更好的建议来回答这个问题吗?如果您需要包含一个不是模块的文件,您有比这更好的方法吗?
9赞 J. Martin 6/10/2012
有时你需要include,有时需要,它们在大多数编程语言中是两个根本不同的概念,Node JS也是如此。老实说,将 js 包含在适当的位置的能力应该是 Node 的一部分,但评估它本质上是一个不错的解决方案。点赞。
4赞 timbo 2/4/2014
请注意,这与 use strict 不兼容 - 因为 use strict 会通过阻止通过 eval 等引入新变量来限制 eval 的使用。
14赞 Fernando 1/5/2012 #4

Udo G. 说:

  • eval() 不能在函数内部使用,必须在函数内部调用 全局作用域,否则将没有函数或变量 可访问的(即您不能创建include()实用程序函数或 类似的东西)。

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

function include(file_) {
    with (global) {
        eval(fs.readFileSync(file_) + '');
    };
};

include('somefile_with_some_declarations.js');

// the declarations are now accessible here.

希望,这会有所帮助。

25赞 Chad Austin 6/27/2012 #5

Node.js中的 vm 模块提供了在当前上下文(包括全局对象)中执行 JavaScript 代码的功能。查看 http://nodejs.org/docs/latest/api/vm.html#vm_vm_runinthiscontext_code_filename

请注意,截至今天,vm 模块中存在一个 bug,该 bug 在从新上下文调用时会阻止 runInThisContext 执行正确的操作。仅当主程序在新上下文中执行代码,然后该代码调用 runInThisContext 时,这才有意义。查看 https://github.com/joyent/node/issues/898

可悲的是,Fernando 建议的 with(global) 方法不适用于像“function foo() {}”这样的命名函数

简而言之,这里有一个适合我的include()函数:

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

评论

0赞 Dexygen 6/29/2013
我在另一个 SO 答案中找到了 vm.runInThisContext,并且一直在使用它来包含“香草”Javascript 代码文件。但是,我尝试使用它来包含依赖于节点功能的代码(例如“var fs = require('fs')”),但它不起作用。然而,在这种情况下,几个答案中提到的“评估”解决方案确实有效。
0赞 Dexygen 7/1/2013
仔细想想,当你开始需要包含依赖于节点功能的代码时,可能是时候编写一个模块了,尽管 eval 解决方案可能是该过程的第一步
1赞 Saulo Castelo Sampaio 7/27/2013 #6

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

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;
37赞 jmparatte 12/9/2013 #7

我也在寻找 NodeJS 的“include”函数,并检查了 Udo G 提出的解决方案 - 请参阅消息 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');

当然,这很有帮助。

评论

2赞 lindhe 1/14/2019
我知道这是多么丑陋的黑客攻击,但它确实帮助了我。
1赞 Nomas Prime 6/9/2020
Node 新手。对我来说似乎很疯狂,这是简单地内联一些JS所需要的,但这是唯一对我有用的解决方案,谢谢。如此多的答案都提到了模块——令人难以置信。
39赞 Placeholder 10/23/2014 #8

这是一个简单明了的解释:

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 else
var databaseName = 'Walter';
var databaseSurname = 'Heisenberg';

// Use the function from 'helpers.js' in the main file, which is server.js
var fullname = helpers.concatenateNames(databaseName, databaseSurname);

Helpers.js内容:

// 'module.exports' is a node.JS specific feature, it does not work with regular JavaScript
module.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 file
var privateFunction = function () 
{
};
228赞 Nick Panov 1/21/2015 #9

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

在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');
}

之后,我可以在每种情况下用作公共类Categoriesrequire('ctrls.js')()

评论

15赞 user3413723 6/26/2015
这怎么没有更多的+1?这是对问题提出的真正解决方案(尽管不是“官方”的)。它的调试也比 eval() 容易一百万倍,因为 node 可以给出一个有用的调用堆栈,而不是指向实际文件,而不仅仅是未定义。
6赞 David 6/13/2016
请注意,您不能在导入的模块中“使用'strict'”模式。
2赞 Udo G 10/4/2016
@Nick Panov:太棒了!应该值得注意的是,这是有效的,因为当函数被直接调用时,函数是全局范围(不以任何方式绑定)。this
4赞 Sam Johnson 4/18/2017
这改变了我的生活,不是开玩笑 - 有一个 1000+ 行文件,我无法分解,因为不同方法的变量都是相互关联的,并且需要所有需求都在同一范围内...... 应该允许我将它们全部导入到同一个范围内!!谢谢!!!require('blah.js')();
3赞 Ryan Griggs 10/11/2018
这是一个很好的提示!注意:如果您使用 () => {} 快捷方式语法而不是标准 function() {} 声明来声明 module.exports 函数,则会失败。我花了一个小时才弄清楚问题出在哪里!(箭头函数没有自己的“this”属性:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...)
3赞 user11153 3/9/2015 #10

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

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);
25赞 Dharmesh 8/22/2015 #11

假设我们想调用函数 ping()add(30,20),它位于lib.js文件中 与main.js相比

main.js

lib = require("./lib.js")

output = lib.ping();
console.log(output);

//Passing Parameters
console.log("Sum of A and B = " + lib.add(20,30))

lib.js

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

评论

1赞 Kokodoko 10/15/2015
这可行,但是我们在包含脚本时不应该使用模块语法吗?
0赞 zyexal 3/26/2016 #12

我也在寻找一个选项来包含不编写模块的代码,例如使用来自不同项目的相同经过测试的独立源代码进行Node.js服务 - jmpautette的答案为我做到了。

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

下面是一个完整的示例:

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

"use strict";

(function(){

    var Foo = function(e){
        this.foo = e;
    }

    Foo.prototype.x = 1;

    return Foo;

}())

SampleModule - 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'
    }

}

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

12赞 M.Hefny 6/16/2016 #13

它像下面这样与我一起工作......

Lib1.js

//Any other private code here 

// Code you want to export
exports.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.js放在node_modules文件夹中。

0赞 Gajender Singh 9/23/2016 #14

就像你有一个文件等等?abc.txt

创建 2 个文件: 和 ,然后编写以下代码:fileread.jsfetchingfile.jsfileread.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 here 
console.log(data.toString());

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

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

谢谢

0赞 suku 12/7/2016 #15

使用 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();
11赞 Alex 1/27/2017 #16

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

来源/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 -v
v7.2.1
bash-3.2$ node main.js 
mlt funcOne here
Alex calls funcThree here
Mulatinho
{ title: 'Node.JS is cool', funcFour: [Function: funcFour] }
internal funcFour() called here
undefined

当你调用我的 object.funcFour() 时要注意 undefined,如果你用 eval() 加载,它会是一样的。希望对:)有所帮助

1赞 Weijing Lin 2/22/2017 #17

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

例如。

// file: index.js
var 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.js
var 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. 子项使用的是“路由器”,而不是父级 Express moudle。
139赞 Jayaprakash G 4/11/2017 #18

创建两个 js 文件

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

主 js 文件

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

控制台输出

Value: 30

评论

0赞 JustTry 7/16/2020
在其他文件中声明的函数有什么方法可以识别类型,我的意思是在我按 .任何 IDE 都能够理解它是哪种类型的对象
10赞 Kristianmitk 4/19/2018 #19

我只想补充一点,如果您只需要从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 文件夹加载。

12赞 Ashish Duklan 9/24/2018 #20

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 };
-4赞 coder 10/15/2018 #21

用:

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

app.js:

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

评论

1赞 Matthew Auld 11/7/2018
您几乎不应该使用完整的目录。您应该考虑使用相对路径,例如:./tools.js
82赞 YouBee 6/17/2019 #22

创建两个文件,例如和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
    }

输出

6
2
0赞 StefaDesign 6/18/2019 #23

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

//util.js
module.exports = {
   myFunction: function () {
   // your logic in here
   let message = "I am message from myFunction";
   return message; 
  }
}

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

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

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

//util.myFunction();
console.log(util.myFunction()); // prints in console :I am message from myFunction 
30赞 Ingo 8/25/2020 #24

创建两个 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);

    

输出

6
2

评论

0赞 john k 11/10/2022
有什么方法可以导入所有函数,这样您就不必使用 SF'?只是自己调用 subtract()?
-2赞 AliBabba 3/10/2021 #25

要在 Unix 环境中以交互方式测试模块,可以使用如下所示:./test.js

    >> node -e "eval(''+require('fs').readFileSync('./test.js'))" -i
    ...
1赞 Jone Polvora 3/22/2022 #26

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

浏览器上的 Javascript 的工作方式因范围而异。有全局作用域,通过 clojures(其他函数中的函数),你有私有作用域。

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

1赞 Hani 3/24/2022 #27

IMO最干净的方式如下,在tools.js:

function A(){
.
.
.
}

function B(){
.
.
.
}

module.exports = {
A,
B
}

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

3赞 Richie Bendall 9/28/2022 #28

使用 ESM 模块系统:

a.js:

export default function foo() {};

export function bar() {};

b.js:

import foo, {bar} from './a.js';
0赞 Crefelder 10/24/2023 #29

我想使用一个静态函数和一个来自 JS 类的方法。 否则我使用 Typescript,但这里它只是编译后的后脚本。 到目前为止,以最疯狂的方式处理了它,并混合了上述所有答案:

js/tools.js:

class Tools {
        count = 0;
    
        constructor(count) {
            this.count = count;
        }
    
        static add = function (x, y) { // static function
            return x + y;
        }
    
        incrementCountByValue(value) // instance method
        {
            this.count += value;
        }
    }
}

module.exports = {
    Tools
}

app.js:

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

console.log(Tools.add(2,2));// console output: 4

const tools = new Tools(5);
console.log(tools.count);// console output: 5

tools.incrementCountByValue(3);
console.log(tools.count); // console output: 8