Nodejs模块化

目录

 

1.模块的了解

1.1什么是模块

1.2 什么是模块化

1.3 模块化的规范

       1.commonJS规范

2.模块的分类

2.1 模块的分类

2.2 内置模块

2.3 自定义模块

3. commen 模块化

3.1 commen模块的组成

3.2 require函数(重要)

3.3 exports 导出数据

3.4 模块对象module

4. NodeJS作用域

4.1 作用域

4.2 暴露数据

5.模块的共性


模块化Module

NodeJs 采用模块化方式,管理和组织代码,NodeJS的所有功能都存在每个模块中.

1.模块的了解

1.1什么是模块

模块:一个具有特定功能的文件就是一个模块

模块的优点: 有了模块,我们就可以非常方式使用这些模块,因为模块总是完成了特定的功能,如果要修改模块中个功能,那么需要修改这个自己的模块文件即可,模块独立于每一个文件中,不影响模块的代码.

模块之间是相互独立的,如果一个模块中引入另一个模块,要用到里面的值,那么必须在被引入的模块中暴露这些值.

1.2 什么是模块化

模块化: 将一个复杂的程序依据一定的规则(规范)封装成几个模块(文件),并进行组合在一起,每个模块内部数据实现私有的, 只是向外部暴露一些接口(方法)与外部其他模块通信

模块的进化

1.全局开发模式 

// 全局开发模式
// 最早期所有的js代码卸载一个js文件中
function foo(){}

function add(){}

// 造成的问题,就是代码量过大以后,Global全局被污染,很容易导致命名冲突

所有js代码均在一个js文件中,代码量会很大,很容易导致命名冲突.

2.对代码进行简单的封装

// 简单封装: Namespac 模式, 就是我们俗称的命名空间
var Namespac = {
    foo: function(){},
    bar: function(){}
}
// 减少Global上的变量数目
// 本质就是对象,不太安全

3.IIFE模式

// 匿名闭包: IIFE模式
var Module = (function(){
    var foo = function(){
        
    }
    
    return {
        foo: foo
    }
})()

Module.foo()

// 函数是JavaScript 的Local Scope

4.模块模式

有时候在一个模块中需要引入其他模块,这就需要我们注入模块.

// 增强封装, 引入依赖
var Module = (function($){
    var $body = $(body);
    var foo = function(){
        
    }
    
    return {
        foo:foo
    }
})($)

1.3 模块化的规范

  1. CommonJS(NodeJS)

  2. AMD

  3. CMD

  4. ESModule (ES模块化)

在这里我们主要了解commonJS规范,

1.commonJS规范

Node 应用由模块组成,采用 CommonJS 模块规范。

每个文件就是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见。

CommonJs是一种规范,NodeJS是对这个规范的实现.

在这个规范中每一个模块都是一个独立的模块.

特点:

  1. 在服务器端:模块的加载是运行时同步加载

  2. 在浏览器端,模块需要提前编译打包处理

 

2.模块的分类

2.1 模块的分类

  1. 系统模块:NodeJS开发 团队已经开发了很多功能模块,不需要卸载,直接 引入就可以使用
  2. 第三方模块:第三方模仿必须要先安装再使用,要使用包管理工具npm进行安装
  3. 自定义模块:自己写的一个js文件,在使用了模块化语法后就是一个自定义模块

2.2 内置模块

NodeJs中的内置了很多模块,可以直接使用require来进行引用.国际惯例,你接受的名字最好和模块的名字一样 .

const http = require("http");

如果引入的模块名字特别长也可以简写:

const qs = require('querystring')

内置模块的引用是无条件的,无路径的 .

2.3 自定义模块

自定义模块:自己所写的js文件就是一个模块,Node.js使用commonjs规范 .

定义a模块

let str = "hello World";
console.log(str);
exports.str = str;  //exports用来暴露数据,后面会详细介绍到.

定义b模块,并在其中引入a模块

