Web 开发概况

Web 开发是指创建和维护网站客户端程序服务器其他 Web 应用程序的过程。它包括使用不同的编程语言和技术来编写、测试和部署 Web 应用程序,以满足特定的业务需求和用户需求

通过 Web 开发技术,开发者能够设计实现诸多满足不同需求场景的应用程序,包括但不限于:网站开发、Android/IOS/Harmony OS NEXT 移动端应用程序、微信小程序、桌面应用、群聊机器人、游戏、浏览器插件、3D 建模、高性能服务器、分布式应用、虚拟现实应用、区块链、物联网设备……

前端和后端

在软件架构和程序设计领域,前端是软件系统中直接和用户交互的部分,而后端控制着软件的输出。将软件分为前端和后端是一种将软件不同功能的部分相互分离的抽象

在 Web 开发中,前端在绝大多数情况下指能够被用户直接访问与交互的模块,如网页、手机 App、桌面应用、小程序等。后端包括程序运行的后台服务器存储数据的数据库以及其他数据中间件。大部分软件都概念性地分成了前端和后端,在大多数情况下,软件的后端经常是隐藏着而不被用户看到

狭义的前端通常是指网站或应用程序中与用户直接交互的部分。它是一种用于构建用户界面的技术和工具的集合,这些界面可以在 Web 浏览器中运行

后端开发主要负责编写运行在服务端上的代码,通常来说,这部分的工作需要和数据库Web API 打交道,比如读写数据、读写文件、实现业务逻辑等。有些时候,业务逻辑存储在客户端,这时后台就是用来以 Web 服务的形式提供数据库中的数据

开发者可以同时掌握前端和后端的技术,但大多数 Web 开发者都还是有一定的专精方向,甚至只在某一方面深入研究。尽管前后端是有天然的区别,但并没有规定它们各自的具体任务。有时前端只是完成数据的显示,而其他主要工作都在后端完成。但也有时,后端只是提供数据,而所有的计算和具体功能都在前端完成。前后端工作的分配,通常都是由项目的设计和架构来决定

浏览器

浏览器是用来检索、展示以及传递 Web 信息资源的应用程序。Web 信息资源由统一资源标识符 (Uniform Resource Identifier,URI) 所标记,它可以是一张网页、一张图片、一段视频或者任何在 Web 上所呈现的内容。使用者可以借助超链接通过浏览器浏览互相关联的信息

浏览器内核 (Rendering Engine),是指浏览器最核心的部分,负责对网页语法的解释(如标准通用标记语言下的一个应用 HTML、CSS、JavaScript)并渲染网页。通常所谓的浏览器内核也就是浏览器所采用的渲染引擎,渲染引擎决定了浏览器如何显示网页的内容以及页面的格式信息。不同的浏览器内核对网页编写语法的解释也有不同

C/S B/S 架构

C/S 架构是一种典型的两层架构,其全称是 Client/Server,即客户服务器端架构,其客户端包含一个或多个在用户的电脑上运行的程序,而服务器端有两种,一种是数据库服务器端,客户端通过数据库连接访问服务器端的数据;另一种是 Socket 服务器端,服务器端的程序通过 Socket 与客户端的程序通信

B/S 架构的全称为 Browser/Server,即浏览器/服务器结构。Browser 指的是 Web 浏览器,极少数事务逻辑在前端实现,但主要事务逻辑在服务器端实现。B/S 架构的系统无须特别安装,只要有 Web 浏览器即可

HTML

超文本标记语言(Hyper Text Markup Language,简称:HTML)是一种用于创建网页的标准标记语言。HTML 是一种基础技术,常与 CSS、JavaScript 一起被众多网站用于设计网页网页应用程序以及移动应用程序用户界面。网页浏览器可以读取 HTML 文件,并将其渲染成可视化网页。HTML 描述了一个网站的结构语义随着线索的呈现,使之成为一种标记语言而非编程语言

CSS

层叠样式表(Cascading Style Sheets)是一种用来为结构化文档(如 HTML 文档或 XML 应用)添加样式(字体、间距和颜色等)的计算机语言。CSS3 现在已被大部分现代浏览器支持,而下一版的 CSS4 仍在开发中。CSS 不仅可以静态地修饰网页,还可以配合各种脚本语言动态地对网页各元素进行格式化。CSS 能够对网页中元素位置的排版进行像素级精确控制,支持几乎所有的字体字号样式,拥有对网页对象和模型样式编辑的能力

JavaScript

JavaScript 是一种高级的、解释型编程语言

JavaScript 是一门基于原型、头等函数的语言,是一门多范式的语言,它支持面向对象程序设计,指令式编程,以及函数式编程。它由 ECMA(欧洲电脑制造商协会)通过 ECMAScript 实现语言的标准化

ECMAScript 6.0(简称 ES6)是 JavaScript 语言的下一代标准,于 2015 年 6 月正式发布。它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言

ES6 既是一个历史名词,也是一个泛指,含义是 5.1 版以后的 JavaScript 的下一代标准,涵盖了 ES2015、ES2016、ES2017 等等,而 ES2015 则是正式名称,特指该年发布的正式版本的语言标准

计算机网络基础知识

HTTP 协议

