zoukankan      html  css  js  c++  java
  • Node.js学习笔记----day03

    认真学习,认真记录,每天都要有进步呀!!!
    加油叭!!!


    一、Node中的模块系统

    使用Node编写应用程序主要就是在使用

    1. EcmaScript
    • 和浏览器不一样的是,在Node中没有BOM、DOM
    1. 核心模块
    • 文件操作的fs
    • http服务的http
    • url路径操作模块
    • os操作系统信息
    1. 第三方模块
    • art-template
    • 必须通过npm来下载才可以使用
    1. 自己创建的模块
    • 自己创建的文件

    二、什么是模块化

    1. 具有文件作用域(没有污染)
    2. 具有通信规则(即可以加载又可以导出)

    三、CommonJS模块化

    在Node中的JavaScript还有一个很重要的概念:模块系统

    1. 模块作用域
      与浏览器相比不是全局作用域,模块作用域,默认全局当中的所有成员不能被外部访问
    2. 使用 require() 方法来加载模块
      没有 script 标签,不能通过 script 标签来加载文件
    3. 使用 exports 接口对象来导出模块中的成员

    四、加载与导出

    1. 加载require()
      语法:
    var 自定义变量名称 = require('模块')
    

    require 方法有两个作用:
    (1) 加载文件模块并执行里面的代码
    (2)得到被加载文件模块导出的接口对象

    1. 导出exports()

    Node中是模块作用域,默认文件中所有的成员只在当前文件模块有效
    对于希望可以被其他模块访问的成员,我们就需要把这些公开的成员都挂载到exports接口中就可以了

    在每个文件模块中都提供了一个对象:exports
    exports 默认是一个空对象
    你要做的就是把所有需要被外部访问的成员挂载到这个 exports 对象中

    2.1 导出多个成员

    exports.age = 123
    exports.hi= 'hello'
    exports.func = function(){
    console.log('aaa')
    }
    exports.message={
    name:'zs'
    }
    

    也可以这样来导出多个成员

    module.exports = {
    add = function(){
    return x + y
    },
    str:'hello'
    }
    

    2.2 导出单个成员,拿到的就是函数,字符串

    module.exports = 'hello'
    

    以下情况会覆盖

    module.exports = 'hello'
    
    //以这个为准,后者会覆盖前者
    module.exports = function(x,y){
    return x + y
    }
    

    五、exports与module.exports的原理解析

    在 Node 中,每个模块内部都有一个自己的 module 对象
    该 module 对象中,有一个成员叫:exports

     var module = {
       exports: {
       对象名:'对象内容',
       方法名:function
       }
     }
      //模块中还有一句
     var exports = module exports
     //默认在代码最后一句
     //谁来require我,谁就得到module exports
     return module exports
    

    也就是说如果你需要对外导出成员,只需要把导出的成员挂载到 module.exports

    main.js

    var fooExports = require('./foo')
    console.log(fooExports)
    

    foo.js

     module.exports.test1 = 'hello'
     module.exports.test2 = 'world'
     module.exports.add = function (x, y) {
       return x + y
     }
     module.exports.reduce = function (x, y) {
       return x - y
     }
    

    foo.js相当于

     var module = {
      exports: {
       test1: 'hello',
       test2: 'world',
      add: function,
      reduce:function,
      }
    }
    

    执行main.js结果:
    在这里插入图片描述
    再添加一些exports对象与方法
    foo.js

     module.exports.test1 = 'hello'
     module.exports.test2 = 'world'
    
      exports.test3 = 'hi'
      exports.test4 = 'node.js'
    
     module.exports.add = function (x, y) {
       return x + y
     }
     module.exports.reduce = function (x, y) {
       return x - y
     }
     
     exports.a = function(a,b){
     	return a + b
     }
     exports.b = function(a,b){
     	return a + b
     }
    

    结果:

    在这里插入图片描述

    我们发现,exports == module.exports,两者一致,说明可以使用任意一方来导出接口成员
    每次导出接口成员的时候都通过 module.exports.xxx = xxx 的方式很麻烦,点儿的太多了
    所以,Node 为了简化操作,专门提供了一个变量:exports 等于 module.exports

    exports相当于 module.exports的一个引用

    console.log(exports == module.exports)  // true
    exports.foo = 'bar'
    //等价于
    module.exports.foo = 'bar'
    
    

    也就是说在模块中还有这么一句代码
    var exports = module.exports

    当一个模块需要导出单个成员的时候
    直接给 exports 赋值是不管用的

    栗子:

    
    exports = 'hello'
    

    是个空对象,什么都没有
    在这里插入图片描述

    一定要记住,最后 return 的是 module.exports
    不是 exports
    所以你给 exports 重新赋值不管用,
    return module.exports

    对比去理解的栗子:

    在这里插入图片描述

    没有给exports 重新赋值之前

    栗子:

     exports.a = 123
     // exports = {}
     exports.foo = 'bar'
    

    在这里插入图片描述
    给exports 重新赋值后

    栗子:

     exports.a = 123
     exports = {}
     exports.foo = 'bar'
    

    给 exports 赋值会断开和 module.exports 之间的引用,重新赋值以后,跟原来没有关系,后面添加都不管用

    在这里插入图片描述
    exports的修改不影响module.export

    栗子:

    exports.a = 123
    exports = {}
    exports.foo = 'bar'
    module.exports.b = 456
    //module.export一直都没有变,所有可以导出 b:456
    //exports的修改不影响module.export
    

    在这里插入图片描述
    module.exports 重新赋值会断开与exports的引用

    栗子:

    module.exports = 'hello'
    exports.a = '123'
    

    在这里插入图片描述

    总结:
    给 exports 赋值会断开和 module.exports 之间的引用
    同理,给 module.exports 重新赋值也会断开

    栗子:

    // 这里导致 exports !== module.exports
     module.exports = {
      foo: 'bar'
     }
    // // 但是这里又重新建立两者的引用关系
     exports = module.exports
     exports.foo = 'hello'
    

    结果:
    在这里插入图片描述
    栗子:

     //{foo: bar}
    exports.foo = 'bar'
    
     // {foo: bar, a: 123}
    module.exports.a = 123
    
    // exports !== module.exports
    // 最终 return 的是 module.exports
    // 所以无论你 exports 中的成员是什么都没用
     exports = {
       a: 456
     }
    
    // {foo: 'haha', a: 123}
     module.exports.foo = 'haha'
    
     // 没关系,混淆你的
     exports.c = 456
    
     // 重新建立了和 module.exports 之间的引用关系了
     exports = module.exports
    
     // 由于在上面建立了引用关系,所以这里是生效的
     // {foo: 'haha', a: 789}
     exports.a = 789
    

    最终结果:
    在这里插入图片描述
    再加上一句:

    // // 前面再牛逼,在这里都全部推翻了,重新赋值
    // // 最终得到的是 Function
     module.exports = function () {
      console.log('hello')
     }
    

    结果:

    在这里插入图片描述

    归纳总结:
    真正去使用的时候:
    导出多个成员:exports.xxx = xxx
    导出多个成员也可以:module.exports = { }
    导出单个成员:module.exports

    六、总结exports与module.exports的区别

    • 每个模块中都有一个 module 对象
    • module 对象中有一个 exports 对象
    • 我们可以把需要导出的成员都挂载到 module.exports 接口对象中
    • 也就是:moudle.exports.xxx = xxx 的方式
    • 但是每次都 moudle.exports.xxx = xxx 很麻烦,点儿的太多了
    • 所以 Node 为了你方便,同时在每一个模块中都提供了一个成员叫:exports
    • exports === module.exports 结果为 trues
    • 所以对于:moudle.exports.xxx = xxx 的方式 完全可以:expots.xxx = xxx
    • 当一个模块需要导出单个成员的时候,这个时候必须使用:module.exports = xxx 的方式
    • 不要使用 exports = xxx 不管用
    • 因为每个模块最终向外 return 的是 module.exports
    • exports 只是 module.exports 的一个引用
    • 所以即便你为 exports = xx 重新赋值,也不会影响 module.exports
    • 但是有一种赋值方式比较特殊:exports = module.exports 这个用来重新建立引用关系的

    七、require方法加载规则

    1. 优先从缓存加载

    在这里插入图片描述
    结果:
    在这里插入图片描述

    1. 判断模块标识
    • 核心模块

    核心模块的本质也是文件
    核心模块文件已经被编译到了二进制文件中了,我们只需要按照名字来加载就可以了
    eg:
    require('fs')
    require('http')

    • 路径形式的文件模块(自定义模块)

    路径形式的模块:
    ./ 当前目录,不可省略
    ../ 上一级目录,不可省略
    /xxx 几乎不用
    d:/a/foo.js 几乎不用
    首位的 / 在这里表示的是当前文件模块所属磁盘根路径
    .js 后缀名可以省略
    require('./foo') 相当于 require('./foo.js')

    • 第三方模块

    凡是第三方模块都必须通过 npm 来下载
    使用的时候就可以通过 require('包名') 的方式来进行加载才可以使用
    不可能有任何一个第三方包和核心模块的名字是一样的
    第三方模块既不是核心模块、也不是路径形式的模块
    先找到当前文件所处目录中的node_modules目录
    node_modules/art-template
    node_modules/art-template/package.json文件
    node_modules/art-template/package.json 文件中的 main 属性
    main 属性中就记录了 art-template 的入口模块
    然后加载使用这个第三方包
    实际上最终加载的还是文件

    如果 package.json 文件不存在或者 main 指定的入口模块是也没有
    node 会自动找该目录下的 index.js
    也就是说 index.js 会作为一个默认备选项

    如果以上所有任何一个条件都不成立,则会进入上一级目录中的 node_modules 目录查找
    如果上一级还没有,则继续往上上一级查找
    。。。
    如果直到当前磁盘根目录还找不到,最后报错:
    can not find module xxx
    var template = require('art-template')

    注意:我们一个项目有且只有一个 node_modules,放在项目根目录中,这样的话项目中所有的子目录中的代码都可以加载到第三方包
    不会出现有多个 node_modules

    总结模块查找机制

    1. 优先从缓存加载
    2. 核心模块
    3. 路径形式的文件模块
    4. 第三方模块
      node_modules/art-template/
      node_modules/art-template/package.json
      node_modules/art-template/package.json main
      index.js 备选项
      进入上一级目录找 node_modules
      按照这个规则依次往上找,直到磁盘根目录还找不到,最后报错:Can not find moudle xxx
      一个项目有且仅有一个 node_modules 而且是存放到项目的根目录

    参考详细文档: 深入Node.js的模块机制

    八、npm

    node package manager

    1. npm 网站 : https://www.npmjs.com/
      可以用来搜索第三方包
      在这里插入图片描述
    2. npm命令行工具
      npm的第二层含义就是命令行工具,只要你安装了node 就相当于安装了npm
      npm 也有版本的这个概念
      查看npm版本
    npm --version
    

    升级npm版本

    npm install --global npm
    
    1. npm 常用命令
      详细参考文档:https://www.cnblogs.com/PeunZhang/p/5553574.html
    2. 解决npm被墙的问题
      参考文档:https://blog.csdn.net/qq_45103612/article/details/108569090

    九、package.json

    建议每一个项目都要有一个package.json (包描述文件,就像产品说明书一样)
    这个文件可以通过npm init的方式初始化出来

    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述

    • 建议每个项目的根目录中都有一个package.json文件
    • 建议执行npm install 包名的时候都加上 --save这个选项,目的是用来保存依赖项信息
    • 可以在package.json文件中通过dependencies选项,查看第三方包的依赖信息
    • 如果项目中的node_modules项目丢失了,只要 package.json文件存在,我们只需要npm install,就会自动把package.json中的dependencies中的所有依赖项都下载回来

    十、package.json与package-lock.json

    npm5以前是不会有package.json这个文件的
    npm5以后才加入了这个文件
    当你安装包以后,npm都会自动安装package-lock.json这个文件

    • npm5以后的版本安装包不需要加上--save参数,它会自动保存依赖信息
    • 当你安装包的时候,会自动创建或更新package-lock.json这个文件
    • package-lock.json会保存node_modules中所有包的信息(版本,下载地址)
    • 这样的话重新npm install的速度就会提升很多
    • 从文件来看,有一个lock称之为锁
    • 这个lock是用来锁定版本的
    • 如果这个项目依赖了1.1.1版本
    • 如果你npm install其实会下载最新版,而不是1.1.1
    • 所以package-loca.json的另外一个作用就是锁定版本号,防止自动升级新版
  • 相关阅读:
    在eclipse中快速多行注释的方法
    Android开发:去掉Activity的头部标题栏及全屏显示
    C#的Process类的一些用法
    C#中隐式操作CMD命令行窗口 (转)
    我的INI 配置文件读写动态库
    Android高手进阶教程(五)之----Android 中LayoutInflater的使用!
    Android高手进阶教程(六)之----Android 中MenuInflater的使用(布局定义菜单)!
    Android Menu 之 optionsMenu 详解
    centos安装php扩展
    linux 权限
  • 原文地址:https://www.cnblogs.com/Chinatsu/p/13823137.html
Copyright © 2011-2022 走看看