//此时的a是在a.js中暴露的对象
let a = require("./a");
//如果要使用,则必须通过a.str才能访问到
console.log(a.str);

 在文件夹中打开Powershell 通过命令 node b.js来执行

会发现require()谁,就会执行谁,会让a.js文件执行

tips:

  1. 会发现require()谁,就会执行谁,会让a.js文件执行

  2. require()引入的模块如果有异步语句,不会死等,会将所有的同步执行完毕后在执行异步语句

  3. 如果是多层引用会先把引入文件里的引入执行干净了

  4. 如果循环引用.A引用B,B引入A,Node会很智能的组织好第二次引入

3. commen 模块化

3.1 commen模块的组成

在模块中打印当前的模块信息

console.log(arguments)
console.log(arguments.callee.toString); // 打印函数体

打印的arguments如下:

[Arguments] {
  '0': {},
  '1': [Function: require] {
    resolve: [Function: resolve] { paths: [Function: paths] },
    main: Module {
      id: '.',
      path: 'C:\\Users\\wuhon\\Desktop\\favorite\\框架\\nodeCode\\day01',
      exports: {},
      parent: null,
      filename: 'C:\\Users\\wuhon\\Desktop\\favorite\\框架\\nodeCode\\day01\\b.js',
      loaded: false,
      children: [Array],
      paths: [Array]
    },
    extensions: [Object: null prototype] {
      '.js': [Function],
      '.json': [Function],
      '.node': [Function]
    },
    cache: [Object: null prototype] {
      'C:\\Users\\wuhon\\Desktop\\favorite\\框架\\nodeCode\\day01\\b.js': [Module],
      'C:\\Users\\wuhon\\Desktop\\favorite\\框架\\nodeCode\\day01\\a.js': [Module]
    }
  },
  '2': Module {
    id: '.',
    path: 'C:\\Users\\wuhon\\Desktop\\favorite\\框架\\nodeCode\\day01',
    exports: {},
    parent: null,
    filename: 'C:\\Users\\wuhon\\Desktop\\favorite\\框架\\nodeCode\\day01\\b.js',
    loaded: false,
    children: [ [Module] ],
    paths: [
      'C:\\Users\\wuhon\\Desktop\\favorite\\框架\\nodeCode\\day01\\node_modules',
      'C:\\Users\\wuhon\\Desktop\\favorite\\框架\\nodeCode\\node_modules',
      'C:\\Users\\wuhon\\Desktop\\favorite\\框架\\node_modules',
      'C:\\Users\\wuhon\\Desktop\\favorite\\node_modules',
      'C:\\Users\\wuhon\\Desktop\\node_modules',
      'C:\\Users\\wuhon\\node_modules',
      'C:\\Users\\node_modules',
      'C:\\node_modules'
    ]
  },
  '3': 'C:\\Users\\wuhon\\Desktop\\favorite\\框架\\nodeCode\\day01\\b.js',
  '4': 'C:\\Users\\wuhon\\Desktop\\favorite\\框架\\nodeCode\\day01'
}

打印出的函数体:

function (exports, require, module, __filename, __dirname) {    
	console.log(arguments.callee.toString())
}

所有用户编写的代码都自动封装一个函数中,函数有五个参数,我们就可以在函数内部使用五个实参.

五个参数:

  1. exports: 是一个对象,暴露对象,可将模块中的数据暴露给需要引入的该模块的其他模块;
  2. require :是一个函数,引入模块的函数,用于在一个模块中引入另外一个模块,并将子模块暴露的数据赋值给变量;
  3. module : 是一个对象,模块对象包含了模块的所有信息(当前模块信息);
  4. __filename : 当前文件所在路径;
  5. __dir :当前文件夹的路径.

3.2 require函数(重要)

