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

Let's say I have a file called app.js. Pretty simple:

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

What if I have a functions inside "tools.js". How would I import them to use in apps.js?

Or...am I supposed to turn "tools" into a module, and then require it? << seems hard, I rather do the basic import of the tools.js file.

转载于:https://stackoverflow.com/questions/5797852/in-node-js-how-do-i-include-functions-from-my-other-files

csdnceshi62
csdnceshi62 I created a module to import scripts, export to file, and include module from outside node_modules folder. npmjs.com/package/node-import Hope it can help. Thanks!
5 年多之前 回复
csdnceshi71
Memor.の What threw me off here was requireing a folder in the same directory on Windows. You've got to use unix-style addressing: ./mydir instead of plain old mydir.
大约 6 年之前 回复

21个回答

You can require any js file, you just need to declare what you want to expose.

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

var zemba = function () {
}

And in your app file:

// app.js
// ======
var tools = require('./tools');
console.log(typeof tools.foo); // => 'function'
console.log(typeof tools.bar); // => 'function'
console.log(typeof tools.zemba); // => undefined
csdnceshi78
程序go in case anyone battles when they have a folder like 'src/myFile' - you need to do: require (./src/myFile').
2 年多之前 回复
csdnceshi73
喵-见缝插针 Good job on the 890 upvotes
接近 3 年之前 回复
csdnceshi57
perhaps? A note to newbies who are like me, the functions definitions in the module are separated by commas, not by semicolons or just new lines.
3 年多之前 回复
csdnceshi60
℡Wang Yan use this. e.g. console.log(typeof this.bar);
大约 4 年之前 回复
weixin_41568131
10.24 Where do you put global variables in this tools.js script? Above the 'module.exports = {' part?
大约 4 年之前 回复
weixin_41568183
零零乙 Answer states usage as tools.foo; I found that the function HAS to have the parentheses at the end like tools.foo(); Took me an hour to figure that out as it kept returning NaN. :-)
4 年多之前 回复
weixin_41568196
撒拉嘿哟木头 you can require any js file seems inconsistent with requirement for it to be formatted as per foo() and bar()
4 年多之前 回复
csdnceshi74
7*4 Used `var SomeClass = ... ; module.exports = SomeClass;
5 年多之前 回复
csdnceshi72
谁还没个明天 how to call function bar() ,inside foo() function, means how to access one function withn another
大约 6 年之前 回复
csdnceshi51
旧行李 How to run initialization code in the require() call?
6 年多之前 回复
csdnceshi63
elliott.david This post should be marked as the correct answer imo. Nice.
6 年多之前 回复
csdnceshi80
胖鸭 Since you are exposing properties I would use exports instead of module.exports. For exports vs module.exports : stackoverflow.com/questions/5311334/…
接近 7 年之前 回复
csdnceshi55
~Onlooker Like zemba in place of baz
大约 7 年之前 回复
csdnceshi76
斗士狗 And what if I have to pass variable into function Like, bar: function(a, b){ //some code }
7 年多之前 回复
csdnceshi52
妄徒之命 I wonder if it's possible to import external scripts. require("http://javascript-modules.googlecode.com/svn/functionChecker.js") doesn't seem to import the module correctly. Is there any other way to import external scripts?
接近 8 年之前 回复
csdnceshi69
YaoRaoLov +1 Nicely done, even confines the imported code to it's own namespace. I'll have to make a note of this for later.
接近 9 年之前 回复

If, despite all the other answers, you still want to traditionally include a file in a node.js source file, you can use this:

var fs = require('fs');

// file is included here:
eval(fs.readFileSync('tools.js')+'');
  • The empty string concatenation +'' is necessary to get the file content as a string and not an object (you can also use .toString() if you prefer).
  • 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).

Please note that in most cases this is bad practice and you should instead write a module. However, there are rare situations, where pollution of your local context/namespace is what you really want.

Update 2015-08-06

Please also note this won't work with "use strict"; (when you are in "strict mode") because functions and variables defined in the "imported" file can't be accessed by the code that does the import. Strict mode enforces some rules defined by newer versions of the language standard. This may be another reason to avoid the solution described here.

weixin_41568127
?yb? It dosn't transform exceptions into warnings but emits a warning instead of an exception as said here: php.net/manual/en/function.require.php
3 年多之前 回复
csdnceshi58
Didn"t forge are you implying that php include transforms exceptions into warnings? I don't think so
3 年多之前 回复
weixin_41568127
?yb? To be more specific in php include and require handles errors differently. So if you want an equivalent to php's include you will need to surround the require with a try catch block and show a warning
3 年多之前 回复
csdnceshi58
Didn"t forge Bling: that's not correct. require() can only provide variables/values and execute code in the module. eval can potentially mess with local variables and in non-strict mode even declare new locally scoped variables. I wouldn't recommend eval() either, but the fact is, eval has different side effects and can do more (dangerous things) than require()
大约 4 年之前 回复
weixin_41568208
北城已荒凉 Stinks for debugging. When there's an error in the included file, it can't tell what file it came from.
接近 5 年之前 回复
csdnceshi58
Didn"t forge unless you do some hacky things you didn't mention, then you're creating a local scope this way. That means the include() function can't export variables or functions. It can, however, access other variables that are accessible to the include() function itself, like a router instance, for example - but that's a specific case and does not qualify as a generic include-function. There are some solutions, though - please see the other answers.
5 年多之前 回复
csdnceshi55
~Onlooker Hmm... Well, I was able to break up my routes/index.js into several includes: authenticated.inc.js, nonauthenticated.inc.js, admin.inc.js, etc. In this way I can segment the code better so that I'm not paging through lots of it.
5 年多之前 回复
csdnceshi58
Didn"t forge Sorry, but that won't really work. Such an include function creates a new scope so you won't be able to access global variables or functions of the included file.
5 年多之前 回复
csdnceshi55
~Onlooker I liked this approach. I just wrapped a function call around it like this, though: function(inc) { eval(fs.readFileSync(inc, 'utf-8').toString()); } And then it's called like this: include('./routes/admin.inc.js'); I like renaming include files so that they're not mistaken by someone else as stand-alone.
5 年多之前 回复
weixin_41568134
MAO-EYE Cool trick but this works as long as tools.js does not depend on any other JS file. However if tools.js needs foo.js, this approach will fail (assuming you do not want to put eval/readFileSync inside tools.js too)
接近 6 年之前 回复
csdnceshi51
旧行李 Note that is incompatible with use strict - as use strict will constrain the use of eval by blocking introduction of new variables through eval, etc.
6 年多之前 回复
csdnceshi69
YaoRaoLov This worked for me and I simply wanted to consume a manually set variable in a global which is share with the client side app. +1
接近 7 年之前 回复
weixin_41568184
叼花硬汉 I would like to use require, but then I can't use John Resig's simple inheritance code (unless I'm mistaken/someone has a solution without using readFileSync)
8 年多之前 回复
csdnceshi73
喵-见缝插针 There are sometimes when you need include, and sometimes require, they are two fundamentally different concepts in most programming languages, Node JS as well. The ability to include js in place should be a part of Node to be honest, but eval'ing it is essentially a decent solution. Upvoted.
8 年多之前 回复
csdnceshi61
derek5. do you have a better suggestion which actually answers the question? If you need to include a file which is not a module, do you have a better approach than this?
8 年多之前 回复
csdnceshi58
Didn"t forge I just answered the original question, which is about including code, not writing modules. The former can have advantages in certain situations. Also, your assumption about require is wrong: The code is certainly eval'd, but it remains in it's own namespace and has no way to "pollute" the namespace of the calling context, hence you need to eval() it yourself. In most cases using the method described in my anwer is bad practice but it's not me that should decide if it is for TIMEX.
接近 9 年之前 回复
csdnceshi75
衫裤跑路 Blindly importing JS into the global namespace can open the code to unintended naming conflicts. If the code in the tools.js file were written in object literal format you could assign them to a local variable which works like a pseudo-namespace. Also, I don't really think the eval is required (masylum's code makes it seem like the code is already eval'd during the require). I think you're import/eval-ing the code with require, casting that code back to string and eval-ing it again just to pidgeonhole it into the global namespace. Looks like you're doing it wrong.
接近 9 年之前 回复
csdnceshi75
衫裤跑路 The "+''" is just a shortcut to force string casting. The more readable solution would be "String(fs.readFileSync('tools.js'))" or if the read.FileSync returns an object then "fs.readFileSync('tools.js').toString()" should also work since toString is attached to the base Object prototype (i.e Object.prototype.toString).
接近 9 年之前 回复
csdnceshi52
妄徒之命 Cool, this is useful for quick'n'dirty putting JS libs designed for client-side into a node.js app without the need of maintaining a Node-styled fork.
接近 9 年之前 回复

You need no new functions nor new modules. You simply need to execute the module you're calling if you don't want to use namespace.

in tools.js

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

in app.js

or in any other .js like myController.js :

instead of

var tools = require('tools.js') which force us to use a namespace and call tools like tools.sum(1,2);

we can simply call

require('tools.js')();

and then

sum(1,2);

in my case I have a file with controllers ctrls.js

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

and I can use Categories in every context as public class after require('ctrls.js')()

csdnceshi50
三生石@ This is a great tip! Caveat: if you declare the module.exports function using the () => {} shortcut syntax rather than the standard function() {} declaration, it fails. Took me an hour to figure out where the problem was! (Arrow functions don't have their own 'this' property: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…)
大约 2 年之前 回复
weixin_41568208
北城已荒凉 this just changed my life, no joke -- had a 1000+ line file that I couldn't break up because the variables of different methods are all inter-correlated and would need the requires to be all in the same scope ... require('blah.js')(); should allow me to import them all into the same scope!!! thanks!!!
3 年多之前 回复
csdnceshi73
喵-见缝插针 Panov: brilliant! It should be worth to note that this works because this in a function is the global scope when the function is called directly (not bound in any way).
大约 4 年之前 回复
csdnceshi73
喵-见缝插针 why not? Don't see any problem with strict mode..
大约 4 年之前 回复
csdnceshi79
python小菜 In some scenarios, it is required to specify a path in the require function (i.e. './tools.js') in order to be recognized.
4 年多之前 回复
csdnceshi58
Didn"t forge Note that you cannot "use 'strict" mode in the imported module.
4 年多之前 回复
csdnceshi71
Memor.の This trick seems comparable to PHP traits and "from x import y" in Python. Powerful, but should be used with care as it adds external stuff to the scope, so it's easier to break stuff and harder to see where variables actually come from. Usually, it would be better to import methods/properties and use the proper namespacing objects. But a useful trick to know nevertheless!
接近 5 年之前 回复
weixin_41568127
?yb? Same as when you overwrite other variables? With require('module.js')(); You actually execute the code from the module in the current scope. It's convenient when you need to import some global scope objects defined as namespaces in the module itself.
大约 5 年之前 回复
weixin_41568110
七度&光 But what if you require different js files that use the same function names? Which "sum" will be called if different modules have a 'sum' function?
大约 5 年之前 回复
csdnceshi75
衫裤跑路 How does this not have more +1s? This is a real solution to what the question asks (albeit not the 'official' one). It's also a million times easier to debug than eval() because node can give a useful call stack instead pointing to the actual file instead of just undefined.
5 年多之前 回复

Create two js files

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

Main js file

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

Output

value: 30

I was also looking for a NodeJS 'include' function and I checked the solution proposed by Udo G - see message https://stackoverflow.com/a/8744519/2979590. His code doesn't work with my included JS files. Finally I solved the problem like that:

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

Sure, that helps.

You can put your functions in global variables, but it's better practice to just turn your tools script into a module. It's really not too hard – just attach your public API to the exports object. Take a look at Understanding Node.js' exports module for some more detail.

Include file and run it in given (non-global) context

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

I've come up with a rather crude method of handling this for HTML templating. Similarly to 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>

Loaded Page Result

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

I was as well searching for an option to include code without writing modules, resp. use the same tested standalone sources from a different project for a Node.js service - and jmparattes answer did it for me.

The benefit is, you don't pollute the namespace, I don't have trouble with "use strict"; and it works well.

Here a full sample:

Script to load - /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'
    }

}

Hope this was helpfull somehow.

say we wants to call function ping() and add(30,20) which is in lib.js file from 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
    }
csdnceshi77
狐狸.fox This works, but aren't we supposed to use the modules syntax when including scripts?
大约 5 年之前 回复
共21条数据 1 3 尾页
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问
相关内容推荐