目录
[ES6 介绍](#ES6 介绍)
[ES6 的变量和模板字符串](#ES6 的变量和模板字符串)
[ES6 的解构表达式](#ES6 的解构表达式)
[ES6 的箭头函数](#ES6 的箭头函数)
[rest 和 spread](#rest 和 spread)
[ES6 的对象创建和拷贝](#ES6 的对象创建和拷贝)
[ES6 的模块化处理](#ES6 的模块化处理)
前端工程化
什么是前端工程化
前端工程化 是使用软件工程的方法来单独解决前端 的开发流程中模块化,组件化,规范化,自动化的问题。
我们在前面的案例中,前后端都在同一个容器中实现。但为了实现模块化,组件化,规范化,自动化,前后端会使用到不同的工具,后端使用 maven,前端使用 nodejs,npm,vite...

但前后端的工具,又无法在同一个容器中部署,所以,前端工程化,就是将 app 中的前端相关的代码剥离出来,形成一个独立的工程,使用相关的专门的技术来实现前端代码模块化,组件化,规范化,自动化

前后端分离模式,要做到:1. 开发分离 2. 部署分离
前端工程化实现技术栈
前端工程化实现的技术栈很多,本文采用 ES6 + Nodejs + npm + Vite + VUE3 + Router + Axios + Element-plus 组合来实现
- ES6 VUE3 中大量使用 ES6 语法
- Nodejs 前端项目运行环境
- npm 依赖下载工具
- Vite 前端项目构建工具
- VUE3 渐进式前端框架
- Router 通过路由实现页面切换
- PInia 通过状态管理实现组件数据传递
- Axios ajax 异步请求封装技术实现前后端数据交互
- Element-plus 可用提供丰富的快速构建网页的组件仓库
ECMA6Script
ES6 介绍
ECMAScript6,是 JavaScript 语言的一次重大更新。带来了大量的新特性,大大提升了 JavaScript 的开发。
ES6 的变量和模板字符串
ES6 新增了 let 和 const,用来声明变量
let 和 var 的区别:
-
let 不能重复声明
-
let 有块级作用域,非函数的花括号遇见 let 会有块级作用域,也就是只能在花括号里面访问
-
let 不会预解析进行变量提升
-
let 定义的全局变量,不会被作为 window 的属性
-
let 在 es6 中推荐更优先使用~
示例




const 和 var 的差异
const 和 let 类似,不过 const 定义的变量不能再被修改。注意理解:不能再被修改,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。
示例:

模板字符串(template string)是增强版的字符串,用反引号(`)标识
-
字符串中可用出现换行符
-
可以使用 ${xxx} 形式输出变量和拼接变量
示例:

ES6 的解构表达式
可以快速将数组或对象中的值拆分并赋值给变量。使用花括号表示对象 ,方括号表示数组。
数组解构赋值:

该语句将数组[1,2,3]中的第一个值赋值给 a 变量,第二个值赋给 b 变量,第三个值赋给 c 变量。可以使用默认值为变量提供备选值,再数组中缺失对应位置的值时使用该默认值
对象解构赋值:
新增变量名必须和属性名相同

函数参数解构赋值:

ES6 的箭头函数
ES6 中允许使用"箭头"函数。语法类似 Java 中的 Lambda 表达式

使用特点:
箭头函数中的 this 关键字
在 JS 中,this 关键字通常用来引用函数所在的对象
或者在函数本身作为构造函数,来引用新对象的实例
但在箭头函数中有所不同
是由箭头函数定义时的上下文来决定的,而不是函数调用时的上下文决定
箭头函数没有自己的this,this指向的是外层上下文环境的this

this 使用:

这个例子中,我们定义了一个 Counter 构造函数,初始化 count = 0
使用 setInterval 设置了一个定时器,每隔 1 秒执行一次回调函数
箭头函数作为回调,并不会创建自己的 this 绑定,而是继承自外层作用域的 this
因此这里的 this 指向的是 Counter 的实例对象(通过 new 创建的 counter)
当我们执行代码:let counter = new Counter() ,会创建一个 counter 实例,启动定时器,每秒将实例的 count 属性增加1并且打印。
这种行为,是因为箭头函数没有自己的 this 绑定,它会捕获所在上下文的 this 值,如果这里使用普通函数作为 setInterval 的回调,this 会指向全局对象,而不是 Counter 实例
箭头函数的练习:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
#xdd{
display: inline-block;
width: 200px;
height: 200px;
background-color: red;
}
</style>
</head>
<body>
<div id = "xdd"></div>
<script>
var xdd = document.getElementById("xdd")
// 方案 1
xdd.onclick = function() {
console.log(this)
let _this = this // this 是 xdd
// 开启定时器
window.setTimeout(function() {
_this.style.backgroundColor="yellow"
},2000)
}
// 方案 2
xdd.onclick = function(){
console.log(this)
// 开启定时器
setTimeout(()=>{
console.log(this) // 使用 setTimeout 方法所在环境上下文的 this 对象
this.style.backgroundColor="yellow"
},2000)
}
</script>
</body>
</html>
方案1:onclick 的回调是普通函数,其 this 指向绑定事件的 DOM 元素(xdd)
setTimeout 的回调也是普通函数,普通函数的this在非严格模式下默认指向全局对象,因此需要用 _this 保存外层的 this(xdd 元素)
方案2:onclick 的回调仍然是普通函数,其 this 依然指向 xdd 元素
但 setTimeout 的回调改为了箭头函数,箭头函数没有自己的 this,会继承外层作用域的 this,这里的外层作用域是 onclick 的回调函数,其 this 是 xdd,因此箭头函数中的 this 也指向 xdd,无需额外变量保存
总结:箭头函数的 this 是"静态"的,在定义时候就确定了(继承自外层)。而普通函数的 this 是"动态"的,在调用时根据上下文确定。
rest 和 spread
rest 剩余的,解决剩余的参数接收问题 。rest 参数在一个参数列表中的最后一个,这也就要求一个参数列表中只能有一个 rest 参数

spread 展开 rest 在实参上的应用
不可以 let arrSpread = ...arr ...arrr 必须在调用方法时作为实参进行使用

应用:

ES6 的对象创建和拷贝
对象创建的语法糖
ES6 中新增了对象创建的语法糖,支持了 class extends constructor 等关键字,让 ES6 的语法和面向对象的语法更接近
html
<script>
class Person {
// 属性
n;
age;
// getter setter
get name() {
console.log("getter")
return this.n;
}
set name(n) {
console.log("setter")
this.n = n;
}
// 实例方法
eat(food) {
console.log(`${this.age}岁的${this.n}正在吃${food}`)
}
// 静态方法
static sum(a,b) {
return a + b
}
// 构造器
constructor(name, age) {
this.n = name
this.age = age
}
}
let person = new Person('小明',8)
console.log(person.name)
person.eat('火锅')
console.log(Person.sum(10,20))
</script>

补充:如果在属性前加 # 代表该属性为私有属性~
也可以再进行继承:

对象的深拷贝和浅拷贝
浅拷贝时候,arr 和 arr2 指向相同的地址引用,是将 arr 的地址引用赋值给了 arr2

在深拷贝中,是形成一个新的对象

ES6 的模块化处理
模块化介绍
模块化是一种组织和管理前端代码的方式,将代码拆分成小的模块单元,使得代码更易于维护,扩展和复用。包括了定义,导出,导入以及管理模块的方法和规范。
ES6 模块化的几种暴露(导入)方式:分别导出,统一导出,默认导出
!!!ES6 中,无论以何种方式导出,导出的都是一个对象,导出的内容都可以理解为是向这个对象中添加属性或者方法!!!
分别导出

module.js:
javascript
// 1. 分别暴露
// 模块想对外导出,在想要导出的内容前面添加 export 关键字即可
// 导出一个变量
export const PI = 3.14
// 导出一个函数
export function sum(a,b) {
return a+b
}
// 导出一个类
export class Person {
constructor(name, age) {
this.name = name
this.age = age
}
sayHello() {
console.log(`Hello my name is ${this.name},I am ${this.age} years old`)
}
}
app.js:
javascript
// * 代表module.js 中的所有成员
// m1 代表所有成员所属的对象
import * as m1 from './module.js'
// 使用暴露的属性
console.log(m1.PI)
// 使用暴露的方法
let result = m1.sum(10,20)
console.log(result)
// 使用暴露的 Person 类
let person = new m1.Person('张三',18)
person.sayHello()
index.html 作为程序启动的入口,导入 app.js

统一导出
module.js
javascript
// 2. 统一暴露
// 模块想对外导出,export 统一暴露想暴露的内容
// 定义一个常量
const PI = 3.14
// 定义一个函数
let sum = (a, b) => a + b
// 定义一个类
class Person {
constructor(name, age) {
this.name = name
this.age = age
}
sayHello = () => {
console.log(`Hello my name is ${this.name},I am ${this.age} years old`);
}
}
// 统一对外导出
export {
PI,
sum,
Person
}
app.js
javascript
/**
* {} 中导入要使用的来自 module.js 中的成员
* {} 中导入的数据的名称要和 module.js 中导出的保持一致,也可以在此处起别名
* {} 中如果定义了别名,那么在当前模块中,就只能使用别名了
* {} 导入的成员顺序可以不是暴露的顺序
* 一个模块中可以同时导入多个 import
* 多个 import 可以导入多个不同的模块,也可以是同一个模块
*/
import {PI, Person, sum, PI as pi, Person as People, sum as add} from './module.js'
// 使用暴露的属性
console.log(PI)
console.log(pi)
// 使用暴露的方法
let result = sum(10,20)
let result2 = add(10,30)
console.log(result)
console.log(result2)
// 使用暴露的 Person 类
let person1 = new Person('张三',10)
let person2 = new People('李四',15)
person1.sayHello()
person2.sayHello()
index.html:

默认导出
module.js:
javascript
// 3. 默认导出
/**
* 默认导出语法: export default sum
* 默认导出相当于是在暴露的对象中增加了一个名字为 default 的属性
* 三种导出方式可以在一个 module 中混合使用
*/
// 分别导出变量
export const PI = 3.14
// 定义一个函数
let sum = (a,b) => a+b
// 定义一个类
class Person {
constructor(name, age) {
this.name = name
this.age = age
}
sayHello() {
console.log(`Hello my name is ${this.name},I am ${this.age} years old`);
}
}
// 默认导出 一个 js 中只能有一个
export default sum
// 统一导出
export {
Person
}
app.js:
javascript
/**
* app.js 中的 * 代表 module.js 中的所有成员
* m1 代表所有成员所属的对象
*/
import * as m1 from './module.js'
import {default as add} from './module.js'
import add2 from './module.js' // 相当于 import {default as add2 from './module.js'}
// 调用暴露的方法
let result = m1.default(10,20)
console.log(result)
let result2 = add(10,30)
console.log(result2)
let result3 = add2(10,40)
console.log(result3)
// 引入其他方式暴露的内容
import {PI,Person} from './module.js'
// 使用暴露的Person
let person = new Person('zzz',18)
person.sayHello()
// 使用暴露的属性
console.log(PI)
index.html:
