ホームページ > 記事 > ウェブフロントエンド > Nodeのモジュール性、ファイルシステム、環境変数について詳しく説明した記事
この記事では、Node のモジュール化、ファイル システム、環境変数について詳しく説明します。一定の参考値があります。必要な友人が参照できるようにします。そうなることを願っています。みんなに役立つ。
#1.0. 変数スコープ(1). ブラウザ側で var を使用して定義した変数、またはキーワードを使用せずに定義した変数はグローバル スコープに属します。つまり、window オブジェクトを使用してアクセスできます。 [関連チュートリアルの推奨事項: nodejs ビデオ チュートリアル
、プログラミング教育 ] <script>
var a = 100;
(function () {
b = 200;
})();
console.log(window.a, a);
console.log(window.b, b);
</script>
#(2). Node.js には window オブジェクトがありません (3) Node.js の対話環境では、定義された変数はグローバルに属します. Global はブラウザ側の window オブジェクトに似ています
## (4) モジュール内(ファイル内)にグローバルオブジェクトがあり、キーワードでメンバを定義しますvar、let、const はグローバル オブジェクトに属しません。キーワードなしで定義されたオブジェクトはグローバル オブジェクトに属します。
うわー
终端输出:
1.1、模块概要
早期的javascript版本没有块级作用域、没有类、没有包、也没有模块,这样会带来一些问题,如复用、依赖、冲突、代码组织混乱等,随着前端的膨胀,模块化显得非常迫切。
前端模块化规范如下:
常见的的JavaScript模块规范有:CommonJS、AMD、CMD、UMD、原生模块化。
虽然我们学习过ES6的模块化但是ES6与NodeJS使用不同的模块化规范,单独学习NodeJS的模块化非常有必要。
模块化是指解决一个复杂问题时,自顶向下逐层把系统划分成若干模块的过程。对于整个系统来说,模块是可组合、分解和更换 的单元。
JavaScript在早期的设计中就没有模块、包、类的概念,开发者需要模拟出类似的功能,来隔离、组织复杂的JavaScript代码,我们称为模块化。
模块就是一个实现特定功能的文件,有了模块我们就可以更方便的使用别人的代码,要用什么功能就加载什么模块。
模块化开发的四点好处:
(1)、 避免变量污染,命名冲突
(2)、提高代码复用率
(3)、提高了可维护性
(4)、方便依赖关系管理
nodejs中根据模块的来源不同,将模块分为了3大类,分别是:
模块作用域。
和函数作用域类似,在自定义模块中定义的变量、方法等成员,只能在当前模块内被访问,这种模块级别的访问限制,叫做模块作用域。
模块作用域的好处:防止了全局变量污染的问题
1.2、CommonJS
CommonJS就是一个JavaScript模块化的规范,该规范最初是用在服务器端NodeJS中,前端的webpack也是对CommonJS原生支持的。
根据这个规范
(1)、每一个文件就是一个模块,其内部定义的变量是属于这个模块的,不会对外暴露,也就是说不会污染全局变量。
(2)、导入自定义的模块时路径需要以./或../开始,同一路径下也不能省略。
(3)、如果反复多次require模块,只加载一次。
(4)、require引入模块时,后缀名.js可以省略
(5)、每个模块文件都是一个独立的函数级作用域,在其它模块中不能直接访问
m1.js:
console.log("这是模块m1"); let a=100; b=200;
m2.js
var m11=require("./m1"); console.log(a); console.log(b);
结果:
从上面的示例可以看出a在模块2中是访问不到的,模块其实就是一个封闭的函数:
m1.js的代码如下:
console.log("这是模块m1"); let a=100; b=200; //输出当前函数 console.log(arguments.callee+"");
实际输出结果:
function (exports, require, module, __filename, __dirname) { console.log("这是模块m1"); let a=100; b=200; //输出当前函数 console.log(arguments.callee+""); }
(6)、每个模块中都包含如下5个对象:
exports:导出对象,默认为{}
require:导入函数,使用该函数可以实现模块的依赖
module:模块信息,用于记录当前模块的所有信息
__filename:当前模块的文件全路径,含文件名
__dirname:当前模块的文件路径不含文件名
(7)、使用exports或module.exports对象可以将当前模块中需要导出的内容暴露出去。
m1.js
let a=100; let b=()=>{ return 200; }; exports.a=a; exports.b=b;
m2.js
const m1=require("./m1"); console.log(m1); console.log(m1.a); console.log(m1.b());
结果:
(8)、导入模块内容可以结合结构语法
m1.js
exports.a=100; exports.b=function(){ return 200; };
m2.js
const {a,b:fun}=require("./m1"); console.log(a); console.log(fun());
结果:
1.3、NodeJS中使用CommonJS模块管理
CommonJS的核心思想就是通过 require 方法来同步加载所要依赖的其他模块,然后通过 exports 或者 module.exports 来导出需要暴露的接口。
CommonJS API编写应用程序,然后这些应用可以运行在不同的JavaScript解释器和不同的主机环境中。
2009年,美国程序员Ryan Dahl创造了node.js项目,将javascript语言用于服务器端编程。这标志"Javascript模块化编程"正式诞生。因为老实说,在浏览器环境下,以前没有模块也不是特别大的问题,毕竟网页程序的复杂性有限;但是在服务器端,一定要有模块,与操作系统和其他应用程序互动,否则根本没法编程。NodeJS是CommonJS规范的实现,webpack 也是以CommonJS的形式来书写。
CommonJS定义的模块分为:{模块引用(require)} {模块定义(exports)} {模块标识(module)} //require()用来引入外部模块; //exports对象用于导出当前模块的方法或变量,唯一的导出口; //module对象就代表模块本身。
Nodejs的模块是基于CommonJS规范实现的,通过转换也可以运行在浏览器端。
特点:
根据commonJS规范,一个单独的文件是一个模块,每一个模块都是一个单独的作用域,也就是说,在该模块内部定义的变量,无法被其他模块读取,除非为global对象的属性。
模块拥有像函数一样的函数级作用域:
每个模块内部,module变量代表当前模块
module变量是一个对象,它的exports属性(即module.exports)是对外的接口
加载某个模块,其实是加载该模块的module.exports属性。require()方法用于加载模块。
模块只有一个出口,module.exports对象,我们需要把模块希望输出的内容放入该对象。
mathLib.js模块定义
var message="Hello CommonJS!"; module.exports.message=message; module.exports.add=(m,n)=>console.log(m+n);
在 Node.js 中,创建一个模块非常简单,如下我们创建一个 'main.js' 文件,代码如下:
var hello = require('./hello'); hello.world();
以上实例中,代码 require('./hello') 引入了当前目录下的hello.js文件(./ 为当前目录,node.js默认后缀为js)。
Node.js 提供了exports 和 require 两个对象,其中 exports 是模块公开的接口,require 用于从外部获取一个模块的接口,即所获取模块的 exports 对象。
接下来我们就来创建hello.js文件,代码如下:
exports.world = function() { console.log('Hello World'); }
在以上示例中,hello.js 通过 exports 对象把 world 作为模块的访 问接口,在 main.js 中通过 require('./hello') 加载这个模块,然后就可以直接访 问main.js 中 exports 对象的成员函数了。
有时候我们只是想把一个对象封装到模块中,格式如下:
module.exports = function() { // ...}
例如:
//hello.js function Hello() { varname; this.setName = function(thyName) { name = thyName; }; this.sayHello = function() { console.log('Hello ' + name); }; }; module.exports = Hello;
这样就可以直接获得这个对象了:
//main.js var Hello = require('./hello'); hello = new Hello(); hello.setName('BYVoid'); hello.sayHello();
模块接口的唯一变化是使用 module.exports = Hello 代替了exports.world = function(){}。 在外部引用该模块时,其接口对象就是要输出的 Hello 对象本身,而不是原先的 exports。
加载模块用require方法,该方法读取一个文件并且执行,返回文件内部的module.exports对象。
在用require加载自定义模块期间,可以省略.js这个后缀名。
myApp.js 模块依赖
var math=require('./mathLib'); console.log(math.message); math.add(333,888);
3、测试运行
安装好node.JS
打开控制台,可以使用cmd命令,也可以直接在开发工具中访问
运行
也许你已经注意到,我们已经在代码中使用了模块了。像这样:
var http = require("http"); ... http.createServer(...);
Node.js中自带了一个叫做"http"的模块,我们在我们的代码中请求它并把返回值赋给一个本地变量。
这把我们的本地变量变成了一个拥有所有 http 模块所提供的公共方法的对象。
Node.js 的 require方法中的文件查找策略如下:
由于Node.js中存在4类模块(原生模块和3种文件模块),尽管require方法极其简单,但是内部的加载却是十分复杂的,其加载优先级也各自不同。如下图所示:
从文件模块缓存中加载
尽管原生模块与文件模块的优先级不同,但是都不会优先于从文件模块的缓存中加载已经存在的模块。
从原生模块加载
原生模块的优先级仅次于文件模块缓存的优先级。require方法在解析文件名之后,优先检查模块是否在原生模块列表中。以http模块为例,尽管在目录下存在一个http/http.js/http.node/http.json文件,require("http")都不会从这些文件中加载,而是从原生模块中加载。
原生模块也有一个缓存区,同样也是优先从缓存区加载。如果缓存区没有被加载过,则调用原生模块的加载方式进行加载和执行。
从文件加载
当文件模块缓存中不存在,而且不是原生模块的时候,Node.js会解析require方法传入的参数,并从文件系统中加载实际的文件,加载过程中的包装和编译细节在前一节中已经介绍过,这里我们将详细描述查找文件模块的过程,其中,也有一些细节值得知晓。
require方法接受以下几种参数的传递:
node_modules文件夹用来存放所有已安装到项目中的包。require()导入第三方包时,就是从这个目录中查找并加载包。
package-lock.json配置文件用来记录node_modules目录下的每一个包的下载信息,例如包的名字、版本号、下载地址等。
注意:不要手动修改node_modules或package-lock.json文件中的任何代码,npm包管理工具会自动维护它们。
在每个.js自定义模块中都有一个module对象,它里面存储了和当前模块有关的信息
每个模块内部,module变量代表当前模块
module变量是一个对象,它的exports属性(即module.exports)是对外的接口
加载某个模块,其实是加载该模块的module.exports属性。require()方法用于加载模块。
Node.js 提供一组类似 UNIX(POSIX)标准的文件操作API。 Node 导入文件系统模块(fs)语法如下所示:
var fs = require("fs")
2.1、异步和同步
Node.js 文件系统(fs 模块)模块中的方法均有异步和同步版本,例如读取文件内容的函数有异步的 fs.readFile() 和同步的 fs.readFileSync()。
异步的方法函数最后一个参数为回调函数,回调函数的第一个参数包含了错误信息(error)。
建议大家是用异步方法,比起同步,异步方法性能更高,速度更快,而且没有阻塞。
实例
创建 input.txt 文件,内容如下:
foo
创建 filereaddemo.js 文件, 代码如下:
const fs=require("fs"); //依赖内置模块fs,用于文件管理 //异步读取文件students.txt,设置读取成功时的回调函数,err表示错误信息,data表示数据 fs.readFile("students.txt",function(err,data){ if(err) throw err; console.log("异步:"+data+""); }); console.log("---------------"); //同步读取 let data=fs.readFileSync("students.txt"); console.log("同步:"+data+"");
以上代码执行结果如下:
接下来,让我们来具体了解下 Node.js 文件系统的方法。
2.2、获取文件信息
以下为通过异步模式获取文件信息的语法格式:
fs.stat(path, callback)
参数使用说明如下:
path - 文件路径。
callback - 回调函数,带有两个参数如:(err, stats), stats 是 fs.Stats 对象。
fs.stat(path)执行后,会将stats类的实例返回给其回调函数。可以通过stats类中的提供方法判断文件的相关属性。例如判断是否为文件:
const fs=require("fs"); fs.stat("students.txt",(err,stats)=>{ console.log("是文件吗?"+stats.isFile()); console.log("是目录吗?"+stats.isDirectory()); console.log(stats); });
結果:
stats クラスのメソッドは次のとおりです:
Method | 説明 |
---|---|
ファイルの場合は true を返し、それ以外の場合は false を返します。 | |
ディレクトリの場合は true を返し、それ以外の場合は false を返します。 | |
ブロック デバイスの場合は true を返し、それ以外の場合は false を返します。 | |
キャラクタ デバイスの場合は true を返し、それ以外の場合は false を返します。 | |
ソフト リンクの場合は true を返し、それ以外の場合は false を返します。 | |
FIFO の場合は true を返し、それ以外の場合は false を返します。 FIFO は、UNIX の特殊なタイプのコマンド パイプです。 | |
ソケットの場合は true を返し、それ以外の場合は false を返します。 |
説明 | |
---|---|
Asynchronous rename(). コールバック関数にはパラメータがありませんが、例外をスローする可能性があります。 | |
非同期 ftruncate() コールバック関数にはパラメータがありませんが、例外がスローされる可能性があります。 | |
同期された ftruncate() | |
Asynchronous truncate(). コールバック関数にはパラメータがありませんが、例外をスローする可能性があります。 | |
同期 truncate() | |
非同期 chown() コールバック関数にはパラメータがありませんが、例外をスローする可能性があります。 | |
Sync chown() | |
非同期 fchown() コールバック関数にはパラメータがありませんが、例外をスローする可能性があります。 | |
Sync fchown() | |
非同期 lchown(). コールバック関数にはパラメータがありませんが、例外をスローする可能性があります。 | |
Sync lchown() | |
非同期 chmod(). コールバック関数にはパラメータがありませんが、例外がスローされる可能性があります。 | #fs.chmodSync(path, mode) |
##fs.fchmod(fd, mode , callback) | |
fs.fchmodSync(fd, モード) | |
fs.lchmod(パス, モード) 、callback) | |
fs.lchmodSync(path, mode) | |
fs.stat(path, callback) | |
fs.lstat(path, callback) | |
fs.fstat(fd, callback) | |
fs.statSync(path) | |
fs.lstatSync(path) | |
fs.fstatSync(fd) | |
fs.link(srcpath, dstpath, callback) | |
fs.linkSync(srcpath, dstpath) | |
fs.symlink(srcpath, dstpath) [, type], callback) | |
fs.symlinkSync(srcpath, dstpath[, type]) | |
fs.readlink (path, callback) | |
fs.realpath(path[,cache], callback) | |
fs.realpathSync(path[, キャッシュ]) | |
fs.unlink(path, callback) | |
fs.unlinkSync(path) | |
fs.rmdir(path, callback) | |
#fs.rmdirSync(path) | Sync rmdir(). |
##fs.mkdir(path[, mode] , callback) | S 非同期 mkdir(2). コールバック関数にはパラメータがありませんが、例外がスローされる可能性があります。モードのデフォルトは 0777. |
fs.mkdirSync(path[, mode]) | Sync mkdir(). |
fs.readdir(path, callback) | 非同期 readdir(3) ディレクトリの内容を読み取ります。 |
fs.readdirSync(path) | 同期 readdir() ファイル配列リストを返します。 |
fs.close(fd, callback) | 非同期 close() コールバック関数にはパラメータがありませんが、例外がスローされる可能性があります。 |
fs.closeSync(fd) | Sync close(). |
fs.open(path, flags[,モード]、コールバック) | ファイルを非同期で開きます。 |
fs.open() のバージョンを同期します。 | |
? | |
ファイルを変更します指定されたファイル パスを通過したファイルのタイムスタンプ。 | |
??? | |
ファイル記述子で指定されたファイルのタイムスタンプを変更します。 | |
非同期 fsync. コールバック関数にはパラメータがありませんが、例外をスローする可能性があります。 | |
fs.fsyncSync(fd) | Sync fsync. |
ファイル記述子で指定されたファイルにバッファーの内容を書き込みます。 | |
ファイル記述子 fd を介してファイルの内容を書き込みます。 | |
fs.write() の同期バージョン。 | |
fs.write() の同期バージョン。 | |
#fs.readSync(fd, バッファ, オフセット, 長さ, 位置) | |
# の同期バージョン#fs.readFile(filename[, options], callback) | ファイルの内容を非同期的に読み取ります。 |
fs.readFileSync(ファイル名[, オプション]) | |
##fs.writeFile(ファイル名, データ[, オプション] 、コールバック) | ファイルの内容を非同期的に書き込みます。 |
fs.writeFileSync(filename, data[, options]) | fs.writeFile の同期バージョン。 |
fs.appendFile(filename, data[, options], callback) | ファイルの内容を非同期的に追加します。 |
fs.appendFileSync(filename, data[, options]) | fs.appendFile の同期バージョン。 |
fs.watchFile(filename[, options],listener) | ファイルの変更を表示します。 |
fs.unwatchFile(filename[,listener]) | ファイル名への変更の表示を停止します。 |
fs.watch(filename[, options][,listener]) | ファイル名の変更を表示します。ファイル名はファイルまたはディレクトリです。 fs.FSWatcher オブジェクトを返します。 |
fs.exists(path, callback) | 指定されたパスが存在するかどうかを検出します。 |
fs.existsSync(path) | fs.exists. |
fs.access(path[, mode]、callback) | 指定されたパスのユーザー権限をテストします。 |
fs.accessSync(path[, mode]) | fs.access の同期バージョン。 |
fs.createReadStream(path[, options]) | ReadStream オブジェクトを返します。 |
fs.createWriteStream(path[, options]) | WriteStream オブジェクトを返します。 |
fs.symlink(srcpath, dstpath[, type], callback) | Asynchronous symlink(). コールバック関数にはパラメータがありませんが、例外がスローされる可能性があります。 |
更多内容,请查看官网文件模块描述:File System。 三、参数与环境变量3.0、读取自定义配置文件数据 创立一个 在咱们的示例应用程序中它应该是这样的: config/default.json { "student":{ "name":"tom", "age":19 } } 先依赖模块config, npm i config 咱们将在咱们的应用程序中通过导入 const config=require("config"); console.log(config.get("student.name")); console.log(config.get("student.age")); 运行结果: 3.1、读取package.json配置参数 用于添加命令行的环境变量 package.json 可以配置config package.json { "name": "demo06", "config": { "foo": "123456" }, "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start":"node configtest.js" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "config": "^3.3.7" } } configtest.js console.log(process.env.npm_package_config_foo); 直接运行(node configtest.js)结果: 直接在命令行执行 node configtest,会输出undefined 使用 npm run start,会输出 123456 npm 设置包的config npm config set foo = 3000 就可以修改默认的配置内容 然后再执行 npm test 会输出 3000 3.2、环境变量的设置与读取 文件.env USER_ID="239482" USER_KEY="foobar" NODE_ENV="development" m3.js npm i dotenv //依赖模块 require("dotenv").config(); console.log(process.env.USER_ID); 输出结果: 239482
3.3. コマンドラインでシステム 操作環境変数の環境変数を取得します。 3.3.1.現在の利用可能なすべての環境変数を表示します。set を入力して表示します。 #3.3.2. 環境変数の確認「設定変数名」を入力します。たとえば、パス変数の値を確認する場合は、「set path3.3.3. 環境変数を変更します。」注: cmd コマンド ラインでの環境変数へのすべての変更は、現在のウィンドウに対してのみ有効であり、永続的な変更ではありません。つまり、この cmd コマンド ライン ウィンドウを閉じると、機能しなくなります。 環境変数を永続的に変更するには 2 つの方法があります。1 つはレジストリを直接変更する方法、もう 1 つは [マイ コンピュータ] -> [プロパティ] -> [詳細] (詳細を参照) を通じてシステムの環境変数を設定する方法です。1. 環境変数を変更します「set 変数名 = 変数の内容」と入力します。たとえば、パスを「d:\nmake.exe」に設定するには、「set path="d:\nmake.exe」と入力するだけです。 環境変数の変更は、追加ではなく、前の内容を現在の内容で上書きすることを意味することに注意してください。たとえば、上記のパスを設定した後、set path="c" を再入力すると、パスを再度確認すると、値は "d:\nmake.exe";" c" ではなく "c:" になります。 。2. 空に設定:特定の変数を空に設定したい場合は、「set variable name=」と入力します。 たとえば、「set path=」と指定すると、パスをチェックすると空になります。上で述べたように、これは現在のコマンド ライン ウィンドウでのみ機能することに注意してください。したがって、パスを表示するときは、「マイ コンピュータ」-「プロパティ」を右クリックしないでください...3. 変数にコンテンツを追加しますEnter "変数名=% 変数名%; 変数の内容を設定します。 (オーバーレイである 3 とは異なります)。たとえば、新しいパスを path に追加するには、「set path=%path%;d:\nmake.exe」と入力して d:\nmake.exe を path に追加し、「set path=%path%; 再度」を実行します。 c:" の場合、set path ステートメントを使用して表示すると、手順 3 のように c: だけではなく、d:\nmake.exe;c: が表示されます。3.3.4、一些常用的环境变量
假定当前的系统环境变量定义如下,注意JAVA_HOME: m3.js console.log(process.env.JAVA_HOME); 出力:
a、b はシステムで定義されています 現在のターミナルは powershell ではなく cmd であることに注意してください
ここで 123 が出力される理由は、変更後にコンピューターが再起動されなかったためです。 888まで。 4. 宿題4.1. ビデオに基づいて各クラスの例を完成させます。 4.2. モジュールcircle.jsを定義します。中央のモジュールで、円の円周を計算するためのメソッドと、円の面積を計算するためのメソッドの2つを定義します。次に、モジュールmain.jsを定義します。これはモジュールcircle.jsに依存しており、計算のためにモジュール内の2つのメソッドを呼び出します。 4.3. 設定ファイルpackage.jsonにポートとホストアドレスhostを定義し、Webサーバーを作成し、設定情報を参照してポートとホストアドレスの切り替え機能を実装します。 4.4. config を使用して 4.3 4.5. .env および dotenv を使用して 4.3 4.6. システム環境変数を使用して 4.3 5. ビデオhttps://www.bilibili.com/video/BV1WW411B78S ノード関連の知識の詳細については、以下を参照してください。 nodejs チュートリアル! |
以上がNodeのモジュール性、ファイルシステム、環境変数について詳しく説明した記事の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。