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

1219

假设我有一个名为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"转换为一个模块,然后进行 require 吗? << 这似乎很困难,我宁愿进行 tools.js 文件的基本导入。


5
在Windows系统中,我感到困惑的是使用require引入同一目录下的文件夹。你需要使用类Unix风格的路径表示方式:使用./mydir而不是简单的mydir - Ben
1
我创建了一个模块,可以导入脚本,将其导出到文件,并从node_modules文件夹外部包含模块。https://www.npmjs.com/package/node-import 希望它能有所帮助。谢谢! - Nanang Mahdaen El-Agung
29个回答

1737

你可以引入任何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
8
我想知道是否可以导入外部脚本。require("http://javascript-modules.googlecode.com/svn/functionChecker.js") 似乎不能正确地导入模块。有其他导入外部脚本的方法吗? - Anderson Green
7
如果我需要将变量传递到函数中,该怎么办? 比如: bar: function(a, b){ //一些代码 } - Nishutosh Sharma
6
既然您正在公开属性,我建议使用exports而不是module.exports。关于exports和module.exports的区别,请参考:https://dev59.com/12435IYBdhLWcg3wnBd8 - Farm
4
如何在函数foo()内调用函数bar(),意思是如何在一个函数中访问另一个函数。 - pitu
显示剩余14条评论

345

如果尽管有其他答案,你仍然想要在node.js源文件中传统地包含一个文件,可以使用以下方法:

var fs = require('fs');

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

请注意,在大多数情况下,这是不好的做法,您应该编写一个模块。然而,在某些罕见情况下,您确实需要污染本地上下文/命名空间。

更新2015-08-06

还请注意,此方法在使用"use strict";时无法正常工作(即处于"严格模式"下),因为在"导入"文件中定义的函数和变量无法被访问。严格模式实施由较新版本的语言标准定义的一些规则。这可能是避免在此处描述的解决方案的另一个原因。


45
很棒,这对于将为客户端设计的 JS 库快速而简便地放入 node.js 应用程序中非常有用,而无需维护一个类似 Node 风格的 fork。 - Kos
19
我只回答了原问题,涉及包括代码而非编写模块。前者在某些情况下确实具有优势。另外,您对 require 的假设是错误的:代码确实被 eval'd,但它仍在自己的命名空间中,并且没有办法“污染”调用上下文的命名空间,因此您需要自己 eval() 它。在大多数情况下,使用我回答中描述的方法是不良实践,但不应由我来决定是否适用于 TIMEX。 - Udo G
16
你是否有更好的建议,可以真正回答这个问题?如果你需要包含一个不是模块的文件,请问你有比这更好的方法吗? - jalf
9
在大多数编程语言和Node JS中,有时你需要使用"include",有时则需要"require",这两个概念基本上是不同的。能够在特定位置包含js代码应该是Node的一部分,但实际上使用eval()也是一个不错的解决方案。已点赞。 - J. Martin
4
注意,这与"use strict"不兼容——因为"use strict"会通过阻止eval引入新变量等方式来限制eval的使用。 - timbo
显示剩余16条评论

228

你不需要新的函数或新的模块。 如果你不想使用命名空间,只需要执行你正在调用的模块即可。

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

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


15
这个回答如此实用,为什么没有更多的“赞”?虽然这不是官方的解决方案,但它真正回答了问题。与使用 eval() 相比,它的调试也容易一百万倍,因为 Node 可以提供有用的函数调用堆栈,而不仅仅是 undefined。 - user3413723
6
请注意,您无法在导入的模块中使用“严格”模式。 - David
2
@Nick Panov:太棒了!值得注意的是,这是因为在函数中this全局范围,当函数直接调用时(没有被任何方式绑定)。 - Udo G
4
这简直改变了我的生活,一点都不开玩笑——我有一个超过1000行的文件,由于不同方法的变量相互关联,需要将所有要求(require)放在同一个作用域中才能分解文件... require('blah.js')(); 可以让我把它们全部导入到同一个作用域中!!! 谢谢!!! - Sam Johnson
3
这是一个很好的提示!但要注意:如果您使用() => {}这种简写语法而不是标准的function() {}声明来声明模块导出函数,则会失败。 我花了一个小时才弄清楚问题所在!(箭头函数没有自己的'this'属性:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/Arrow_functions) - Ryan Griggs
显示剩余5条评论

139

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

在其他文件中声明的函数,有没有办法识别类型,我的意思是,在编码时,当我按下“.”时,任何IDE都能够理解它是哪种类型的对象。 - JustTry

82

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

工具.js

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

输出

6
2

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);
抱歉,我只能使用英语回答您的问题。若您有需要,我可以尝试将答案翻译成中文。
// '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 () 
{
};

37

我也在寻找 NodeJS 的 'include' 函数,检查了Udo G提出的解决方案——请见消息https://dev59.com/3m025IYBdhLWcg3wyZEn#8744519。然而,他的代码不能与我的包含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
我知道这是多么丑陋的一个Hack,但它确实帮了我个大忙。 - lindhe
1
新手入门Node。对我来说,这似乎很疯狂,只是为了内联一些JS,但这是唯一有效的解决方案,谢谢。有很多提到模块的答案,令人难以置信。 - Nomas Prime

30

创建两个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.) 主文件.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

有没有办法导入所有函数,这样你就不必使用 sf` 了?只需单独调用 subtract() 函数即可? - john k

25

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

需要注意的是,截至今天,vm模块存在一个bug,防止从新上下文调用runInThisContext时正确执行。这仅在您的主程序在新上下文中执行代码,然后该代码调用runInThisContext时才会有影响。请参见https:// github.com / joyent / node / issues / 898

不幸的是,像“function foo() {}”这样的命名函数对于Fernando建议的with(global)方法不起作用。

简而言之,以下是适合我的include()函数:

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

我在另一个SO答案中发现了vm.runInThisContext,并一直在使用它来包含“vanilla”Javascript代码文件。然后,我尝试使用它来包含依赖于node功能的代码(例如“var fs = require('fs')”),但它不起作用。在这种情况下,几个答案中提到的“eval”解决方案确实可行。 - Dexygen
再仔细考虑一下,当您开始需要包含依赖于节点功能的代码时,很可能是编写模块的时候了,尽管eval解决方案可能是该过程的第一步。 - Dexygen

25

假设我们想要在 main.js 文件中调用位于 lib.js 文件中的函数 ping()add(30,20)

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接