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


967

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


4
让我失望的是require,在Windows的同一目录中有一个文件夹。您必须使用Unix风格的寻址:./mydir而不是普通的old mydir
2014年

1
我创建了一个模块来导入脚本,导出到文件并从外部node_modules文件夹包含模块。npmjs.com/package/node-import希望能对您有所帮助。谢谢!
Nanang Mahdaen El-Agung 2015年

Answers:


1414

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

101
+1做得很好,甚至将导入的代码限制在它自己的名称空间中。稍后我将对此进行记录。
Evan Plaice 2012年

8
我想知道是否可以导入外部脚本。require("http://javascript-modules.googlecode.com/svn/functionChecker.js")似乎无法正确导入模块。还有其他导入外部脚本的方法吗?
Anderson Green

6
以及如果我必须将变量传递给函数,如bar:function(a,b){//一些代码}
Nishutosh Sharma

5
由于您要公开属性,因此我将使用导出而不是module.exports。对于出口VS module.exports:stackoverflow.com/questions/5311334/...
农场

4
如何在foo()函数内部调用函数bar()意味着如何与另一个函数一起访问
pitu

303

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

var fs = require('fs');

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

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

更新2015-08-06

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


41
太酷了,这对于快速将为客户端设计的JS库放到node.js应用程序中很有用,而无需维护Node样式的fork。
科斯

18
我只是回答了原始问题,该问题是关于包含代码而不是编写模块的。前者在某些情况下可能具有优势。同样,您对require的假设是错误的:代码当然已经过评估,但是它保留在它自己的名称空间中,无法“污染”调用上下文的名称空间,因此您需要自己eval()它。在大多数情况下,使用我的anwer中描述的方法是不好的做法,但不是我应该决定是否适合TIMEX。
Udo G

14
@EvanPlaice:您是否有更好的建议,实际上可以回答问题?如果您需要包括一个不是模块的文件,那么您是否有比这更好的方法?
2012年

8
在大多数编程语言(Node JS)中,有时有时需要包含(有时需要)它们是两个根本不同的概念。老实说,将js包含在适当位置的能力应该是Node的一部分,但是评估它本质上是一个不错的解决方案。已投票。
J. Martin

4
请注意,是不兼容使用严格的 -如使用严格将通过阻断通过EVAL引入新的变量,等限制使用eval
北京天宝

189

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

在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')()


12
怎么没有更多的+1?这是对问题的真正解决方案(尽管不是“正式”问题)。它比eval()调试还容易一百万倍,因为节点可以提供有用的调用堆栈,而不是指向实际文件而不是未定义的文件。
user3413723 2015年

5
请注意,您不能在导入的模块中“使用'strict”模式。
戴维(David

1
@尼克帕诺夫:太好了!值得一提的是,这是有效的,因为this在函数中,当直接调用该函数(不以任何方式绑定)时,它是全局作用域
Udo G

3
这只是改变了我的生活,没有开玩笑-有一个我无法分解的1000多个行文件,因为不同方法的变量都是相互关联的,并且需要所有条件都在同一范围内... require('blah.js')();应该请允许我将它们全部导入同一范围!!!谢谢!!!
山姆·约翰逊

2
这是一个很好的提示!注意:如果您使用()=> {}快捷语法而不是标准function(){}声明来声明module.exports函数,它将失败。花了我一个小时找出问题所在!(箭头函数没有自己的'this'属性:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Ryan Griggs,

117

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

哪个版本的js可以工作?
Mirv-马特

39

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

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 () 
{
};

34

我也在寻找NodeJS的“包含”功能,并且检查了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

30

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

26

说我们要调用函数平()添加(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

25

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

请注意,到目前为止,vm模块中存在一个错误,该错误会阻止runInThisContext从新上下文中调用时执行正确的操作。这仅在主程序在新上下文中执行代码,然后该代码调用runInThisContext时才重要。参见https://github.com/joyent/node/issues/898

不幸的是,费尔南多建议的with(global)方法不适用于诸如“ foo(){}”之类的命名函数。

简而言之,这是一个对我有用的include()函数:

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

我在另一个SO答案中找到了vm.runInThisContext,并一直在使用它来包含“原始” Javascript代码文件。然后,我尝试使用它来包含依赖于节点功能的代码(例如“ var fs = require('fs')”),它将无法正常工作。但是,在那种情况下,确实有几个答案中提到的“评估”解决方案确实有效。
Dexygen

仔细考虑一下,当您开始需要包括依赖于节点功能的代码时,可能是时候编写模块了,尽管评估解决方案可能是该过程的第一步
Dexygen 2013年

只有一个在2019
迈恩

13

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.

希望有帮助。


12

它像下面这样与我合作....

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文件夹中



11

我认为,执行此操作的另一种方法是,当您使用(function(/ *这里* /){})();调用require()函数时,执行lib文件中的所有内容这样做将使所有这些功能成为全局范围,就像eval()解决方案一样

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 -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

收费atention的不确定时,你叫我object.funcFour() ,这将是相同的,如果你加载的eval() 。希望能帮助到你 :)


10

我只想添加一下,以防万一您只需要从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 docs

如果没有前导“ /”、“./”或“ ../”表示文件,则该模块必须是核心模块,或者是从node_modules文件夹加载的。


10

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 };

3

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

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);

2

这是到目前为止我创建的最好方法。

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;

2

就像您有文件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 here 
console.log(data.toString());

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

您正在传递文件名作为参数,而且包括所有文件 readfile.js而不是传递。

谢谢


2

你可以简单地 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模块​​。

1

我也正在寻找一个选项,以包括代码而无需编写模块。将来自不同项目的相同经过测试的独立来源用于Node.js服务-和jmparatte的答案为我做到了。

好处是,您不会污染名称空间,我不会遇到麻烦 "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'
    }

}

