一、Node开发需要模块化

概念

ES6之前

ECMAScript存在以下几个问题

  1. 没有模块系统
  2. 官方标准库少/标准接口少
  3. 缺乏包管理系统

模块化

  1. 如果程序设计的规模达到了一定程度,则必须对其进行模块化
    前端没多大必要, 所以不太需要
    服务器端开发, 没有模块化开发思想就玩不转了
  2. 模块化可以有多种形式,但都提供了能够将代码分割为多个源文件的机制
    Common.js

CommonJS规范

  1. CommonJS规范的提出,主要是为了弥补JavaScript没有模块化标准的缺陷
  2. CommonJS规范为JS希望JS能够在任何地方运行:这是一个美好的愿景
  3. CommonJS对模块的定义
    模块引用:require(“路径”);
    模块定义
    模块标识

总结

  1. 从文件角度看, 每个JS文件就是一个模块
  2. 从结构看, 多个JS文件之间可以相互require,共同实现了一个功能,这整体上也是一个模块
  3. 在Node.js中,一个模块中定义的变量、 函数等, 都只能在这个文件内部有效
  4. 当需要从此JS文件外部引用这些变量,、函数时,必须使用exports进行暴露,使用者通过require引用

实践1

  1. 在Node中,一个js文件就是一个模块

  2. 在Node中,通过require()函数来引入外部的模块
    引入外部模块要加上 . 或者 …

  3. 在Node中,每一个js文件中的js代码都是独立运行在一个小闭包中, 而不是全局作用域,所以一个模块的中的变量和函数在其他模块中无法访问
    目的: 全局变量私有化, 避免全局污染

  4. 暴露模块中的变量和函数
    export
    只需要将需要暴露给外部的变量或方法设置为exports的属性即可

    02.js

    let site = 'www.itlike.com';
    
    let log = ()=>{
       console.log('这是一个神奇的网站:', site);
    };
    
    exports.site = site;
    exports.log = log;
    

    03.js

    // 1. 引入其它模块
    let  fn = require('./02.js');
    // console.log(fn);
    console.log(fn.site);
    fn.log();
    
    

实践2

模块标识

  1. 当我们使用require()引入外部模块时,使用的就是模块标识,我们可以通过模块标识来找到指定的模块
    比如: let myFunc = require("./js/myFunc");
  2. 分类
    ① 内建模块:底层由C++编写
    ② 文件模块:由用户自己创建的模块
    标识:文件的路径(绝对路径,相对路径)
    ③ 核心模块:由node引擎提供的模块、由node_modules提供的模块
    标识:模块的名字、http、fs、global…

思考: export和require怎么来的?

  1. 错误答案: 全局变量
    1)window不是Node中的全局对象
    2)Node中有一个全局对象global, 作用和window类似
  2. 正确答案: 函数参数
    1)函数的标识: arguments
    获取函数的所有实参
    2)获取函数自身 arguments.callee
    返回函数本身

node文件组成剖析

  1. 当node在执行模块中的代码时,它会首先在代码的最顶部,添加如下代码 function (exports, require, module, __filename, __dirname) {
  2. 在代码的最底部,添加 }
  3. 所以模块中的代码都是包装在一个函数中执行的,并且在函数执行的同时传递进了5个实参
    ① exports: 该对象用来将函数内部的局部变量或局部函数暴露到外部
    ② require: 用来引入外部的模块
    ③ module: 代表的是当前模块本身, exports就是module的属性; 我们既可以使用 exports 导出,也可以使用module.exports导出
    ④ __filename: 当前模块的完整路径
    ⑤ __dirname: 当前模块所在文件夹的完整路径

Node中的Common.js

  1. 在node.js 里,模块划分所有的功能,每个JS都是一个模块

  2. 实现require方法,NPM实现了模块的自动加载和安装依赖

  3. 内部形式

    (function(exports,require,module,__filename,__dirname){
      exports = module.exports={}
      exports.brands = 'itlike';
      exports = {brands :'itlike'};
      return module.exports;
    })
    

exports 和 module.exports的区别

两者区别

  1. 在每一个模块中,最终返回的是module.exports.
    exports类似一根指针,指向module.exports。因此,exports只能通过点语法获取并向外输出,无法通过赋值对象输出。
    (function(exports,require,module,__filename,__dirname){
        exports = module.exports={};
    
    
        return module.exports;
    })
    
    所以module改变方式是不受影响的,但exports改变就无法正确返回。
  2. exports只能使用.语法来向外暴露内部变量
    exports.xxx = xxx;
  3. module.exports既可以通过.语法,也可以直接赋值一个对象
    module.exports.xxx = yyy;
    module.exports = {xxx: yyy};

