ESModule&Webpack&npm_01


框架前置课

1-node.js基础,node最重要是服务器开发,具体后面学,现在只学基础

2-npm/yarn/cnpm/npx/pnpm

3-模块化的使用

4-webpack,vue和reactCLI都会用到

5-GIT包管理工具

6-express

7-mysql基础知识

Node.js是什么

909

910

911

1-node是一个基于V8引擎(处理js的)的JavaScript运行时环境

2-node.js与浏览器相比,都是基于V8引擎执行处理js,但是各自还有自己的其他应用,比如chorm浏览器肯定还有书签,收藏夹什么的,node.js也有中间层libuv去处理文件读写,网络io,事件循环等。

3-其中libuv(异步事件库)是由c语言编写的,所以node.js的一部分也是由c语言编写。

Node的应用场景

912

1-包的管理,以前我们引入一个框架库,vue或者react或者lodash等,都是需要去官网下载到本地,然后用script标签引入,但是有了包管理工具如npm,我们就可以直接安装,如npm install day.js

哪个页面需要使用,就import day.js from“”day.js”即可

tip:我们可以自己打包好node包上传到npm上,然后就可以通过npm在线下载了

2-用node.js开发服务器,中间件,代理服务器的开发。

3- 借助node.js完成前后端渲染的同构应用,如ssr服务器渲染。

4-用node运行为项目编写的JavaScript的脚本,而不是python和shell

5-使用electron开发桌面应用程序,也需要node环境才能运行。

Node的安装和管理

1-我们安装的时候最好用LTS,long time support版本,比较稳定。如果是个人学习可以选current最新版本。

2-我们也可以下载多个版本,通过工具管理,实现不同node版本间的切换。

914

tip:我们下载后,后缀是msi全称就算Microsoft Install

913

这里有一个add to path 千万不要取消了,这个就是自动为我们node添加环境变量,也就是在cmd命令行中可以直接使用,如果取消了就需要自己像添加java环境那些一样去设置里面七七八八的手动添加环境变量,麻烦的要死,一个字母错了都不行。

最后在cmd命令行里面输入 node -v 和npm -v如果出来了版本号,就代表安装完毕了。

916

如果我们这里勾选了,就会出现如下页面

915

这个页面,它是在为我们安装使用一些包可能需要用到的环境,比如需要c++编译,但是事实上这个时候我们node和npm已经安装好了,这里可以直接关闭,以后需要这些环境的时候再安装,也可以等待它全部下载安装完毕(不魔法上网大概率会安装失败)

node的版本管理工具

实现node版本的切换,可以在电脑上安装多个版本node,比如工作就用LTS版本,在家学习用Current版本。

917

其中n和nvm都是只支持mac,所以github有人发布了nvm-windows

https://github.com/coreybutler/nvm-windows

nvm install latest 是安装当前时间最新的node版本
nvm list是显示出当前电脑,安装了的node版本
nvm use xx.xx.xx 就是切换版本xx是版本号,注意这里需要给cmd管理员权限运行

注意!!!

必须在nvm的配置文件也就是setting.txt中加入下面两行修改镜像源,不然你下一辈子都下不完,科学上网也不行。

tip:当你下载一些东西没反应,第一时间考虑要不要科学上网,如果还不行就换镜像源。

镜像源就是那些大厂什么的帮我们复制了国外的资源,然后我们在国内访问这个镜像源下载就行了。

node_mirror: https://npm.taobao.org/mirrors/node/
npm_mirror: https://npm.taobao.org/mirrors/npm/

JavaScript代码在node中的 执行

命令行运行

1-以前我们的js文件,必须建一个html文件,然后用script引入,现在我们只需要把js写好,然后在命令行cd到当前demo.js文件的目录,然后node demo.js即可

2-移动盘符的命令,什么cd.. tab补全 dir cls 百度学一下就行

3-也可以在vscode的终端打开cmd和powershell都可以(vscode是用electron写的)

Node的输入和输出

919

输出

很简单直接console.log()打印输出

console.clear()清空控制台

console.trace()输出函数的调用栈,也就是执行路径

输入

输入的话,原先用浏览器执行js,可以用prompt(),现在用node在终端执行怎么办呢?

在执行文件的命令后空格隔开,输入变量赋值即可。

//文件名字为demo.js
// 1.输出的内容
console.log("Hello World")

const num1 = 100
const num2 = 200

console.log(num1 + num2)


// 2.给程序输入内容
// node ./webpack.config.js env=development
const arg1 = process.argv[2]
const arg2 = process.argv[3]
console.log(process.argv)
console.log(arg1, arg2)

