现代前端开发基础

库和框架

库是一系列预先定义好的数据结构和函数或类的集合,程序员可以通过调用这些代码实现功能。简单来说就是库为我们提供了很多封装好的函数,看起来比较零散,但使用起来更灵活,只用取里面我们需要的某部分,再自己实现项目中其他部分得功能

库就类似于 C 语言中的头文件,比如 <stdio.h> 头文件提供了一系列常用的功能:printf()scanf()gets()fopen()

在前端开发中,使用库可以简化开发流程,提高开发效率。例如,jQuery 提供了简化 DOM 操作的语法,减少了编写繁琐代码的需要。React 通过虚拟 DOM 和声明式 UI ,便于快速构建用户界面

如果需要在网页中使用 JavaScript 库,可以去网上下载库文件,放在网页的同一目录下,再到script标签中引入。或者不下载通过通过链接在<script>标签中引用该库即可:

1
<script src="https://cdn.staticfile.org/jquery/3.4.0/jquery.min.js"></script>

或者在代码中通过 require 或者 import 中引入库。在现代的前端开发中,通常推荐使用 import 来进行模块导入,特别是在使用现代 JavaScript 特性的项目中。这主要与现代 JavaScript 的发展趋势和语言特性有关

import 是 ES6 新引入的关键字,支持按需导入,而不需要导入整个模块。同时import 的语法也比 require 更直观清晰,更符合现代变成风格

随着 JavaScript 生态的发展,越来越多的库和工具采用了 ES6 模块系统,使用 import 能够更好地与这些现代化的工具和库进行集成。

框架

框架是提供如何构建应用程序的意见的库,是一整套的工具,所有东西已经准备齐全了,可以按照它的规定就可以很简单的完成一些事情,但我们不能去改变它,只能按照要求使用,并且其他人拿到这套工具也是一样的,如 Vue、Angular 等等。

注意是一套而不是单个,比如 React 就是一个库,它本身只是一个前端渲染的库,纯粹地写 UI 组件,没有什么异步处理机制、模块化等,但是当它结合 Redux 和 React-router 的时候,就是一个框架了。

框架和库的联系紧密,都是为了提高我们的开发效率而存在,库的使用上会简单一些,更加灵活,但功能不全。而框架的功能很全面,但需要我们按规定去使用。也就是说库是一种工具,我提供了,你可以不用,即使你用了,也没影响你自己的代码结构,控制权在使用者手中。框架则是面向一个领域,提供了一套解决方案

区别

库是一组已经实现的代码集合,提供了特定功能的函数和方法,开发者可以根据需要选择性地使用。库不控制应用程序的整体架构,而是为开发者提供了可调用的工具,以便在应用程序中实现特定功能

框架是一种提供了一整套解决方案的软件结构,它规定了整个应用程序的架构,定义了组织代码的方式,并提供了一系列工具和库,以便开发者可以在框架的基础上构建应用。框架通常有一个完整的生命周期,控制着应用程序的流程,开发者需要按照框架的规则来编写代码。

Node.js

什么是 Node.js

JavaScript 是一个脚本语言,最初用来处理网页中的一些动态功能和一些用户行为。它一般运行于浏览器

但是这门语言后续不断更新,越来越多的人开始使用 JavaScript 。为了把它迁移到了服务端,但服务端上又不能跑浏览器,那我们就需要一种新的运行环境。就这样,这个基于 Chrome V8 引擎的 JavaScript 运行时 Node.js 诞生了

安装 Node.js

打开 Node.js 的官网链接

单击左侧的 LTS 版本进行下载

image-20240123155049028

安装过程没什么好说的,一路下一步

image-20240123155413105

之后我们就可以在终端中执行 node命令编译运行 .js 文件

image-20240123155752568

模块化编程

在计算机编程中,模块是指一个相对独立的程序文件或代码库,通常包含一组相关的函数、变量、类或其他可重用的代码构件,每个模块在内部执行某个功能。并向外部公开一定的接口以供其他模块使用。在编程语言中,通常有一些标准库或第三方库,这些库都是由多个模块组成的,可以在程序中被引用和使用。模块化主要是为了帮助程序员组织和管理大型代码库,可以将大型的程序有逻辑地拆分成一个个相对较小的部分,实现代码复用,让程序设计更加灵活,使其更易于维护和扩展。这是优点之一。并且还可以避免变量名和函数名命名冲突的问题以及解决不同模块之间的依赖关系。

比如,我要写一个 Wordle 小游戏,普通代码编写就把所有代码像画布渲染,键盘的输入,逻辑判断等都写到一个 HTML 文件里,如果使用模块化概念,我们可以简单分块,分成主文件,键盘输入,逻辑判断以及读取 json 等多个模块,然后在各个文件里实现相应的逻辑,这样假如你发现 json 的读取有问题,你就可以直接去找读 json 那个文件有没有问题,这样会让代码的后续维护更简单,目的更明确。

importexport 是 ES6 引入的模块系统的关键字,用于在 JavaScript 中进行模块化编程。模块化使得代码更结构化、可维护,并允许开发者将代码分割为小的可重用部分

export 的使用:

export 用于将变量、函数、类或其他声明导出为模块的公共接口,以便其他模块可以使用。有三种常见的 export 的方式

命名导出

可以通过 export 关键字单独导出多个成员

1
2
3
4
5
// module.js
export const myVariable = 42;
export function myFunction() {
// ...
}
默认导出

通过 export default 关键字导出一个默认成员,每个模块只能有一个默认导出

1
2
3
// module.js
const myVariable = 42;
export default myVariable;

import 的使用:

import 用于在一个模块中引入其他模块导出的成员,以便在当前模块中使用。有三种常见的 import 的方式:

命名导入

导入其他模块中的命名导出

1
2
// main.js
import { myVariable, myFunction } from "./module";
默认导入

导入其他模块中的默认导出

1
2
// main.js
import myVariable from "./module";
导入所有

导入其他模块的所有导出,形成一个命名空间对象

1
2
// main.js
import * as myModule from "./module";

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// module.js
export const myVariable = 42;

export function myFunction() {
// ...
}

const internalVariable = "internal";
export default internalVariable;

// main.js
import { myVariable, myFunction } from "./module";

console.log(myVariable); // 42
myFunction();

import internalVariable from "./module";
console.log(internalVariable); // 'internal'

import * as myModule from "./module";
console.log(myModule.myVariable); // 42

npm

JavaScript 包是一种封装了代码、资源的组织形式,能够方便共享、安装和管理代码。这些包可以包含 JavaScript 库、框架、工具或应用程序等。而 npm 就是管理这些包的工具(当然除了 npm 也有其他工具,比如 yarnyum等),专门用于在服务器端和命令行工具中管理 JavaScript 包

为什么我们需要包管理工具呢?我们一次性把包都下载到电脑里,像 C 语言的头文件一样,需要用什么拿什么不就好了吗?首先,JavaScript 的包多达 90 万个,将所有这些包完全下载到本地会占用大量存储空间。这对于开发者的计算机来说可能是不切实际的,特别是在多个项目中共享相同的依赖项时。其次,软件包和库经常会更新,手动下载所有包可能导致更新不及时,使得项目失去了最新的功能和安全性修复。最后,有的项目需要使用某个包特定的版本,使用其他版本会导致项目无法运行或出现其他 bug,而包管理工具允许开发者指定项目所使用的依赖项的特定版本,以确保项目的稳定性和一致性。手动下载所有包可能会导致版本冲突和不同环境之间的不一致。因此我们需要使用包管理工具

npm 是随同 Node.js 安装的包管理工具,安装好 node 之后就会默认安装好 npm

我们可以在命令行中输入 npm -v 判断是否安装了 npm

image-20240123213514850

如果成功获取到了版本号,说明 npm 已经成功的安装在您的电脑中了

npm 的常见命令

npm install <Module Name> 使用 npm 命令本地安装模块

npm install -g <Module Name> 全局安装

两个的区别就是本地安装将安装包放在当前文件夹的 node_modules (如果没有则会自动生成)文件夹下,通过 import 来引入本地安装的包;全局安装包则通常放在 node 的安装目录下,可以直接在命令行里使用

npm uninstall <Name> 卸载模块

npm install -g npm@<版本号> 更新 npm

npm publish 将自己的代码发布到 npm 上的全球开源库中

package.json

package.json 是 Node.js 项目中的一个重要文件,它用于存储项目的配置信息。包含了项目的元数据(metadata),如项目名称、版本、作者、依赖库等信息。通过描述项目上下文、所需依赖和开发脚本,使项目具备可重复性和可移植性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
{
"name": "learn_react", // 项目的名称
"version": "0.1.0", // 项目的版本号
"private": true, // 用于指示是否将该项目发布到公共的包注册表的标志
"dependencies": {
// 项目运行时所依赖的第三方包
"@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^13.0.0",
"@testing-library/user-event": "^13.2.1",
"@types/jest": "^27.0.1",
"@types/node": "^16.7.13",
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"typescript": "^4.4.2",
"web-vitals": "^2.1.0"
},
"scripts": {
// 定义一组自定义的命令脚本
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"browserslist": {
// 用于指定项目所支持的目标浏览器范围的配置文件,通常用于前端开发
"production": [
">0.2%", // 支持全球使用率超过0.2%的浏览器
"not dead", // 排除已经被官方宣布为不再更新的浏览器
"not op_mini all" // 用于排除 Opera Mini 浏览器,Opera Mini 具有一些独特的行为或限制,需要在项目中进行特殊处理
],
"development": [
"last 1 chrome version", // 支持每个浏览器的最后一个版本
"last 1 firefox version",
"last 1 safari version"
]
}
}

如果项目有 package.json 文件,则通过命令 npm install 可以根据 "dependencies" 自动在 node_modules 文件夹中安装项目所需的所有包

注:上述 package.json 的注释是粘贴到 md 后再加的,目的是讲解键值对的意义,而 json 文件中是不允许添加注释的:

image-20240310183237979

打包

打包是指将多个模块( JavaScript、CSS、图片等)打包成为一个文件,这有助于代码管理、发布和使用。在前端开发中,通常需要使用打包工具将代码打包成浏览器可识别的格式,并优化加载速度和性能。

为什么前端需要打包?以前的前端开发存在三个大问题:没有模块化、第三方包的引入繁琐困难、代码以明文形式展示出来

我们利用打包工具就可以实现:支持模块化、自动打包第三方包、代码混淆,使得其他人无法阅读

下面介绍两个常使用的与打包有关的工具

Babel

Babel 是一个 JavaScript 编译器,它能够将 ECMAScript 2015+ 的新特性转换为向后兼容的 JavaScript 代码,例如将 ES6 的箭头函数转换为普通函数、将模板字符串转换为常规字符串等等,使得我们可以在现代浏览器中使用最新的 JavaScript 特性,从而解决浏览器兼容性问题

执行 npm install -g babel-cli 安装 Babel

在项目根目录创建 .babelrc 文件,这是 Babel 的配置文件,并编写:

1
2
3
4
{
"presets": ["es2015"],
"plugins": []
}

执行 npm install babel-preset-es2015 安装转码器,就是从源码转到老版本的代码中间的语法映射表

在根目录创建 src 文件夹,新建 index.js 并编写如下代码

1
2
3
4
// ./src/index.js
let [a, b, c] = [1, 2, 3];
[a, b, c] = [b, c, a + 1];
console.log(a, b, c);

这里用到了 ES6 的新特性解构赋值,执行 babel src -d dist Babel 就能够将它转换为旧的 ES2015 代码:

1
2
3
4
5
6
7
8
9
10
11
12
// ./dist/index.js
"use strict";

var a = 1,
b = 2,
c = 3;
var _ref = [b, c, a + 1];
a = _ref[0];
b = _ref[1];
c = _ref[2];

console.log(a, b, c);

Webpack

Webpack 是一个模块打包工具,它可以将多个模块打包成一个或多个 JavaScript 文件,而这些 JavaScript 文件可以被浏览器正确加载执行。Webpack 可以处理各种类型的资源文件,如 JS、CSS、图片等,并提供了各种插件和 loader 用于对不同类型的资源进行处理和优化,同时还支持热更新功能,方便开发人员进行调试和开发

Webpack 会隐藏源码的细节,把多个 JavaScript 合并成一个 JavaScript,提高浏览器的访问速度,使源码更加安全

执行 npm install -g webpack webpack-cli 安装 Webpack

修改 src 下的 index.js

1
2
3
4
5
// ./src/index.js
let [a, b, c] = [1, 2, 3];
[a, b, c] = [b, c, a + 1];
let arr = [a, b, c];
export default arr;

src 下新建 main.js

1
2
3
// ./src/main.js
import arr from "./index.js";
console.log(arr);

在根目录下定义一个 webpack.config.js 文件配置打包规则:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//导入path模块,nodejs的内置模块
const path = require("path");
//定义JS打包的规则
module.exports = {
//指定构建的模式
mode: "development",
//入口函数从哪里开始进行编译打包
entry: "./src/main.js",
//编译成功以后要把内容输出到那里去
output: {
//定义输出的指定的目录__dirname 当前项目根目录,将生成一个dist文件夹
path: path.resolve(__dirname, "./dist"),
//合并的js文件存储在dist/bundle.js文件中
filename: "res.js",
},
};

终端执行 webpack 即可在 dist 文件夹中看到生成的 res.js,这就是合并后的 JavaScript 代码

通常在前端项目中,我们会将 Babel 和 Webpack 结合使用,使用 Babel 将最新版本的语法转换成向后兼容的代码,再由 Webpack 将这些代码打包并优化,最终生成浏览器可以解析的文件。