【问题标题】:In Node.js, how do I "include" functions from my other files?在 Node.js 中,如何从其他文件中“包含”函数?
【发布时间】:2015-10-06 14:08:03
【问题描述】:

假设我有一个名为 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 中使用?

或者...我应该把“工具”变成一个模块,然后需要它吗?

【问题讨论】:

  • 让我失望的是require在 Windows 上的同一目录中创建一个文件夹。您必须使用 unix 样式的寻址:./mydir 而不是普通的旧 mydir
  • 我创建了一个模块来导入脚本,导出到文件,并从node_modules 文件夹之外包含模块。 npmjs.com/package/node-import希望能帮到你。谢谢!

标签: javascript import header node.js


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

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

          >> node -e "eval(''+require('fs').readFileSync('./test.js'))" -i
          ...
      

      【讨论】:

        【解决方案4】:

        创建两个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 都能够理解它是哪种类型的对象
        【解决方案5】:

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

        【讨论】:

          【解决方案6】:

          它和我一起工作如下......

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

          【讨论】:

            【解决方案7】:

            用途:

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

            app.js:

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

            【讨论】:

            • 您几乎不应该使用完整目录。您应该考虑使用相对路径,例如:./tools.js
            【解决方案8】:

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

            【讨论】:

              【解决方案9】:

              我只是想补充一点,如果您只需要从 tools.js 导入的某些功能,那么您可以使用自版本 起在 node.js 中支持的 destructuring assignment 6.4 - 见node.green


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

              tools.js

              module.exports = {
                  sum: function(a,b) {
                      return a + b;
                  },
                  isEven: function(a) {
                      return a % 2 == 0;
                  }
              };
              

              ma​​in.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】:

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

                【讨论】:

                • +1 做得很好,甚至将导入的代码限制在它自己的命名空间中。我得记下这个以备后用。
                • 我想知道是否可以导入外部脚本。 require("http://javascript-modules.googlecode.com/svn/functionChecker.js") 似乎没有正确导入模块。有没有其他方法可以导入外部脚本?
                • 如果我必须将变量传递给函数,比如 bar: function(a, b){ //some code }
                • 由于您要公开属性,我将使用导出而不是 module.exports。对于导出与 module.exports:stackoverflow.com/questions/5311334/…
                • 如何在 foo() 函数内部调用 bar() 函数,表示如何访问一个函数与另一个函数
                【解决方案11】:

                你可以简单的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。

                【讨论】:

                  【解决方案12】:

                  在我看来,另一种方法是在您使用 (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');
                              }
                      }
                  })();
                  

                  然后在您的主代码中,您可以按名称调用您的函数,例如:

                  ma​​in.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()加载也是一样>。希望对你有帮助:)

                  【讨论】:

                    【解决方案13】:

                    使用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();
                    

                    【讨论】:

                      【解决方案14】:

                      您可以将您的函数放在全局变量中,但最好将您的工具脚本变成一个模块。这真的不太难——只需将您的公共 API 附加到 exports 对象。请查看Understanding Node.js' exports module 了解更多详情。

                      【讨论】:

                      • 例子胜于链接
                      【解决方案15】:

                      您是否有一个文件 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 中的所有文件而不是传递它。

                      谢谢

                      【讨论】:

                        【解决方案16】:

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

                        好处是,你不会污染命名空间,"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'
                            }
                        
                        }
                        

                        希望这对您有所帮助。

                        【讨论】:

                          【解决方案17】:

                          假设我们要调用 ping()add(30,20) 函数,它们在 lib.js 文件中 来自 ma​​in.js

                          ma​​in.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
                              }
                          

                          【讨论】:

                          • 这可行,但我们不应该在包含脚本时使用模块语法吗?
                          【解决方案18】:

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

                          在 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 作为公共类

                          【讨论】:

                          • 这怎么没有更多的+1?这是问题所要求的真正解决方案(尽管不是“官方”解决方案)。它也比 eval() 更容易调试一百万倍,因为 node 可以提供有用的调用堆栈,而不是指向实际文件,而不仅仅是 undefined。
                          • 请注意,您不能在导入的模块中“使用“严格”模式。
                          • @Nick Panov:太棒了!值得注意的是,这是可行的,因为函数中的this 是直接调用函数时的全局范围(不以任何方式绑定)。
                          • 这只是改变了我的生活,不是开玩笑——有一个 1000 多行的文件,我无法分解,因为不同方法的变量都是相互关联的,需要全部在同一个范围内...require('blah.js')(); 应该允许我将它们全部导入到同一个范围内!!!谢谢!!!
                          • 这是一个很棒的提示!警告:如果您使用 () => {} 快捷语法而不是标准的 function() {} 声明来声明 module.exports 函数,它会失败。我花了一个小时才弄清楚问题出在哪里! (箭头函数没有自己的“this”属性:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
                          【解决方案19】:

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

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

                          请注意,在大多数情况下这是不好的做法,您应该改为write a module。但是,在极少数情况下,您真正​​想要的是污染本地上下文/命名空间。

                          2015-08-06 更新

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

                          【讨论】:

                          • 酷,这对于快速地将为客户端设计的 JS 库放入 node.js 应用程序而无需维护 Node 样式的 fork 很有用。
                          • 我刚刚回答了最初的问题,是关于包含代码,而不是编写模块。前者可以在某些情况下具有优势。此外,您对 require 的假设是错误的:代码肯定是经过评估的,但它保留在自己的名称空间中,无法“污染”调用上下文的名称空间,因此您需要自己 eval() 。在大多数情况下,使用我的回答中描述的方法是不好的做法,但不是我应该决定它是否适用于 TIMEX。
                          • @EvanPlaice:您有更好的建议实际上回答了问题吗?如果你需要包含一个不是模块的文件,你有比这更好的方法吗?
                          • 有时需要包含,有时需要,它们是大多数编程语言中两个根本不同的概念,Node JS 也是如此。老实说,包含 js 的能力应该是 Node 的一部分,但评估它本质上是一个不错的解决方案。赞成。
                          • 请注意,这与 use strict 不兼容 - 因为 use strict 将通过阻止通过 eval 等引入新变量来限制 eval 的使用。
                          【解决方案20】:

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

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

                          【讨论】:

                            【解决方案21】:

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

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

                            【讨论】:

                              【解决方案22】:

                              我还在寻找 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');
                              

                              当然,这有帮助。

                              【讨论】:

                              • 我知道这是多么丑陋的黑客行为,但它确实帮助了我。
                              • Node 新手。对我来说似乎很疯狂,这只是内联一些 JS 所需要的,但这是唯一对我有用的解决方案,谢谢。这么多答案提到模块——难以置信。
                              【解决方案23】:

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

                              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;
                              

                              【讨论】:

                                【解决方案24】:

                                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(global) 方法不适用于“function foo() {}”等命名函数

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

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

                                【讨论】:

                                • 我在另一个 SO 答案中找到了 vm.runInThisContext,并且一直在使用它来包含“vanilla”Javascript 代码文件。然后,我尝试使用它来包含依赖于节点功能的代码(例如“var fs = require('fs')”),但它不起作用。然而,在这种情况下,几个答案中提到的“评估”解决方案确实有效。
                                • 再想一想,当您开始需要包含依赖于节点功能的代码时,可能是时候编写一个模块了,尽管 eval 解决方案可能是该过程的第一步跨度>
                                【解决方案25】:

                                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.
                                

                                希望,这会有所帮助。

                                【讨论】:

                                  猜你喜欢
                                  • 2018-05-22
                                  • 2015-07-28
                                  • 2021-11-09
                                  • 2019-03-21
                                  • 2012-09-19
                                  • 2019-10-09
                                  • 2021-12-22
                                  相关资源
                                  最近更新 更多