HTTP 是 Hyper Text Transfer Protocol(超文本传输协议)的缩写。HTTP 协议用于从 WWW 服务器传输超文本到本地浏览器的传送协议。它可以使浏览器更加高效,使网络传输减少。它不仅保证计算机正确快速地传输超文本文档,还确定传输文档中的哪一部分,以及哪部分内容首先显示 (如文本先于图形) 等。HTTP 是一个应用层协议,由请求响应构成,是一个标准的客户端服务器模型

URL

在互联网上,每一信息资源都有统一的且在网上唯一的地址,该地址就叫 URL(Uniform Resource Locator, 统一资源定位符)。

URL 由三部分组成:资源类型、存放资源的主机域名、资源文件名

也可认为由 4 部分组成:协议主机端口路径

URL 的一般格式为:protocol :// hostname [:port] / path / [:parameters] [?query] #fragment

IP 地址和 DNS

IP 地址(类似 192.168.1.1 内网网关)是互联网协议地址,它给因特网上的每台计算机和其它设备都规定了一个唯一的地址。由于有这种唯一的地址,才保证了用户在连网的计算机上操作时,能够高效而且方便地从千千万万台计算机中选出自己所需的对象来

但是 IP 地址毕竟是一串毫无规律的数字,并不方便人类的记忆和书写。因此在 IP 地址的基础上又发展出一种符号化的地址方案,来代替数字型的 IP 地址,每一个符号化的地址都与特定的 IP 地址对应。这个与网络上的数字型 IP 地址相对应的字符型地址,就是域名

类似 http://www.google.com 这样的字符串就是“域名”,当访问 www.google.com 时,首先由 DNS(Domain Name System, DNS)域名系统解析为 IP 地址,随后再访问 IP

HTTP 请求

HTTP 请求是指从客户端到服务器端的请求消息,请求报文由请求行 (Request line)、请求头 (Header),空行、请求正文 4 部分组成

HTTP 响应

在接收和解释请求消息后,服务器会返回一个 HTTP 响应消息。HTTP 响应报文也由四个部分组成,分别是:状态行、消息报头、空行和响应正文

HTTP 方法

根据 HTTP 标准,HTTP 请求可以使用多种请求方法。HTTP 方法描述了对给定资源的期望动作,每一种请求方法都抽象出了一种不同给定语义。

HTTP1.0 定义了三种请求方法:GET、POST 和 HEAD 方法。

HTTP1.1 新增了六种请求方法:OPTIONS、PUT、PATCH、DELETE、TRACE 和 CONNECT 方法。

在实际开发中 GET、POST、PUT、DELETE 四类 HTTP 方法的使用率最高,能够用一套统一的语法规范对资源的 CRUD (增删改查) 逻辑进行抽象

GET 方法请求一个指定资源的表示形式,使用 GET 的请求应该只被用于获取数据

POST 方法用于将实体提交到指定的资源,通常导致在服务器上的状态变化或副作用

PUT 方法用请求有效载荷替换目标资源的所有当前表示

DELETE 方法删除指定的资源

HTTP 状态码

当浏览者访问一个网页时,浏览者的浏览器会向网页所在服务器发出请求。当浏览器接收并显示网页前,此网页所在的服务器会返回一个包含 HTTP 状态码的信息头(server header)用以响应浏览器的请求

状态码类型:

状态码 类别 原因
1xx 信息性状态码 接收的请求正在处理
2xx 成功状态码 请求正常处理完毕
3xx 重定向状态码 需要进行附加操作以完成请求
4xx 客户端错误状态码 服务器无法处理请求
5xx 服务端错误状态码 服务器处理请求出错

常见的状态码:

100 Continue

客户端应继续其请求

200 OK

请求成功,一般用于 GET 与 POST 请求

201 Created

已创建,成功请求并创建了新的资源

401 Unauthorized

请求要求用户的身份认证

403 Forbidden

服务器理解请求客户端的请求,但是拒绝执行此请求

404 Not Found

服务器无法根据客户端的请求找到资源(网页)。

500 Internal Server Error

服务器内部错误,无法完成请求

RESTful API

REST 全称是 Representational State Transfer,中文意思是表述性状态转移

RESTful 架构应该遵循统一接口原则,统一接口包含了一组受限的预定义的操作,不论什么样的资源,都是通过使用相同的接口进行资源的访问。

接口应该使用标准的 HTTP 方法如 GET,PUT 和 POST,并遵循这些方法的语义。

REST 所谓的表述指的是对资源的表述。要让一个资源可以被识别,需要有个唯一标识,在 Web 中这个唯一标识就是 URI

版本控制工具

Git 版本控制工具

Git 是一个开源的分布式版本控制系统,可以有效、高速地处理从很小到非常大的项目版本管理。也是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件

GitHub 代码托管仓库

GitHub 是一个面向开源及私有软件项目的托管平台,因为只支持 Git 作为唯一的版本库格式进行托管

基础知识

库是一系列预先定义好的数据结构和函数或类的集合,程序员可以通过调用这些代码实现功能。简单来说就是库为我们提供了很多封装好的函数,看起来比较零散,但使用起来更灵活

使用库可以简化开发流程,提高开发效率。例如,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 诞生了

模块化编程

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

比如,我要写一个 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
// 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

npm 的常见命令

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

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

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

npm uninstall <Name> 卸载模块

1
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 文件中是不允许添加注释的

打包

打包是指将多个模块( 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

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 将这些代码打包并优化,最终生成浏览器可以解析的文件。