错误解决方案和模块化 CommonJS、AMD、CMD

2022-05-21  本文已影响0人  咸鱼不咸_123

一、错误处理方案

1.throw后面跟的类型

1.1 Error类型

Error类包含三个属性:

Error有自己的子类:

2. 异常的处理

我们会发现在之前的代码中,一个函数抛出了异常,调用它的时候程序会终止执行。

例如下面的异常:

function foo(){
  throw new Error("foo函数发生了异常")
}

function bar(){
  foo()
}

function demo(){
  bar()
}

demo()

3. try...catch

如果代码可能会存在问题,可以使用try...catch进行捕获异常。

function foo(){
  throw new Error("foo函数发生了异常")
}

function bar(){
  try{
    foo()
  }catch(err){
    console.log("err:",err);
  }finally{
    console.log("finally代码执行");
  }
}

function demo(){
  bar()
}

demo()

catch后面参数可省略:

function foo(){
  throw new Error("foo函数发生了异常")
}

function bar(){
  try{
    foo()
  }catch{
    // console.log("err:",err);
    console.log("发生异常了");
  }finally{
    console.log("finally代码执行");
  }
}

function demo(){
  bar()
}

demo()

二、模块化

1.什么是模块化

到底什么是模块化、模块化开发?

上面提到的结构,就是模块。按照这种结构划分开发程序的过程。就是模块化开发的过程。

1.1 模块化的历史

早期时,js仅仅只是作为一种脚本语言,做一些简单的验证、动画,代码也比较少。

但是随着前端和js的快速发展,js的代码变的越来越复杂了。

所以,模块化已经是js一个非常迫切的需求:

2.没有模块化的问题

早期没有模块化的时候,会造成命名冲突,多个Js文件没有自己的作用域。

所以我们使用了立即执行函数,将需要向外共享的变量、函数、对象以一个对象的形式返回。

但是,我们其实带来了新的问题:

所以,我们会发现,虽然实现了模块化,但是我们的实现过于简单,并且是没有规范的。

3.CommonJS规范和Node关系

CommonJS是一个规范(只是一个规范),最初提出来是在浏览器以外的地方使用,并且当时被命名为ServerJS,后来为了体现它的广泛性,修改为CommonJS,平时我们也会成为CJS

webpack是模块化打包工具

webpack打包的代码最终是要在Node环境下运行的。

所以,Node中对CommonJS进行了支持和实现,让我们在开发Node的过程中可以方便的进行模块化开发。

前面我们提到过模块化的核心是导出和导入,Node中对其进行了实现:

4.CommonJS的使用

4.1 CommonJS的基本使用

wjy.js

const name="wjy";
const age=18

function sum(num1,num2){
  return num1+num2;
}


// * 导出的方式有两个:一个是exports,一个是module.exports
// * module是这个模块本身的对象
// * 返回将东西放在属性exports中,这些东西都会被导出。
module.exports={
  name,
  age,
  sum
}

// console.log("module:",module);

main.js

// * 使用wjy模块,所以需要导入,导入的时候,会将另外模块的代码执行
/**
 * * 如果不加后缀
 * * 1.会先在末尾加.js后缀
 * * 2.如果还是没找到,会在后面加.json后缀
 * * 3.如果还是没找到,会在后面加node
 * * 4.最后还是没找到,则会报错
 */
// const wjy=require("./wjy")

// console.log(wjy.name);
// console.log(wjy.age);
// console.log(wjy.sum);


// * 也可以使用解构赋值
const {name,age}=require("./wjy")
console.log(name);
console.log(age);

4.2 内部原理

wjy.js

module.exports={
  name:"wjy",
  age:18,
  foo:function(){
    console.log("foo函数");
  }
}

setTimeout(()=>{
 module.exports.name="kobe"
},1000)

main.js

const wjy=require("./wjy");//* 导入的是wjy模块的module.exports对象。
console.log(wjy);

//* 内部的原理:根据id找到这个文件,然后将这个模块的module.exports返回,这个它们指向的是同一片内存空间的地址。
// function require(id){
//   return module.exports;
// }
setTimeout(()=>{
  console.log("name:",wjy.name);
},2000)

4.3 exports

在node的源码中

module.exports={}
exports=module.exports;

起初module.exports和exports指向的是同一片内存空间。