希望这对您有所帮助。


1

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

var f1 = function(){
   console.log("f1");
}
var f2 = function(){
   console.log("f2");
}

module.exports = {
   f1 : f1,
   f2 : f2
}

将此存储在名为s的js文件和静态文件夹中

现在使用该功能

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

1

我想出了一种相当粗糙的方法来处理HTML模板。类似于PHP<?php include("navigation.html"); ?>

server.js

var fs = require('fs');

String.prototype.filter = function(search,replace){
    var regex = new RegExp("{{" + search.toUpperCase() + "}}","ig");
    return this.replace(regex,replace);
}

var navigation = fs.readFileSync(__dirname + "/parts/navigation.html");

function preProcessPage(html){
    return html.filter("nav",navigation);
}

var express = require('express');
var app = express();
// Keep your server directory safe.
app.use(express.static(__dirname + '/public/'));
// Sorta a server-side .htaccess call I suppose.
app.get("/page_name/",function(req,res){
    var html = fs.readFileSync(__dirname + "/pages/page_name.html");
    res.send(preProcessPage(html));
});

page_name.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <title>NodeJS Templated Page</title>
    <link rel="stylesheet" type="text/css" href="/css/bootstrap.min.css">
    <link rel="stylesheet" type="text/css" href="/css/font-awesome.min.css">
    <!-- Scripts Load After Page -->
    <script type="text/javascript" src="/js/jquery.min.js"></script>
    <script type="text/javascript" src="/js/tether.min.js"></script>
    <script type="text/javascript" src="/js/bootstrap.min.js"></script>
</head>
<body>
    {{NAV}}
    <!-- Page Specific Content Below Here-->
</body>
</html>

navigation.html

<nav></nav>

载入页面结果

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <title>NodeJS Templated Page</title>
    <link rel="stylesheet" type="text/css" href="/css/bootstrap.min.css">
    <link rel="stylesheet" type="text/css" href="/css/font-awesome.min.css">
    <!-- Scripts Load After Page -->
    <script type="text/javascript" src="/js/jquery.min.js"></script>
    <script type="text/javascript" src="/js/tether.min.js"></script>
    <script type="text/javascript" src="/js/bootstrap.min.js"></script>
</head>
<body>
    <nav></nav>
    <!-- Page Specific Content Below Here-->
</body>
</html>

0

如果您想利用多个CPU和微服务体系结构来加快处理速度,请在分叉进程上使用RPC。

听起来很复杂,但是使用章鱼很简单。

这是一个例子:

在tools.js上添加:

const octopus = require('octopus');
var rpc = new octopus('tools:tool1');

rpc.over(process, 'processRemote');

var sum = rpc.command('sum'); // This is the example tool.js function to make available in app.js

sum.provide(function (data) { // This is the function body
    return data.a + data.b;
});

在app.js上,添加:

const { fork } = require('child_process');
const octopus = require('octopus');
const toolprocess = fork('tools.js');

var rpc = new octopus('parent:parent1');
rpc.over(toolprocess, 'processRemote');

var sum = rpc.command('sum');

// Calling the tool.js sum function from app.js
sum.call('tools:*', {
    a:2, 
    b:3
})
.then((res)=>console.log('response : ',rpc.parseResponses(res)[0].response));

披露-我是章鱼的作者,并且为我的类似用例而构建,因为我找不到任何轻量级的库。


0

要将“工具”变成一个模块,我一点也不觉得困难。尽管有其他所有答案,我仍然建议使用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 

-3

采用:

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

app.js:

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

1
您几乎永远不应使用完整目录。您应该考虑使用相对路径,例如:./tools.js
Matthew D Auld
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.