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

TIM*_*MEX 893 javascript import header 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);
Run Code Online (Sandbox Code Playgroud)

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

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

mas*_*lum 1307

您可以要求任何js文件,您只需要声明要公开的内容.

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

var zemba = function () {
}
Run Code Online (Sandbox Code Playgroud)

在您的app文件中:

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

  • +1很好地完成,甚至将导入的代码限制在它自己的命名空间中.我将不得不在以后记下这一点. (93认同)
  • 我想知道是否可以导入外部脚本.`require("http://javascript-modules.googlecode.com/svn/functionChecker.js")`似乎没有正确导入模块.有没有其他方法可以导入外部脚本? (7认同)
  • 如果我必须将变量传递给函数Like,bar:function(a,b){// some code} (6认同)
  • 由于您正在公开属性,我将使用exports而不是module.exports.对于出口与module.exports:http://stackoverflow.com/questions/5311334/what-is-the-purpose-of-nodejs-module-exports-and-how-do-you-use-it (5认同)
  • 如何调用函数bar(),在foo()函数内部,意味着如何使用另一个函数访问一个函数 (2认同)

Udo*_*o G 290

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

var fs = require('fs');

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

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

更新2015-08-06

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

  • 很酷,这对于快速为客户端设计的JS库而无需维护Node-style的fork非常有用. (41认同)
  • 我刚回答了原来的问题,即包含代码,而不是编写模块.前者*在某些情况下可以有优势.另外,你对require的假设是错误的:代码肯定是eval'd,但它仍然存在于它自己的命名空间中,无法"污染"调用上下文的命名空间,因此你需要自己eval()它.在大多数情况下,使用我的anwer*中描述的方法是不好的做法*但是我不应该决定它是否适用于TIMEX. (18认同)
  • @EvanPlaice:你有更好的建议**实际上回答了问题**吗?如果你需要包含一个不是模块*的文件*,你有比这更好的方法吗? (14认同)
  • 有时当你需要包含,有时需要时,它们在大多数编程语言中都是两个根本不同的概念,Node JS也是如此.正确地包括js的能力应该是Node的一部分,但是评估它本质上是一个不错的解决方案.Upvoted. (8认同)
  • 请注意,这与__use strict__不兼容 - 因为__use strict__将通过阻止通过eval等引入新变量来约束eval的使用. (4认同)
  • 对于所有认为 eval() 是“危险”或“坏”的人,请记住:正在评估的是程序员自己的代码。仅当您不知道自己在运行什么时,评估才是危险的。 (2认同)

小智 178

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

在tools.js中

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

在app.js

或者像myController.js这样的任何其他.js:

代替

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

我们可以简单地打电话

require('tools.js')();
Run Code Online (Sandbox Code Playgroud)

然后

sum(1,2);
Run Code Online (Sandbox Code Playgroud)

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

module.exports = function() {
    this.Categories = require('categories.js');
}
Run Code Online (Sandbox Code Playgroud)

我可以Categories在每个背景下用作公共课require('ctrls.js')()

  • 这怎么没有+ 1s?这是问题所要求的真正解决方案(虽然不是"官方"问题).调试比eval()容易百万倍,因为节点可以提供有用的调用堆栈,而不是指向实际文件,而不仅仅是未定义. (12认同)
  • 请注意,您不能在导入的模块中"使用'严格"模式. (5认同)
  • 这只是改变了我的生活,没有玩笑 - 有一个1000+行文件,我无法分手,因为不同方法的变量都是相互关联的,并且需要所有都在同一范围内...... require('blah.js')();`应该允许我将它们全部导入同一范围!谢谢!!! (3认同)
  • @尼克帕诺夫:太棒了!值得注意的是,这是有效的,因为当函数被直接调用(不以任何方式绑定)时,函数中的“this”是*全局作用域*。 (2认同)
  • 这是一个很好的提示!注意:如果您使用()=&gt; {}快捷方式语法而不是标准function(){}声明来声明module.exports函数,则它将失败。花了我一个小时找出问题所在!(箭头函数没有自己的'this'属性:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) (2认同)

小智 105

创建两个js文件

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

主要的js文件

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

产量

Value: 30
Run Code Online (Sandbox Code Playgroud)


Pla*_*der 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);
Run Code Online (Sandbox Code Playgroud)

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 () 
{
};
Run Code Online (Sandbox Code Playgroud)


小智 33

我也在寻找NodeJS'include'功能,我检查了Udo G提出的解决方案- 请参阅消息/sf/answers/612116361/.他的代码不适用于我包含的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');
Run Code Online (Sandbox Code Playgroud)

当然,这有帮助.

  • 我理解黑客是多么丑陋,但它确实帮助了我. (2认同)

Dha*_*esh 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))
Run Code Online (Sandbox Code Playgroud)

lib.js

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


Ing*_*ngo 26

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

// ...
Run Code Online (Sandbox Code Playgroud)

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

    
Run Code Online (Sandbox Code Playgroud)

输出

6
2
Run Code Online (Sandbox Code Playgroud)


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

遗憾的是,Fernando建议的with(全局)方法不适用于像"function foo(){}"这样的命名函数

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

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


小智 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.
Run Code Online (Sandbox Code Playgroud)

希望,这有帮助.


Jim*_*dra 11

您可以将函数放在全局变量中,但最好将工具脚本转换为模块.这真的不太难 - 只需将您的公共API附加到exports对象上即可.看看了解Node.js的出口模块的一些细节.

  • 一个例子比一个链接更好 (5认同)

Ale*_*nho 11

在我看来,另一种方法是使用(function(/*things here*/){})();来调用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');
            }
    }
})();
Run Code Online (Sandbox Code Playgroud)

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

main.js

require('./src/lib')
funcOne();
funcThree('Alex');
console.log(name);
console.log(myobject);
console.log(myobject.funcFour());
Run Code Online (Sandbox Code Playgroud)

会产生这个输出

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
Run Code Online (Sandbox Code Playgroud)

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


M.H*_*fny 10

它跟我一样,如下......

Lib1.js

//Any other private code here 

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

// Again any private code
Run Code Online (Sandbox Code Playgroud)

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

var mylib = requires('lib1.js');
mylib.function1(params);
mylib.function2(params);
Run Code Online (Sandbox Code Playgroud)

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


Kri*_*itk 9

我只想添加,如果您只需要从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;
    }
};
Run Code Online (Sandbox Code Playgroud)

main.js

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

console.log(isEven(10));
Run Code Online (Sandbox Code Playgroud)

输出: true


这也避免了您将这些函数指定为另一个对象的属性,如下面(常见)赋值中的情况:

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

你需要打电话的地方tools.isEven(10).


注意:

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

来自Node.js文档:

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


Ash*_*lan 9

app.js

let { func_name } = require('path_to_tools.js');
func_name();    //function calling
Run Code Online (Sandbox Code Playgroud)

tools.js

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

module.exports = { func_name };
Run Code Online (Sandbox Code Playgroud)


You*_*Bee 9

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

app.js

const mainFile= require("./main.js")


var x = mainFile.add(2,4) ;
console.log(x);
Run Code Online (Sandbox Code Playgroud)

main.js

const add = function(x, y){
    return x+y;
}

module.exports ={
    add:add
}
Run Code Online (Sandbox Code Playgroud)

输出

6
Run Code Online (Sandbox Code Playgroud)