const name="wjy";
const age=18;
function sum(num1,num2){
  return num1+num2
}

// * 第一种导出module.exports

// * 第二种导出
exports.name=name
exports.age=age
exports.sum=sum;


// * 源码
// module.exports={}
// exports=module.exports;

所以上面的exports.name=name,都是这片内存空间添加一个东西。

exports={
  name,
  age,
  sum
}

如果直接让exports={...},这就让module.exports和exports指向的不是同一片内存空间,所以这样的导出是无效的。

因为require取出的module.exports这个对象所指向的内存空间。

最终能导出的只有module.exports

// * 第三种情况 module.exports指向了新的内存地址
exports.name=name;
exports.age=age;
exports.sum=sum

module.exports={}

4.5 require细节

我们现在已经知道,require是一个函数,可以帮助我们引入一个文件(模块)导出的对象

require函数传入的是一个字符串,导入格式为 require(X)

  1. 情况一:如果X是一个Node核心模块时,比如path、http

    • 直接返回核心模块,并且停止查找。
  2. 情况二:X是以./或../开头或/开头的【是一个路径开头,不是一个简单的名称了。】

    • 第一步:将X当做一个文件在对应的目录下查找

      • 如果有后缀名,按照后缀名的格式查找对应的文件
      • 如果没有后缀名,会按照如下顺序:
        • 直接查找文件X
        • 查找X.js文件
        • 查找X.json文件
        • 查找X.node文件
    • 第二步:如果没有找到对应的文件,则将X当做目录

      • 查找目录下面的index文件
        • 查找X/index.js文件
        • 查找X/index.json文件
        • 查找X/index.node文件
  3. 情况三:X既不是 路径 ,也不是核心模块

    • 会沿着当前module.paths数组中依次取出对应的路径,并且会每次在对应的路径中查找node_modules文件夹是否有X文件夹。如果取出数组中的最后一个路径,还是没有找到,会报错。
// * node的核心模块
const path=require("path")
const fs=require("fs")
console.log(path);

如果X既不是路径,也不是核心模块,会去当前目录下的node_modules文件夹查找X文件夹,如果还是没找到,会上一层目录的node_modules文件夹查找。

image-20220520195654010.png

4.6 模块的加载过程

image-20220520222826859.png

4.7 CommonJS规范缺点

6.AMD

6.1 require.js的使用

  <script src="./lib/require.js" data-main="./src/main.js"></script>

main.js

//* paths实现了模块化的注册

require.config({
  baseUrl:"./src",
  paths:{
    foo:"./foo",//这个路径是相当于 index.html的位置来看待的
    bar:"./bar"
  }
})

// * 加载具体的模块
require(["foo","bar"],function(foo){
  console.log("main:",foo);
})

foo.js

define(function(){
  const name="wjy";
  const age=18;
  function sum(num1,num2){
    return num1+num1;
  }
  return {
    name,
    age,
    sum
  }
})

bar.js

// define(function(){
//   console.log("目前到达bar模块---------");
//   // * 如果想使用foo模块
//   require(["foo"],function(foo){
//     console.log("bar:",foo);
//   })
// })

// * 如果想使用foo模块
define(["foo"],function(foo){
  console.log("bar:",foo);
})

7.CMD

CMD规范也是应用于浏览器的一种模块化规范:

CMD也有自己比较优秀的实现方案:

index.html

 <script src="./lib/sea.js"></script>
  <script>
    seajs.use("./src/main.js")
  </script>

main.js

define(function(require,exports,module){
  const foo=require("./foo")
  console.log("main:",foo);
})

foo.js

define(function(require,exports,module){
  const name="wjy"
  const age=18;
  function sum(num1,num2){
    return num1+num2;
  }
  // * 导出方式一:
  // exports.name=name;
  // exports.age=age;
  // exports.sum=sum;
  // * 导出方式二
  module.exports={
    name,
    age,
    sum
  }
})

8.认识ES Module

js没有模块化一直是它的痛点,所以才会产生我们前面学习的社区规范:CommonJS、AMD、CMD等。所以在ES推出自己的模块化系统时,大家也是兴奋异常。

ES Module和CommonJS的模块化有一些不同之处:

ES Module模块采用 import和export关键字来实现模块化

了解:采用ES Module 将自动采用 严格模式 :use strict

ES Module最终还是应用在浏览器中。