setTimeout(() => {
  // console.clear()
  console.trace()
}, 3000);

命令

node demo.js num1=20 num2=30

在node中js是有一个process.argv的数组,里面保存了一些数据

918

为什么叫argv?

,循环

node的repl

read-eval-print-loop读取,求值,输出,循环

921

我们在控制台输入node就可以进入,输入.exit或者按两次ctrl+c就可以退出

它和我们在浏览器的console控制台差不多,可以写简单的js代码运行,实际中作用不大

922

Node的全局对象

1-众所周知在浏览器中有全局对象window,但是在node中是没有window的,但是有global

2-一个是浏览器视口可以看到的所有东西,node根本没有视口何来window

3-在浏览器执行js中我们定义一个var变量会被添加成为window的属性,但是在node中不会被添加为global的属性

3-为了避免把浏览器和node的全局对象记混,统一了一个名字globalThis,在浏览器中指window,在node中指global,我个人认为多此一举。

923

process进程全局对象

console.log(process)这个对象东西非常多比如原先说的argv[],可以自己去nodejs.org或者api.nodejs.cn去查询文档

tips:org后缀域名代表非盈利性或政府组织。

定时器也是全局对象

924

interval间隔,immediate立即立刻的也就是说它会立即执行这个回调函数。

process.nextTick()和setImmediate()谁先执行?在事件循环中会讲清楚。

特殊的全局对象

1-它实际上是模块中的变量,每个模块都有,像全局变量

2-在命令行交互中不可以使用。

假设当前文件在 e:\学习\demo.js
__dirname可以拿到当前代码所在的目录结构   //e:\学习\
__filename当前代码文件目录结构  		  //e:\学习\demo.js
 module模块,exports出口传播,require需求,也是特殊的全局对象,后面会学
// 特殊的全局对象
// __dirname当前的文件所在的目录结构(重要) 注意这是两个下划线
console.log(__dirname)
// __filename当前目录+文件名称
console.log(__filename)

前端模块化

什么是模块化开发

925

1-比如一个项目,不同的人为一个页面书写js,如果不使用模块化开发,那么”东方“写了a.js并定义了一些变量,”亚洲“就无法在b.js中再定义那些变量的名字。如果是一些常用的变量名如name,age,两个人就要去看另一个人的代码,避免变量冲突,这样就太麻烦了。

2-怎么办?我们可以用立即执行函数,因为有函数作用域的限制,所以不会冲突,但问题又来了,当我们需要用到另一个js文件的变量怎么办?因为作用域的限制,想要的时候又拿不到了

3-我们可以在立即执行函数里面书写函数返回值,把立即函数内的所有变量通过对象返回,那么别人在需要使用的时候就可以通过返回值引入了。

const moduleA = (function() {
  let name = "why"
  let age = 18
  let height = 1.88
  console.log(name)

  return {
    name,
    age,
    height
  }
}())

4-其实这样就避免了作用域的冲突,也可以导入导出不同文件的变量和函数等,但是每个人有每个人的习惯,你写的a.js返回的是对象,也许其他人不知道这个方法就不会调用a.js中的所需变量。必须有一个统一的书写方法。

5-所以社区就诞生了很多模块化的规范,其中有CommonJS和AMD和CMD,官方后来推出了ESMoudle使用的最多。

926

没有模块化的问题

927

CommonJS(社区模块化方案)和Node

社区指定的约定规范,还有很多人使用。在webpack中也有它的影子

928

929


utile.js

const UTIL_NAME = "util_name"

function formatCount() {
  return "200万"
}

function formatDate() {
  return "2022-10-10"
}
//exports是一个对象,如果你没有导入任何东西就是空的
console.log(exports) // {}
//导出
//这个变量随便命名的,命名为一样使用方便点
exports.UTIL_NAME = UTIL_NAME
exports.formatCount = formatCount
exports.formatDate = formatDate

导入

// 1.直接获取导出的对象, 从对象中获取属性
//这个util是一个对象,你随便命名的,这是命名为文件名字有利于区分
// const util = require("./util.js")

// console.log(util.UTIL_NAME)
// console.log(util.formatCount())
// console.log(util.formatDate())

// 2.导入对象之后, 直接对其进行解构
// const { 
//   UTIL_NAME,
//   formatCount, 
//   formatDate 
// } = require("./util.js")

// console.log(UTIL_NAME)
// console.log(formatCount())
// console.log(formatDate())


