什么是node

“Node全称NodeJS,是一个基于Chrome V8引擎的JavaScript运行环境;一个让JavaScript 运行在服务端的开发平台,它让JavaScript成为与PHP、Python、Perl等服务端语言平起平坐的脚本语言。”

node版本管理工具

NVM 下载链接 选择nvm-setup.zip下载解压即可运行可执行文件
nvm url

常用命令

  1. nvm list 是查找本电脑上所有的node版本

    • nvm list 查看已经安装的版本
    • nvm list installed 查看已经安装的版本
    • nvm list available 查看网络可以安装的版本
  2. nvm install 安装最新版本nvm

  3. nvm use ## 切换使用指定的版本node

  4. nvm ls 列出所有版本

  5. nvm current显示当前版本

  6. nvm alias ## 给不同的版本号添加别名

  7. nvm unalias ## 删除已定义的别名

  8. nvm reinstall-packages ## 在当前版本node环境下,重新全局安装指定版本号的npm包

  9. nvm on 打开nodejs控制

  10. nvm off 关闭nodejs控制

  11. nvm proxy 查看设置与代理

  12. nvm node_mirror [url] 设置或者查看setting.txt中的node_mirror,如果不设置的默认是 https://nodejs.org/dist/
      nvm npm_mirror [url] 设置或者查看setting.txt中的npm_mirror,如果不设置的话默认的是: https://github.com/npm/npm/archive/.

  13. nvm uninstall 卸载制定的版本

  14. nvm use [version] [arch] 切换制定的node版本和位数

  15. nvm root [path] 设置和查看root路径

  16. nvm version 查看当前的版本

node程序传递参数

在终端可以通过node运行js文件,一般命令为node 文件名.js ,但是在有些情况下需要传递参数的时候可以在该命令后添加相关参数,则参数会传递到程序内部。那么怎么获取呢?可以使用全局对象 process(进程)

在控制终端输入命令

1
node index.js 简单点

效果图如下:
node传递参数

node中常用的打印输出方式

命令 效果
console.log() 最常用的输入内容的方式
console.clear() 清空控制台
console.trace() 打印函数的调用栈

其他的方法,参考链接

常见的全局对象

特殊的全局对象

  • 这些全局对象实际上是模块中的变量,只是每个模块中都有,看起来像是全局变量
  • 在命令行交互中是不可以使用的
  • 包括: __dirname(目录名称)、__filename(文件名称)、exports、module、require()
1
2
console.log(__dirname);
console.log(__filename);
PS C:\Users\starry\Desktop\total\node\02_nodeGlobalObject\01_specialGlobalObject> node specialGlobalObject.js
C:\Users\starry\Desktop\total\node\02_nodeGlobalObject\01_specialGlobalObject
C:\Users\starry\Desktop\total\node\02_nodeGlobalObject\01_specialGlobalObject\specialGlobalObject.js

常见的全局对象

常见的定时器对象

问题1:为什么执行的顺序不一样?
问题2:为什么process.nextTick比setImmediate还快?

global全局对象

1
console.log(global)
 Object [global] {
  global: [Circular *1],
  clearInterval: [Function: clearInterval],
  clearTimeout: [Function: clearTimeout],
  setInterval: [Function: setInterval],
  setTimeout: [Function: setTimeout] {
    [Symbol(nodejs.util.promisify.custom)]: [Function (anonymous)]
  },
  queueMicrotask: [Function: queueMicrotask],
  clearImmediate: [Function: clearImmediate],
  setImmediate: [Function: setImmediate] {
    [Symbol(nodejs.util.promisify.custom)]: [Function (anonymous)]
  }
}

JavaScript的模块化

为了让Node.js的文件可以相互调用,Node.js提供了一个简单的模块系统。

模块是Node.js 应用程序的基本组成部分,文件和模块是一一对应的。换言之,一个 Node.js 文件就是一个模块,这个文件可能是JavaScript 代码、JSON 或者编译过的C/C++ 扩展。

立即执行函数实现的模块化

1
2
3
4
5
6
7
var moduleFoo = (function(){
return {
age,
name
}
})()

如果模块化同名也会产生冲突。

COMMON.JS规范

我们需要知道common.js是一个规范,最初提出来是在浏览器以外的地方使用,并且当时被命名为ServerJS, 后来为了体现它的广泛性,修改为CommonJS,平时我们也会简称为CJS.

  • NODE是commonJs在服务器端一个具有代表性的实现。
  • Browserify是COMMON.JS在浏览器中的实现。
  • webpack打包工具具备对CommonJs的支持与转换。

exports

每个模块都有一个为exports的对象,其默认值为空对象。

node中实现common.js的方式就是对象的引用赋值。

问题3:对象的引用赋值与深拷贝,浅拷贝实际是三种东西?

module.exports

会创建新的地址空间,默认为空的对象。
exports只能使用语法来向外暴露内部变量:如http://exports.xxx = xxx;
module.exports既可以通过语法,也可以直接赋值一个对象。

require

require是一种函数,可以帮助我们引入一个文件(模块)中导入的对象。

require的查找规则

官方文档

一、require的加载规则
1、优先从缓存加载
2、判断模块标识符

核心模块
自己写的模块(路径形式的模块)

第三方模块(node_modules):

  • 第三方模块的标识就是第三方模块的名称(不可能有第三方模块和核心模块的名字一致);
  • 开发人员可以把写好的框架库发布到npm上;
  • 使用者通过npm命令来下载,使用式:var 名称 = require(‘npm install【下载包】 的包名’);node_modules/express/package.json main;如果package.json或者main不成立,则查找被选择项:index.js;如果以上条件都不满足,则继续进入上一级目录中的node_modules按照上面的规则依次查找,直到当前文件所属此盘根目录都找不到最后报错.