require(moduleId)函数用于在当前模块中加载和使用别的模块,传入一个模块名,返回一个模块导出对象

 '1': [Function: require] {
    resolve: [Function: resolve] { paths: [Function: paths] },
    main: Module {
      id: '.',
      path: 'C:\\Users\\wuhon\\Desktop\\favorite\\框架\\nodeCode\\day01',
      exports: {},
      parent: null,
      filename: 'C:\\Users\\wuhon\\Desktop\\favorite\\框架\\nodeCode\\day01\\b.js',
      loaded: false,
      children: [Array],
      paths: [Array]
    },
    extensions: [Object: null prototype] {
      '.js': [Function],
      '.json': [Function],
      '.node': [Function]
    },
    cache: [Object: null prototype] {
      'C:\\Users\\wuhon\\Desktop\\favorite\\框架\\nodeCode\\day01\\b.js': [Module],
      'C:\\Users\\wuhon\\Desktop\\favorite\\框架\\nodeCode\\day01\\a.js': [Module]
    }
  },

./表示当前路径,模块文件的后缀名.js课省略.

let foo = require('./foo'); 
let foo2 = require('./foo.js')

如果省略了后缀名,则会优先找js文件,没有js文件会找json文件,没有json文件则会找node文件.

tips:

  1. 引入模块文件有语法错误时会报错

  2. 引入模块不存在时会报错

  3. 重复引入模块只会执行一次(返回值会被缓存起来)

  4. 所有的模块如果没有返回值,导入的模块中将返回空对象

  5. 导入自定义模块必须加'./' 因为在node.js中查找 模块默认是在node_modules目录中查找的

  6. 如果引入第三方模块,直接写模块的名字就可以了require("jquery")

第三点第四点详解:

定义模块a:

console.log("a.js");
let num = 5;
//并没有使用exports向外面暴露数据

在模块b中引入模块a,在这里我引入了3次模块a;

let a = require("./a");
let b = require('./a');
let c  = require('./a');
console.log(a);
console.log(b);
console.log(c);

执行代码观察执行的结果:

可以看到在没有暴露数据的情况默认会返回空对象,在这里我引入了3次a.js,所以打印出来3个a.js.

而且我们可以看到a.js只被打印了一次,说明虽然我们多次的引入了a.js,但是a.js只执行了一次.后面会直接在缓存区找数据,不会再次执行a.js.

 3.3 exports 导出数据

exports 对象是当前模块的导出对象,用于导出模块共有的方法和属性,别的模块在通过require函数导入使用当前模块时就会获得当前模块的exports 对象 .

exports.hello = function(){
    console.log("hello World")
}

注意事项:

  1. exports 是module.exports对象的引用

  2. exports 不能改指向,只能添加属性和方法

如果希望更改暴露指向,那么我 们就需要使用modeule.exports进行暴露 .

定义a模块

console.log("a.js");
let num = 5;
exports.num = 5;

定义b模块引入a模块

let a = require("./a");
let b = require('./a');
let c  = require('./a');
console.log(a);
console.log(b);
console.log(c);

运行b.js,结果如下:

 如果我们使用moudle.exports导出数据,结果则会发生改变:

console.log("a.js");
let num = 5;
exports.num = 5;
module.exports = {};
//使用moudule.exports导出一个空对象

则打印的结果如下:

可以按照下面图所示的理解,实际上导出的数据是module.exports,erports实际上是module.exports对象的引用.当改变module.exports的指向时,exports就失效了.但是可以给exports添加属性和方法.

3.4 模块对象module