值类型和引用类型

Node.js:Node模块简介_当前目录

二、module&NPM

模块分类

原生模块

http path fs util events 编译成二进制,加载速度最快,原生模块是通过名称来加载

文件模块

  1. 在硬盘的某个位置,加载速度非常慢,文件模块通过名称或路径来加载
  2. 文件模块的后缀有三种
    ① 后缀名为.js的JavaScript脚本文件,需要先读入内存再运行
    ② 后缀名为.json的JSON文件,需要借助fs模块读入内存,转化成JSON对象
    ③ 后缀名为.node的经过编译后的二进制C/C++扩展模块文件,可以直接使用
  3. 注意
    ① 一般自己写的通过路径来加载
    ② 其他人写的通过名称去当前目录或全局的node_modules下面去找

第三方模块

  1. 如果require函数只指定名称,则视为从node_modules下面加载文件,这样的话,我们可以移动模块而不需要修改引用的模块路径
  2. 第三方模块的查询路径包括module.paths和全局目录
  3. 全局目录
    ① window如果在环境变量中设置了NODE_PATH变量,并将变量设置为一个有效的磁盘目录,require在本地找不到此模块时,会向上在此目录下继续找这个模块
    ② UNIX操作系统中会从 $HOME/.node_modules $HOME/.node_libraries目录下寻找
  4. 模块加载策略
    Node.js:Node模块简介_模块化_02

  1. 在Node.js中,可以通过包来对一组具有相互依赖关系的模块进行统一管理,通过包可以把某个独立功能封装起来
  2. 每个项目的根目录下面,一般都有一个package.json文件,定义了这个项目所需要的各种模块,以及项目的配置信息(比如名称、版本、许可证等元数据)
  3. 使用npm init命令初始化包
  4. npm install命令根据这个配置文件,自动下载所需的模块,也就是配置项目所需的运行和开发环境
  5. 图示
    Node.js:Node模块简介_node.js_03

NPM

概念

  1. 安装完node之后只能使用Node语言特性及核心函数,我们还需要一个系统来下载、安装和管理第三方模块。
  2. 在 Node看这个系统被称为Node包管理器(Node Package Manager,NPM)

npm提供的功能

  1. 公共注册服务,用户可以把自己写的包上传到服务器上
  2. 命令行下载工具,用户可以通过npm命令把别人写的包下载到自己电脑上,还可以管理自己模块依赖的其它模块
  3. 搜索第三方包的地址:https://www.npmjs.com/search

npm命令

  1. 安装包
    打开命令行或终端,进入要安装包的目录,然后执行以下命令安装依赖的模块
    npm install <package-name>
    npm i jquery
    此命令会从服务器上下载此模块到当前目录下的node_modules目录下,如果node_modules目录不存在则会创建一个, 也可以安装特定的版本
    npm install <package name>@<version spec>
    npm i jQuery@3.1
    npm i mime@2.x
  2. 卸载包
    npm uninstall <package name>
  3. 更新包
    npm update <package name>

包的安装模式

  1. 本地安装
    ① 默认情况下安装命令会把对应的包安装到当前目录下,这叫本地安装
    ② 如果包里有可执行的文件,NPM会把可执行文件安装到./node_modules/.bin目录下
    ③ 本地安装的模块只能在当前目录和当前目录的子目录里面使用
  2. 全局安装
    ① 希望安装的包能够在计算机机的所有目录下面都能使用,就需要全局安装
    npm install <package-name> -g
    ② 在全局安装的模式下,npm会把包安装到全局目录,通过此命令可以查看当前全局目录的位置
    Node.js:Node模块简介_模块化_04
    ③ 如果要修改全局安装目录,可以使用
    npm config set prefix “E:\node.js\node_global”
  3. 注册、登录和发布模块
    注册npm账号 https://www.npmjs.com/
    登录,npm login
    发布,npm publish

yarn

概念

  1. yarn 是一个依赖管理工具
  2. 它能够管理你的代码,并与全世界的开发者分享代码
  3. 代码是通过包(有时也被称为模块)进行共享的
  4. 在每一个包中包含了所有需要共享的代码,另外还定义了一个package.json文件,用来描述这个包

安装yarn

npm yarn --save -g

初始化一个新的项目

yarn init

添加一个依赖包

yarn add [package]
yarn add [package]@[version]
yarn add [package]@[tag]

更新一个依赖包

yarn upgrade [package]
yarn upgrade [package]@[version]
yarn upgrade [package]@[tag]

删除一个依赖包

yarn remove [package]

安装所有的依赖包

yarn
yarn install