require加载文件的顺序

  1. 在当前文件中,有通过require加载的文件,同时本文件有其他操作时,会先同步加载前面所导入的文件

  2. require在嵌套调用的时候,有的文件可能会被引入多次,但是执行时,同样的代码只会执行一次,因为在内部进行了缓存。在下方打印module的时候有一个loaded属性,如果是true就代表已经加载过,需要缓存;反之,就是没有加载过。

  3. 循环引用的加载顺序:深度优先

打印module

1
console.log(module)
PS C:\Users\starry\Desktop\total\node\03_JavaScript_module\02_commonjs> node bar.js
Module {
  id: '.',
  path: 'C:\\Users\\starry\\Desktop\\total\\node\\03_JavaScript_module\\02_commonjs',        
  exports: { name: 'jiang', age: 23 },
  parent: null,
  filename: 'C:\\Users\\starry\\Desktop\\total\\node\\03_JavaScript_module\\02_commonjs\\bar.js',
  loaded: false,
  children: [],
  paths: [
    'C:\\Users\\starry\\Desktop\\total\\node\\03_JavaScript_module\\02_commonjs\\node_modules',
    'C:\\Users\\starry\\Desktop\\total\\node\\03_JavaScript_module\\node_modules',
    'C:\\Users\\starry\\Desktop\\total\\node\\node_modules',
    'C:\\Users\\starry\\Desktop\\total\\node_modules',
    'C:\\Users\\starry\\Desktop\\node_modules',
    'C:\\Users\\starry\\node_modules',
    'C:\\Users\\node_modules',
    'C:\\node_modules'
  ]
}

AMD规范

全称是Asynchronous Module Definition,即异步模块加载机制。从它的规范描述页面看,AMD很短也很简单,但它却完整描述了模块的定义,依赖关系,引用关系以及加载机制。从它被requireJs,Dojo,JQuery使用也可以看出它具有很大的价值,没错,JQuery近期也采用了AMD规范。

AMD与COMMON.JS阮一峰博客

require.js in node

CMD规范

CMD 即Common Module Definition通用模块定义,CMD规范是国内发展出来的,就像AMD有个requireJS,CMD有个浏览器的实现SeaJS,SeaJS要解决的问题和requireJS一样,只不过在模块定义方式和模块加载(可以说运行、解析)时机上有所不同

SEA.JS
知乎:AMD与CMD的区别

ES6导出方式

方式一:

一个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取。如果你希望外部能够读取模块内部的某个变量,就必须使用export关键字输出该变量。下面是一个 JS 文件,里面使用export命令输出变量。

1
2
3
export var firstName = 'Michael';
export var lastName = 'Jackson';
export var year = 1958;

方式二:列表方式,大括号

是大括号,不是对象,一定要注意,在大括号中统一导出。
通常情况下,export输出的变量就是本来的名字,但是可以使用as关键字重命名。

1
2
3
4
5
6
7
8
9
function v1() { ... }
function v2() { ... }
function v3() { ... }

export {
v1 as streamV1,
v2 as streamV2,
v3 as streamLatestVersion
};

ES6导入方式

foo.js文件内容:

1
2
3
4
5
6
7
8
9
10
11
12
const name = "coderwhy";
const age = 18;
const sayHello = function(name){
console.log("hello" + name)
}

//
export {
name,
age,
sayHello
}

index.js文件内容:

最普通的导入方式

import {name,age,sayHello} from “./modules/foo.js”

第二种,导入变量后可以起别名

import {name as vName,age as vAge,sayHello as vSayHello} from “./modules/foo.js”

import {streamV1 as vName,streamV2 as vAge,streamLatestVersion as vSayHello} from “./modules/foo.js”

第三种 * as foo

import * as foo from ‘./modules/foo.js’

console.log(foo.name);
console.log(foo.age)
foo.sayHello(“coderwhy”)

本质是 将导入的 {name as vName,age as vAge,sayHello as vSayHello} 对象给foo对象,作为它的属性,然后在后方调用。

export与from的使用

—相当于从指定的js文件,导出需要导出的内容
foo.js文件内容:

const name = "coderwhy";
const age = 18;
const sayHello = function(name){
    console.log("hello" + name)
}
export {name,age,sayHello} from "./modules/foo.js"

1
2
3
console.log(name);
console.log(age);
sayHello("coderwhy");

default导出

默认导出,可以不给导出的文件加名字。

从前面的例子可以看出,使用import命令的时候,用户需要知道所要加载的变量名或函数名,否则无法加载。但是,用户肯定希望快速上手,未必愿意阅读文档,去了解模块有哪些属性和方法。

为了给用户提供方便,让他们不用阅读文档就能加载模块,就要用到export default命令,为模块指定默认输出。

export default命令用于指定模块的默认输出。显然,一个模块只能有一个默认输出,因此export default命令只能使用一次。所以,import命令后面才不用加大括号,因为只可能唯一对应export default命令。

// export-default.js
export default function foo() {
  console.log('foo');
}

// 或者写成

function foo() {
  console.log('foo');
}

export default foo;

动态加载

import()函数动态加载

1
2
<script src="./index.js" type="module"></script>
script标签加载是异步的,不回阻塞后面代码的执行。

可以在左侧修改值,不能在右侧改变变量的值。