8.1 基本使用

index.html

 <!-- *
    *  默认情况会将js文件当做一个普通的文件加载进来,然后从上往下执行,默认是不支持import、export
    * 所以应该要指定加载这个文件是一个模块,所以需要设置 type=module
    * file协议是不允许去加载模块的,所以会报错的。需要使用http协议来加载对应的模块
     -->
  <!-- 
       * 其实在电脑上是可以直接打开一个index.html文件的:这个相当于浏览器对本地文件来解析的。
       * live-server:会开启一个本地服务器,有自己的ip地址、端口号
      -->
  <script src="./main.js" type="module"></script>

main.js

import  {name,age} from "./foo.js";//* 这里必须要加后缀名全称,因为没有webpack的环境
console.log(name);
console.log(age);

foo.js

export const name="wjy"
export const age=18;

8.2 export关键字

8.2.1 export 声明语句
export const name="wjy"
export const age=18;

export function sum(num1,num2){
  return num1+num2;
}
export class Person{

}
8.2.2 export导出和声明分开
// * 第二种:export导出和声明分开
const name="wjy"
const age=18;
function foo(){
  console.log("foo函数");
}

// * {}是一个固定语法,不要去写什么键值对形式,否则会报错的。
export {
  name,
  age,
  foo
}

8.2.3 export导出和声明分开,导出时取别名

使用as 关键字取别名

const name="wjy"
const age=18;
function foo(){
  console.log("foo函数");
}
export {
  name as fName,
  age as fAge,
  foo as fFoo
}

8.3 import关键字

8.3.1 普通的导入
// * 导入方式一:普通的导入
import  {fName,fAge} from "./foo.js";//* 这里必须要加后缀名全称,因为没有webpack的环境
8.3.2 导入时起别名
// * 导入方式二:起别名
import {name as fName, age as fAge,foo as fFoo} from "./foo.js"
8.3.3 将导出的所有内容放到一个标识符中
// * 导入方式三:将导出的所有内容放到一个标识符中
import * as foo "./foo.js"
console.log(foo.name);
console.log(foo.age);
console.log(foo.foo());

8.4 综合使用

index.js

// * 导出方式一:
// import {add,sub} from "./math.js"
// import {timeFormat,priceFormat} from "./format.js"

// export {
//   add,
//   sub,
//   timeFormat,
//   priceFormat
// }

// * 导出方式二
// export {add,sub} from "./math.js"
// export {timeFormat,priceFormat} from "./format.js"

// * 导出方式三
export * from "./math.js"
export * from "./format.js"

8.5 default

foo.js

 const name="wjy"
 const age=18;

 const foo="foo value"

export  {
  name,
  age,
  // * 默认导出方式一
  // foo as default 
}

// * 默认导出方式二
export default foo



main.js

import wjy from "./foo.js";//这个拿到的是 foo.js的默认导出

console.log(wjy);

8.6 import 函数

前面我们使用的普通的导入方式,是同步的,必须要等到对应的模块加载完,才能执行当前模块的其他代码,所以会造成后续代码的阻塞、

如果不想模块的导入阻塞后续的代码,可以使用require函数,它的返回值是一个Promise对象

// import {name,age,foo} from "./foo.js";//* 默认这种导入模块,要等到对应模块加载完,才会执行模块内的代码,如果模块还未加载完,后续的代码会被阻塞的。

// * 如果不想导入其他模块时,而阻塞当前模块的内容,可以使用import函数
// * 可以使用import函数,返回的是一个Promise对象

import ("./foo.js").then(res=>{
  console.log("res:",res);
})
console.log("后续的代码都是不会运行的");

8.7 ESModule的解析流程

image-20220521143102943.png
8.7.1 构建阶段(Construction)
image-20220521144418698.png image-20220521144748680.png
8.7.2 阶段二和阶段三:实例化阶段——求值阶段
image-20220521145159094.png

9ES Module和CommonJS的关系

如果在一个模块中使用module.exprots方式【CommonJS】导出,能否在另外一个模块使用import【ES Module】方式导入呢?

如果在一个模块中使用export方式导出 【ES Module】导出,能否在另外一模块使用 requrie【CommonJS】方式导入呢?

使用webpack 必须使用webpack-cli
错误解决方案和模块化.png
上一篇下一篇

猜你喜欢

热点阅读