// 3.探讨require的本质
const bar = require("./bar.js")
console.log(bar.name) // bar
console.log(bar.nb) // bar
console.log(bar) // bar

// 4s之后重新获取name
// setTimeout(() => {
//   console.log(bar.name)
// }, 4000)

// 2s之后通过bar修改了name
setTimeout(() => {
  bar.name = "kobe"
}, 2000)

tip:const bar = require(“./bar.js”)是把bar.js里面的exports对象的地址给了bar

所以说在使用中修改一些exports里面的属性变量值,两边都会被改

module.exports导出

const name = "foo"
const age = 18
function sayHello() {
  console.log("sayHello")
}

// 1.在开发中使用的很少
// exports.name = name
// exports.age = age
// exports.sayHello = sayHello

// 2.将模块中内容导出
// 结论: Node导出的本质是在导出module.exports对象
 module.exports.name = name
 module.exports.age = age
module.exports.sayHello = sayHello

如上代码是module.exports导出方法,你这不是犯病吗?效果一样的,偏要多加个单词module

上面代码中module.exports.age和exports.age其实是一个东西

exports===module.exports

const name = "foo"
const age = 18
function sayHello() {
  console.log("sayHello")
}

// 1.在开发中使用的很少
// exports.name = name
// exports.age = age
// exports.sayHello = sayHello

// 2.将模块中内容导出
// 结论: Node导出的本质是在导出module.exports对象
// module.exports.name = name
// module.exports.age = age
// module.exports.sayHello = sayHello

// // console.log(exports.name, "----")
// // console.log(exports.age, "----")
// // console.log(exports.sayHello, "----")
// console.log(exports === module.exports)

// 3.开发中常见的写法
module.exports = {
  name,
  age,
  sayHello
}

// exports.name = "哈哈哈哈"
// module.exports.name = "哈哈哈哈"

导入者按理来说是不应该能修改导出者也就是原始版本中的变量的,在ESmodule中就不支持。

所以开发中commonJS一般是给module.exports一个对象值,那么就开辟了一个新地址新内存,另一个js文件通过require方法取到exports对象中的属性变量后,即使修改也不会影响被导出变量的js中的变量值。

问题:exports===module.exports,那我还是没有理由写module呀,开辟新对象,我给exports对象赋值不是一样的?

测试中我发现,你直接给export赋值一个类,开辟新空间,另一个js文件中引不到东西。

require方法的解析

930

如上图,在index.js导出了一个变量对象,在mian.js中引入的时候,并没有写导入的变量来自具体哪一个文件如utils/index.js,而只写了utils还是可以使用,这是为什么?这就需要知道require的查找机制

require的查找寻找机制

931

path和http是内置的模块

932

933

在实际开发中,比如我们require一个axios

1-axios不是核心库

2-搜索node_modules文件夹(这个文件夹npm install axios等会自动生成),当前路径找不到,就自动搜寻再上一级目录,如果都没有返回not found。

require引入模块的运行过程

foo.js

console.log("foo-----")
console.log("foo+++++")

934

1-当模块被引入,模块代码会被自动执行一次,按照当前main.js代码顺序执行,遇到模块引入就跳到被引入模块的js文件中执行,然后继续后面代码

2-模块引入执行一次后,再重复引入,不会再执行模块中的代码。

935

也就是说main引入了aaa和bbb,aaa引入了ccc,ccc引入了ddd,ddd引入了eee

main会先引入完了bbb这条线,再去引入bbb,bbb虽然引入了ccc,但是ccc已经被引入一次了,就不会再被执行。

936

commonjs的引入是同步的,没有异步。

1-一般commonjs是在服务器中,引入的文件也都在服务器存储了,如上引入aaa,bbb,ccc等等

因为代码在本地都有,所以速度是很快的,即使aaa中调用了查询数据库等需要耗时,但是查询数据库本身是异步的,所以会继续执行下去,总而言之引入的速度会很快。

2-如果把它应用到浏览器中,因为commonjs是同步的,aaa,bbb等文件都需要从服务器去下载下来,一个没下载好,下面的其他引入都无法执行。

AMD和CMD(了解)

937

现在开发已经不用了

938

939

940


文章作者: 瑾年
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 周东奇 !
免责声明: 本站所发布的一切内容,包括但不限于IT技术资源,网络攻防教程及相应程序等文章仅限用于学习和研究目的:不得将上述内容用于商业或者非法用途,否则一切后果请用户自负。本站部分信息与工具来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。如有侵权请邮件(jinnian770@gmail.com)与我们联系处理。
  目录