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

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

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

1
2
3
4
5
6
7
8
9
10
11
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文件的基本导入。


您可以需要任何JS文件,只需声明您想要公开的内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
// tools.js
// ========
module.exports = {
  foo: function () {
    // whatever
  },
  bar: function () {
    // whatever
  }
};

var zemba = function () {
}

在应用程序文件中:

1
2
3
4
5
6
// 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源文件中包含一个文件,则可以使用此选项:

1
2
3
4
var fs = require('fs');

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

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

更新2015-08-06

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


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

在工具S. JS中

1
2
3
4
5
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);这样的工具。

我们可以打电话

1
require('tools.js')();

然后

1
sum(1,2);

在我的例子中,我有一个带有controllers ctrls.js的文件

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

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


创建两个JS文件

1
2
3
4
5
6
7
8
9
// File cal.js
module.exports = {
    sum: function(a,b) {
        return a+b
    },
    multiply: function(a,b) {
        return a*b
    }
};

主JS文件

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

产量

1
value: 30


下面是一个简单明了的解释:

server.js内容:

1
2
3
4
5
6
7
8
9
// 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内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// '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 ()
{
};

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

1
2
3
4
5
6
7
8
9
10
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');

当然,这有帮助。


node.js中的vm模块提供在当前上下文(包括全局对象)中执行javascript代码的能力。请参见http://nodejs.org/docs/latest/api/vm.html vm vm runinthiscoxt code filename

注意,从今天开始,VM模块中存在一个bug,它阻止Runin上下文从新上下文调用时做正确的操作。只有当主程序在新的上下文中执行代码,然后该代码调用RunIn上下文时,这才是重要的。参见HTTPS:/GIHUUBCOM/JONTEN/NODE/SUNES/898

遗憾的是,费尔南多建议的使用(全局)方法对于命名函数"函数脚"({})不起作用。

简而言之,这里有一个为我工作的包含函数。

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


假设我们想调用函数ping()并添加(30,20),它在lib.js文件中从M.J.

MIN JS

1
2
3
4
5
6
7
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

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


Udo G.说:

  • The eval() can't be used inside a function and must be called inside
    the global scope otherwise no functions or variables will be
    accessible (i.e. you can't create a include() utility function or
    something like that).

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

1
2
3
4
5
6
7
8
9
function include(file_) {
    with (global) {
        eval(fs.readFileSync(file_) + '');
    };
};

include('somefile_with_some_declarations.js');

// the declarations are now accessible here.

希望,这有帮助。


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

SRC/LIB JS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
(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');
            }
    }
})();

然后,在主代码中,您可以通过以下名称调用函数:

MIN JS

1
2
3
4
5
6
require('./src/lib')
funcOne();
funcThree('Alex');
console.log(name);
console.log(myobject);
console.log(myobject.funcFour());

将生成此输出

1
2
3
4
5
6
7
8
9
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

当调用my object.funcfur()时,请注意未定义的,如果使用eval()加载,它将是相同的。希望有帮助:)


您可以将函数放在全局变量中,但最好将工具脚本转换为模块。这并不太难——只需将公共API连接到exports对象即可。了解node.js的exports模块,了解更多详细信息。


我只是想补充一点,如果您只需要从tools.js导入某些函数,那么您可以使用自6.4版以来node.js支持的破坏性赋值——请参见node.green。

例子:(两个文件在同一文件夹中)

tools.js

1
2
3
4
5
6
7
8
module.exports = {
    sum: function(a,b) {
        return a + b;
    },
    isEven: function(a) {
        return a % 2 == 0;
    }
};

main.js

1
2
3
const { isEven } = require('./tools.js');

console.log(isEven(10));

输出:true

这也避免了在以下(公共)分配中,将这些函数作为另一个对象的属性进行分配:

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

你需要打电话给tools.isEven(10)

注:

别忘了在文件名前面加上正确的路径——即使两个文件都在同一个文件夹中,也需要在文件名前面加上EDOCX1[12]

从node.js文档:

Without a leading '/', './', or '../' to indicate a file, the module
must either be a core module or is loaded from a node_modules folder.


它对我起到了如下作用…

LIB 1.JS

1
2
3
4
5
6
7
//Any other private code here

// Code you want to export
exports.function1 = function1 (params) {.......};
exports.function2 = function2 (params) {.......};

// Again any private code

现在在main.js文件中,您需要包含lib1.js

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

请记住将lib1.js放在node_modules文件夹中。


App.JS

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

JS工具

1
2
3
4
5
6
7
let func_name = function() {
    ...
    //function body
    ...
};

module.exports = { func_name };


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

1
2
3
define({
   "data":"XYZ"
});

MIN JS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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个文件:fileread.jsfetchingfile.js,然后在fileread.js中编写此代码:

1
2
3
4
5
6
7
8
9
10
11
12
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中,编写以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
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--文件=abc.txt

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

谢谢


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
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();

你仍然需要告知你想要出口什么

1
2
3
4
5
6
7
8
9
10
includeOnce('./bin/WebServer.js');

function Lara() {
  this.webServer = new WebServer();
  this.webServer.start();
}

Lara.prototype.webServer = null;

module.exports.Lara = Lara;

你只需简单地输入require('./filename')

如。

1
2
3
4
5
6
7
8
9
10
11
// 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+'!');
});
1
2
3
4
5
6
7
8
9
10
11
12
// 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;

请注意:

  • 无法在子文件上侦听端口,只有父Express模块具有端口侦听器
  • 孩子使用的是"路由器",而不是父Express模块。

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    var f1 = function(){
       console.log("f1");
    }
    var f2 = function(){
       console.log("f2");
    }

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

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

    现在使用函数

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


    我想出了一个相当粗糙的方法来处理HTML模板化。与php 类似

    server.js

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
        NodeJS Templated Page
        <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 type="text/javascript" src="/js/tether.min.js">
        <script type="text/javascript" src="/js/bootstrap.min.js">
    </head>
    <body>
        {{NAV}}
        <!-- Page Specific Content Below Here-->
    </body>
    </html>

    navigation.html

    1
    <nav></nav>

    Loaded Page Result

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
        NodeJS Templated Page
        <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 type="text/javascript" src="/js/tether.min.js">
        <script type="text/javascript" src="/js/bootstrap.min.js">
    </head>
    <body>
        <nav></nav>
        <!-- Page Specific Content Below Here-->
    </body>
    </html>

    我也在寻找一个不需要编写模块就可以包含代码的选项。对node.js服务使用来自不同项目的相同测试的独立源,jmpartates的答案为我做了这件事。

    其好处是,您不会污染名称空间,我对"use strict";没有问题,而且它工作得很好。

    这里是一个完整的样本:

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    "use strict";

    (function(){

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

        Foo.prototype.x = 1;

        return Foo;

    }())

    示例模块-index.js

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    "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'
        }

    }

    希望这能有所帮助。


    如果您想利用多个CPU和微服务体系结构,以加快速度……请使用RPC而不是分叉进程。

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

    下面是一个例子:

    在tools.js上添加:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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,添加:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    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));

    披露-我是章鱼的作者,如果我找不到任何轻量级的图书馆,那么我就要为我的类似用途建造它。


    用途:

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

    App.JS:

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