当前位置: 首页 > news >正文

Javaweb - 14.1 - 前端工程化

目录

前端工程化

什么是前端工程化

前端工程化实现技术栈

ECMA6Script

ES6 介绍

ES6 的变量和模板字符串

ES6 的解构表达式

ES6 的箭头函数

rest 和 spread

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 新增了 letconst,用来声明变量

let 和 var 的区别:

        1. let 不能重复声明

        2. let 有块级作用域,非函数的花括号遇见 let 会有块级作用域,也就是只能在花括号里面访问

        3. let 不会预解析进行变量提升

        4. let 定义的全局变量,不会被作为 window 的属性

        5. let 在 es6 中推荐更优先使用~

示例

1.

2.

3.

4.

const 和 var 的差异

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

示例:

模板字符串(template string)是增强版的字符串,用反引号(`)标识

        1. 字符串中可用出现换行符

        2. 可以使用 ${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 实例

箭头函数的练习:

<!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")// 方案 1xdd.onclick = function() {console.log(this)let _this = this // this 是 xdd// 开启定时器window.setTimeout(function() {_this.style.backgroundColor="yellow"},2000)}// 方案 2xdd.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 的语法和面向对象的语法更接近

    <script>class Person {// 属性n;age;// getter setterget 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 = namethis.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:

// 1. 分别暴露
// 模块想对外导出,在想要导出的内容前面添加 export 关键字即可// 导出一个变量
export const PI = 3.14// 导出一个函数
export function sum(a,b) {return a+b
}// 导出一个类
export class Person {constructor(name, age) {this.name = namethis.age = age}sayHello() {console.log(`Hello my name is ${this.name},I am ${this.age} years old`)}
}

app.js:

// * 代表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

// 2. 统一暴露
// 模块想对外导出,export 统一暴露想暴露的内容// 定义一个常量
const PI = 3.14// 定义一个函数
let sum = (a, b) => a + b// 定义一个类
class Person {constructor(name, age) {this.name = namethis.age = age}sayHello = () => {console.log(`Hello my name is ${this.name},I am ${this.age} years old`);}
}// 统一对外导出
export {PI,sum,Person
}

app.js

/*** {} 中导入要使用的来自 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:

// 3. 默认导出
/*** 默认导出语法: export default sum* 默认导出相当于是在暴露的对象中增加了一个名字为 default 的属性* 三种导出方式可以在一个 module 中混合使用*/// 分别导出变量
export const PI = 3.14// 定义一个函数
let sum = (a,b) => a+b// 定义一个类
class Person {constructor(name, age) {this.name = namethis.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:

/***  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:

完!

http://www.xdnf.cn/news/1265599.html

相关文章:

  • day16 - CSS3新增属性
  • 利用whisper api实现若无字幕则自动下载音频并用 whisper 转写,再用 LLM 总结。
  • Blender 快捷键速查表 (Cheat Sheet)
  • 数据结构(9)——排序
  • 202506 电子学会青少年等级考试机器人二级理论综合真题
  • 本文章分享一个本地录音和实时传输录音给app的功能(杰理)
  • java10学习笔记
  • IntelliJ IDEA 新手全方位使用指南
  • 服务机器人选择屏幕的逻辑
  • 7、docker |其余命令
  • spring.config.import 不存在
  • Pytest中实现自动生成测试用例脚本代码
  • kettle插件-kettle MinIO插件,轻松解决文件上传到MinIO服务器
  • C++隐式转换的魔法与陷阱:explicit关键字的救赎
  • qt文件操作与qss基础
  • 推荐系统学习笔记(十一)预估分数融合
  • java web项目入门了解
  • Go语言接口实战指南
  • 聊聊经常用的微服务
  • Baumer高防护相机如何通过YoloV8深度学习模型实现火星陨石坑的检测识别(C#代码UI界面版)
  • 集成电路学习:什么是RQT图形用户界面工具
  • 智慧园区误报率↓76%:陌讯多模态融合算法实战解析
  • 智能情趣设备、爆 bug:可被远程操控。。。
  • 计算机网络:如何将/22的CIDR地址块划分为4个子网
  • 前端视角下关于 WebSocket 的简单理解
  • rosrun 和 roslaunch 区别
  • [激光原理与应用-205]:光学器件 - LD与DFB的比较
  • JavaWeb03——javascript基础语法
  • 微信小程序功能 表单密码强度验证
  • 从浅拷贝到深拷贝:C++赋值运算符重载的核心技术