'2': Module {
    id: '.',
    path: 'C:\\Users\\wuhon\\Desktop\\favorite\\框架\\nodeCode\\day01',
    exports: {},
    parent: null,
    filename: 'C:\\Users\\wuhon\\Desktop\\favorite\\框架\\nodeCode\\day01\\b.js',
    loaded: false,
    children: [ [Module] ],
    paths: [
      'C:\\Users\\wuhon\\Desktop\\favorite\\框架\\nodeCode\\day01\\node_modules',
      'C:\\Users\\wuhon\\Desktop\\favorite\\框架\\nodeCode\\node_modules',
      'C:\\Users\\wuhon\\Desktop\\favorite\\框架\\node_modules',
      'C:\\Users\\wuhon\\Desktop\\favorite\\node_modules',
      'C:\\Users\\wuhon\\Desktop\\node_modules',
      'C:\\Users\\wuhon\\node_modules',
      'C:\\Users\\node_modules',
      'C:\\node_modules'
    ]
  },
  • module.id 模块的识别符,通常是带有绝对路径的模块文件名。
  • module.filename 模块的文件名,带有绝对路径。
  • module.loaded 返回一个布尔值,表示模块是否已经完成加载。
  • module.parent 返回一个对象,表示调用该模块的模块。
  • module.children 返回一个数组,表示该模块要用到的其他模块。
  • module.exports 表示模块对外输出的值。(重要)

module对象可以访问到当前模块的一些相关信息,但最多的用途是替换当前模块导出的对象

module.exports = {}

例如默认的导出对象是一个对象,我们可以改变,让导出对象为普通的函数或其他数据类型的值

module.exports = function(){
    console.log('hello world')
}

module.exports 真正的暴露对象,exports只是对module.exports的引用

4. NodeJS作用域

4.1 作用域

作用域:规定一个变量和函数可以使用的范围,作用域分为两种,全局作用域和局部作用域.

在node中,每一个js文件都是单独的作用域,因为node的模块化会将每一个文件中的代码封装在一个函数内部,这和和DOM浏览器开发不同.在浏览器中,var a,此时a会自动成为window的属性,此时js文件和js文件共享作用域,但是Node.js中,每个js文件是独立的作用域不共享,所以node中每一个文件中的变量都是私有的.

比如我们写了下面的代码:

let a = 10;

Node在执行代码之前,会将我们的代码编译为:

function (exports,require,module,__filename,__dirname){
    let a = 10;
}

4.2 暴露数据

如果其他的作用域要使用本作用域中的值,就需要我们将本作用域中的值暴露(导出).

暴露数据

module.exports = {num: 10}

使用exports暴露数据(定义a模块)

// a.js
var a = 100;
exports.a = a;
// exports是一个对象,给这个对象添加了一个属性a,a的值就是本作用域的变量值

定义b模块,在里面引入a.js

// b.js
var aa = require('./test.js');
// 此时text是引入的对象,就是exports对象,所以如果要获取a的值应该用
// aa.a
console.log(aa.a)

使用module.exports暴露数据:

在上面我们使用的是exports来暴露数据,但是你会发现很不方便,通过exports暴露数据的时候,暴露的数据会成为exports的属性,通过require()引用数据的时候,必须通过访问对象的属性才能访问到暴露的值,如果仅仅只能暴露一个东西,我希望向外暴露一个类,此时就很不方便.

如果js里仅仅只暴露一个东西,我们可以使用module.exports来暴露

这样module.export暴露的是什么,那么require()导入返回的就是什么

module.exports暴露一个东西,exports暴露多个东西

// 暴露类 Person.js
function Person(name,age,sex){
  this.name = name;
  this.age = age;
  this.sex = sex;
}
module.exports = Person;

导入

let Person = require(./Person.js);
// 如果采用抵module.exports暴露的,这里Person就是暴露的那个类,所以饿哦们可以直接使用
var xiaoming = new Person('小明',12,'男')

4.3 定义全局变量

let username = 'lhrlp'
global.name = username

使用时可以不写global

console.log(name)

5.模块的共性

所有的模块化都有一个共性,模块的功能都是把代码放到一个独立的函数中

  1. 模块中使用的var 定义变量都是局部变量

  2. 模块中定义的函数也是局部的

  3. 模块有一个模块对象,包含moduleName(模块名),exports(导出对象)

  4. 如果模块中需要 暴露方法或者属性给外部使用,那么就是像exports对象上添加

  5. 导入一个模块使用require('moduleName'),改方法返回的是模块对象的exports对象

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值