分类: 计算机

  • WEB前端-HTML篇

    新增标签元素

    标签类别 具体标签
    语义化结构标签 header、footer、nav、main、article、section、aside、figure、figcaption、time、mark
    多媒体标签 audio、video、source、track、canvas、svg
    表单增强元素 datalist、output、meter、progress
    新增 Input 类型 input(date)、input(datetime)、input(email)、input(number)、input(range)、input(tel)、input(color)、input(time)、input(url)、input(search)
    其它标签 details、summary、dialog、template

    本地存储

    生命周期:

    • cookie 可设置过期时间
    • localStorage 永久存储
    • sessionStorage 关闭标签页自动清除

    存储大小:

    • cookie 4KB
    • sessionStorage 5MB – 10MB
    • localStorage 5MB – 10MB

    作用域:

    • cookie:可设置 Domain 和 Path,控制哪些域名和路径可以访问
    • localStorage:同源策略下的所有窗口和标签页共享
    • sessionStorage:仅当前标签页有效,即使同源的其他标签页也无法访问

    以下是整理成 Markdown 表格的浏览器存储特性对比:

    特性 Cookie localStorage sessionStorage
    生命周期 可设置过期时间(Expires/Max-Age 永久存储,除非手动清除 关闭标签页后自动清除
    存储大小 约 4KB 5MB – 10MB(不同浏览器可能有差异) 5MB – 10MB(同 localStorage)
    作用域 通过 DomainPath 控制访问范围 同源策略下的所有窗口/标签页共享 仅当前标签页有效,同源其他标签页不可访问
    数据发送 每次请求自动携带在 HTTP 头部 不自动发送,仅客户端存储 不自动发送,仅客户端存储
    API 易用性 需手动解析字符串 直接使用 setItem()/getItem() 等操作 同 localStorage

    补充说明

    • 同源策略:协议、域名、端口必须完全相同。
    • 安全建议:
      • Cookie 敏感数据建议设置 HttpOnlySecure 属性。
      • 大容量数据优先使用 localStoragesessionStorage
      • sessionStorage 适合临时数据(如表单填写中途防止丢失)。

    <script> 加载方式

    <!-- 默认加载:同步阻塞 HTML 解析 -->
    <script src="script.js"></script>
    <!-- defer 加载:延迟执行,直至 DOM 解析完成后 -->
    <script defer src="script.js"></script>
    <!-- async 加载:异步引入,下载完成后立即执行 -->
    <script async src="script.js"></script>

    加载说明

    • 默认:<script> 同步加载,阻塞 HTML 解析和渲染
    • defer:<script> 延迟执行,DOM 解析完成后按顺序执行
    • async:<script> 异步加载,下载完成后立即执行(执行顺序不固定)
  • 【Typescript】接口、类

    接口

    TypeScript的核心原则之一是对值所具有的结构进行类型检查。

    interface LabelledValue {
      label: string;
    }
    
    function printLabel(labelledObj: LabelledValue) {
      console.log(labelledObj.label);
    }
    
    let myObj = {size: 10, label: "Size 10 Object"};
    printLabel(myObj);

    可选属性

    interface SquareConfig {
        width: number
        height: number
        color?: string // 可选属性
    }

    只读属性

    只能在刚创建时修改其值

    interface Point {
        readonly x: number;
        readonly y: number;
    }

    额外的属性检查

    如果 SquareConfig带有上面定义的类型的color和width属性,并且还会带有任意数量的其它属性,可以这样定义:

    interface SquareConfig {
        width: number
        color?: string
        [propName: string]: any
    }

    函数类型

    interface SearchFunc {
      (source: string, subString: string): boolean
    }
    
    // 对于函数类型的类型检查来说,函数的参数名不需要与接口里定义的名字相匹配。 
    let mySearch: SearchFunc;
    mySearch = function(src: string, sub: string): boolean {
      let result = src.search(sub);
      return result > -1;
    }

    可索引的类型

    interface StringArray {
      [index: number]: string;
    }
    
    let myArray: StringArray;
    myArray = ["Bob", "Fred"];
    
    let myStr: string = myArray[0];

    类类型

    interface ClockInterface {
        currentTime: Date;
        setTime(d: Date);
    }
    
    // 通过 implements 描述
    class Clock implements ClockInterface {
        currentTime: Date;
        setTime(d: Date) {
            this.currentTime = d;
        }
        constructor(h: number, m: number) { }
    }

    继承接口

    interface Shape {
        color: string;
    }
    
    interface PenStroke {
        penWidth: number;
    }
    
    interface Square extends Shape, PenStroke {
        sideLength: number;
    }
    
    let square = 
    <Square>{};
    square.color = "blue"
    square.sideLength = 10
    square.penWidth = 5

    混合类型

    一个对象可以同时做为函数和对象使用,并带有额外的属性

    interface Counter {
        (start: number): string;
        interval: number;
        reset(): void;
    }
    
    function getCounter(): Counter {
        let counter = 
    <Counter>function (start: number) { };
        counter.interval = 123;
        counter.reset = function () { };
        return counter;
    }
    
    let c = getCounter();
    c(10);
    c.reset();
    c.interval = 5.0;

    class Animal {
        move(distanceInMeters: number = 0) {
            console.log(`Animal moved ${distanceInMeters}m.`);
        }
    }
    
    class Dog extends Animal {
        bark() {
            console.log('Woof! Woof!');
        }
    }
    
    const dog = new Dog();
    dog.bark();
    dog.move(10);
    dog.bark();

    继承

    通过 extends 关键字

    class Animal {
        name: string;
        constructor(theName: string) { this.name = theName; }
        move(distanceInMeters: number = 0) {
            console.log(`${this.name} moved ${distanceInMeters}m.`);
        }
    }
    
    class Snake extends Animal {
        constructor(name: string) { super(name); }
        move(distanceInMeters = 5) {
            console.log("Slithering...");
            super.move(distanceInMeters);
        }
    }

    公共,私有与受保护的修饰符

    public(默认)

    在TypeScript里,成员都默认为 public。

    class Animal {
        public name: string;
    }
    private

    当成员被标记成private时,它就不能在声明它的类的外部访问。

    class Animal {
        private name: string
        constructor(theName: string) { this.name = theName; }
    }
    
    new Animal('Cat').name // 错误: 'name' 是私有的.
    protected

    protected与private修饰符的行为很相似,但有一点不同, protected成员在派生类中仍然可以访问。

    class Person {
        protected name: string
        constructor(name: string) { this.name = name }
    }
    
    class Employee extends Person {
        private department: string
        public getElevatorPitch() {
            return `my name is ${this.name} and I work in ${this.department}.`
        }
    }
    
    let dick = new Employee("Howard", "Sales")
    console.log(dick.getElevatorPitch());
    console.log(dick.name); // 错误

    readonly修饰符

    readonly关键字将属性设置为只读的。 只读属性必须在声明时或构造函数里被初始化。

    class Octopus {
        readonly name: string;
        constructor (theName: string) {
            this.name = theName;
        }
    }
    let dad = new Octopus("Man with the 8 strong legs");
    dad.name = "Man with the 3-piece suit"; // 错误! name 是只读的.

    存取器

    TypeScript支持通过getters/setters来截取对对象成员的访问。

    let passcode = "secret passcode";
    
    class Employee {
        private _fullName: string;
    
        get fullName(): string {
            return this._fullName;
        }
    
        set fullName(newName: string) {
            if (passcode && passcode == "secret passcode") {
                this._fullName = newName;
            }
            else {
                console.log("Error: Unauthorized update of employee!");
            }
        }
    }
    
    let employee = new Employee();
    employee.fullName = "Bob Smith";
    if (employee.fullName) {
        alert(employee.fullName);
    }

    抽象类

    抽象类做为其它派生类的基类使用。 它们一般不会直接被实例化。

    abstract class Department { ... }
    class AccountingDepartment extends Department { ... }
    
    let department: Department // 允许创建一个对抽象类型的引用
    department = new Department() // 错误: 不能创建一个抽象类的实例
    department = new AccountingDepartment() // 允许对一个抽象子类进行实例化和赋值
  • 【JS】小数精度处理技巧

    JavaScript 使用 IEEE 754 双精度浮点数表示所有数字,这会导致一些常见的小数精度问题,例如 0.1 + 0.2 !== 0.3。以下是处理 JavaScript 小数精度的常用技巧:

    1. 四舍五入方法

    // toFixed方法(返回字符串)
    let num = 0.1 + 0.2; // 0.30000000000000004
    let fixed = num.toFixed(2); // "0.30"
    
    // 使用Math.round四舍五入
    function round(value, decimals) {
      return Number(Math.round(value + 'e' + decimals) + 'e-' + decimals);
    }
    round(1.005, 2); // 1.01

    2. 精度运算库

    使用专门的数学库处理精确计算:

    • decimal.js —— 功能相对简单,适合基本的高精度计算需求
    • big.js —— 支持三角函数、指数、对数等高级数学运算
    // 使用decimal.js示例
    import Decimal from 'decimal.js';
    let sum = new Decimal(0.1).add(new Decimal(0.2)); // 0.3

    3. 整数运算技巧

    将小数转换为整数进行计算,再转换回去:

    function add(num1, num2) {
      const multiplier = Math.pow(10, Math.max(getDecimalLength(num1), getDecimalLength(num2)));
      return (num1 * multiplier + num2 * multiplier) / multiplier;
    }
    
    function getDecimalLength(num) {
      const decimalStr = num.toString().split('.')[1];
      return decimalStr ? decimalStr.length : 0;
    }

    4. 比较数字时的容差方法

    function numbersEqual(a, b, tolerance = 1e-10) {
      return Math.abs(a - b) < tolerance;
    }

    5. 格式化显示

    // 使用Intl.NumberFormat
    const formatter = new Intl.NumberFormat('en-US', {
      minimumFractionDigits: 2,
      maximumFractionDigits: 2
    });
    formatter.format(0.1 + 0.2); // "0.30"

    6. 避免常见陷阱

    • 不要直接比较浮点数
    • 对于货币计算,通常使用整数表示分(如用100表示1.00元)
    • 大整数计算考虑使用BigInt类型

    对于简单的显示问题,toFixed可能足够;对于复杂的财务计算,建议使用专门的库。

  • 【NPM】package.json 参数详解

    package.json 必须是纯 JSON 格式,而不仅仅是一个 JavaScript 对象字面量。

    name 和 version

    Name 和 version 字段是 package.json 文件中最重要的字段。这是必须的字段,如果你的 npm 包没有指定这两个字段,将无法被安装。name 和 version 字段被假定组合成一个唯一的标识符。包内容的更改和包版本的更改是同步的。

    description

    npm 包的描述,description 是一个字符串。它可以帮助人们在使用 npm search 时找到这个包。

    keywords

    npm 包的关键字,keywords 是一个字符串的数组。它可以帮助人们在使用 npm search 时找到这个包。

    homepage

    项目主页的 url

    bugs

    改项目的 issue 跟踪页面或这报告 issue 的 email 地址。这对使用这个包遇到问题的用户会有帮助。

    license

    证书许可。SPDX表达式:

    { "license": "ISC" }
    { "license": "(MIT OR Apache-2.0)" }

    通常我们不希望授权别人以任何形式使用的私有包或未发布包,可以这样写:

    { "license": "UNLICENSED”}

    或者设置

    { "private": true }

    author, contributors

    关于人的字段

    files

    files 字段是一个被项目包含的文件名数组,如果你在里面放一个文件夹名,那么这个文件夹中的所有文件都会被包含进项目中(除非是那些在其他规则中被忽略的文件)。

    main

    Main 字段指定了模块的入口程序文件。就是说,如果你的模块名叫 "foo",用户安装了它,并且调用了 require("foo"),则这个main字段指定的模块的导出对象会被返回。 例如 node_modules 中引入的模块指定主入口文件。

    bin

    许多包有一个或多个可执行文件希望被安装到系统路径。提供一个bin字段,它是一个命令名和本地文件名的映射。在安装时,如果是全局安装,npm将会使用符号链接把这些文件链接到prefix/bin,如果是本地安装,会链接到 ./node_modules/.bin/。

    比如,要使用myapp作为命令时可以这么做:

    { "bin" : { "myapp" : "./cli.js" } }

    当安装完毕myapp,npm会从cli.js文件创建一个到/usr/local/bin/myapp的符号链接(这使你可以直接在命令行执行myapp)。

    man

    指定一个单一的文件名或一个文件名数组来让man程序使用。如果只给man字段提供一个文件,则安装完毕后,它就是 man 的结果,这和此文件名无关。

    directories

    CommonJS Packages 规范说明了几种你可以用 directories 对象来标示你的包结构的方法(lib、bin、man、doc、example)。

    repository

    指明你的代码被托管在何处,这对那些想要参与到这个项目中的人来说很有帮助。如果 git 仓库在 github 上,用 npm docs 命令将会找到你。

    scripts

    scripts 字段是一个由脚本命令组成的字典,这些命令运行在包的各个生命周期中。这里的键是生命周期事件名,值是要运行的命令。

    config

    config 字段是一个对象,可以用来配置包脚本中的跨版本参数。

    dependencies

    dependencies 字段是一个对象,它指定了依赖的包名和其版本范围的映射。版本范围是个有一个或多个空白分隔描述符的字符串。dependencies 字段还可以用 tarball 或者 git URL。

    (请不要将测试或过渡性的依赖放到 dependencies 中)

    devDependencies

    如果有人计划在他们的项目中下载和使用你的模块,但他们可能并不想或并不需要你开发所使用的外部测试和文档框架。 在这种情况下,最好将这些附加的项放在 devDependencies 中。即开发模式下的依赖。

    peerDependencies

    在某些情况下,当一个主机无法 require 依赖包时,你会想要告诉它还有哪些工具或库与这个依赖包兼容。这通常被成为一个插件。尤其是在 host 文档中声明的模块会暴露一个特定的接口。

    bundledDependencies

    在发布包时,包名的数组会被打包进去。

    optionalDependencies

    如果一个依赖项可用,但希望在这个依赖项无法被找到或者安装时失败npm还能继续处理(不中断),那么你可以把它放在 optionalDependencies中。和 dependencies 一样,optionalDependencies 是一个包名和版本号或 url 的映射。区别在于 optionalDependencies 中的依赖构建失败时不会导致 npm 整体安装失败。

    engines

    你可以指定node的工作版本:

    { "engines": { "node": ">=0.10.3 <0.12" } }

    os

    可以指定模块运行的操作系统:"os" : [ "darwin", "linux" ] 也可以使用操作系统黑名单来替代白名单,只要在前面加个’!’:

    { "os": [ "!win32" ] }

    cpu

    指明只能运行在特定的 cpu 架构上

    preferGlobal

    如果你的包是一个需要进行全局安装的命令行应用,需要设置 preferGlobal为true,如果这个包被本地安装会报出一个警告。 这个选项并不会阻止用户本地安装这个包,但这么做确实能在包未按照预期被安装造成诸多麻烦时提供一些提示。

    private

    如果你在包的 package.json 中设置” private": true “,则 npm 会拒绝发布它。这是防止私有包被以外发布的一种方法。

    publishConfig

    这是一个在 publish-time 时会用到的配置集合。当你想设置 tag、registry 或] access 时特别有用,所以你可以确保一个给定的包无法在没有被打上"latest"标记时就被发布到全局公共的registry。 任何配置都可以被覆盖,当然可能只有"tag", "registry" 和 "access" 和发布意图有关。

  • 【NPM】使用指南

    查看本机镜像地址

    npm config get registry

    如果是默认源或者淘宝镜像切换成私服地址

    • 默认镜像:https://registry.npmjs.org
    • 淘宝镜像:http://registry.npm.taobao.org
    • 私服地址:http://xxxx

    修改镜像地址

    npm config set registry http://xxxx

    (npm 私服下 有hosted(私有仓库,登录上传都是使用此仓库) proxy(代理仓库去下载第三方依赖) group(对外暴露的仓库地址,配置镜像地址) 登录都是登录hosted,镜像地址都是group的) package.json文件内配置镜像地址

    {
        "publishConfig": {
            "registry": "http://xxxx"
        }
    }

    到项目目录下登录镜像

    npm login

    输入账号密码(如果指定全局镜像为私服可以不加 –registry)或

    npm login  --registry=http://xxxx(指定要登录镜像地址)

    查看登录用户

    npm whoami

    推送镜像(注意:上传的包名 package.json 中name不能有大写空格和下划线)

    npm publish

    (如果指定全局镜像为私服可以不加 –registry)或

    npm publish  --registry=http://xxxx
    更新包
    • 需要将package.json的version版本号进行更新(1.0.0->1.0.1)
    • 忽略上传文件,可在gitignore文件中添加忽略文件
    • 使用下载依赖包,在新的项目中添加依赖名称和版本号 进行npm install 如下载失败请查看镜像地址是否正确
    • 异常情况
    Code 描述
    400 可能登录地址不对,可能私服已经存在此版本
    403 可能未登录,或者账户没有权限
    401 私服仓库可能权限不够npm Bearer Token Realm 可能未激活
  • 【JS】判断登录设备是移动端还是PC端

    基于 navigator.userAgent 的 User Agent 检测

    function isMobileDevice () {
      const ua = navigator.userAgent || navigator.vendor || window.opera;
      const mobileRegex = /android|iphone|ipad|ipod|blackberry|iemobile|opera mini|mobile|windows phone|phone|webos|kindle|tablet/i;
      return mobileRegex.test(ua.toLowerCase());
    }

    通过 navigator.userAgent 获取浏览器标识字符串‌。正则表达式匹配移动端关键词(如 android、iphone、mobile 等)‌。返回 true 表示移动端,false 表示 PC 端。

    ‌基于 navigator.userAgent 的插件方案‌

    插件:mobile-detect.js

    插件通过解析 navigator.userAgent 中的设备标识符(如 Android、iPhone、Windows 等)实现设备判断‌。 支持更细分的设备类型检测(如平板、手机、PC)‌。

    import MobileDetect from 'mobile-detect';
    
    const md = new MobileDetect(navigator.userAgent);
    
    if (md.mobile()) {
      console.log("移动端登录设备(手机/平板)");
    } else if (md.tablet()) {
      console.log("平板设备");
    } else {
      console.log("PC 端设备");
    }
  • 【Nginx】学习笔记

    常用命令

    • 检查配置文件正确性

      nginx -t
    • 重启服务

      sudo nginx -s reload
    • 停止服务

      sudo nginx -s quit|stop
    • 启动服务

      sudo nginx
    • 查看进程

      ps aux | grep nginx

    其它

    • 查找 nginx.conf 的位置

      find / -name nginx.conf
    • 指定启动配置文件

      sudo nginx -c /usr/local/nginx/conf/nginx.conf
    user root owner; # 运行时的用户名
    worker_processes 1; # 运行时的进程数
    error_log /var/log/nginx/error.log; # 错误日志存放位置
    pid /run/nginx.pid; # 设置 nginx 的 master 进程 ID 写入的位置
    events {
        worker_connections 1024; # 设置每个 woker 进程同时能为多少个连接提供服务
    }
    http {
        include mime.types; # 把 mime.types 这个文件的内容加载进来
        access_log /var/log/nginx/access.log  main; # 指令设置了访问的日志存储的位置
        index index.html index.htm; # 设置了当请求的地址里不包含特定的文件的时候,默认打开的文件
        server {
            server_name hezhiyi.com; # 创建基于主机名的虚拟主机
            root "/Users/GZZHIYI/Documents/web"; # 配置虚拟主机的根目录 
            location / { ... }; # 配置 nginx 怎么样响应请求的资源
        }
    }
  • 【微信小程序】学习笔记(持续更新)

    微信小程序的框架主要包括以下几个核心部分:

    1. WXML(WeiXin Markup Language)

    • 作用:用于描述小程序的结构,类似于HTML。
    • 特点:支持数据绑定、条件渲染、列表渲染等功能。

    2. WXSS(WeiXin Style Sheets)

    • 作用:用于描述小程序的样式,类似于CSS。
    • 特点:支持大部分CSS特性,并扩展了尺寸单位(如rpx)以适应不同屏幕。

    3. JavaScript

    • 作用:用于处理小程序的逻辑。
    • 特点:支持ES6语法,提供丰富的API,如网络请求、数据存储、设备信息等。

    4. WXS(WeiXin Script)

    • 作用:一种脚本语言,可以在WXML中直接使用。
    • 特点:类似于JavaScript,但运行在视图层,适合处理一些简单的逻辑。

    5. JSON

    • 作用:用于配置小程序的页面、窗口表现、网络超时时间等。
    • 特点:简洁易读,支持注释(但在实际使用中需去除注释)。

    6. 小程序框架API

    • 作用:提供丰富的API,帮助开发者实现各种功能。
    • 分类
      • 网络API:如wx.requestwx.uploadFile等。
      • 媒体API:如wx.chooseImagewx.playVoice等。
      • 数据缓存API:如wx.setStoragewx.getStorage等。
      • 位置API:如wx.getLocationwx.openLocation等。
      • 设备API:如wx.getSystemInfowx.getNetworkType等。
      • 界面API:如wx.showToastwx.showModal等。

    7. 小程序生命周期

    • 作用:管理小程序的启动、运行、销毁等过程。
    • 主要生命周期函数
      • onLaunch:小程序初始化时触发。
      • onShow:小程序启动或从后台进入前台时触发。
      • onHide:小程序从前台进入后台时触发。
      • onError:小程序发生脚本错误时触发。

    8. 页面生命周期

    • 作用:管理页面的加载、显示、隐藏、卸载等过程。
    • 主要生命周期函数
      • onLoad:页面加载时触发。
      • onShow:页面显示时触发。
      • onReady:页面初次渲染完成时触发。
      • onHide:页面隐藏时触发。
      • onUnload:页面卸载时触发。

    9. 组件

    • 作用:提供丰富的UI组件,帮助开发者快速构建界面。
    • 常见组件
      • 基础组件:如viewtextimagebutton等。
      • 表单组件:如inputpickerslider等。
      • 导航组件:如navigator
      • 媒体组件:如videoaudio等。
      • 地图组件:如map
      • 画布组件:如canvas

    10. 自定义组件

    • 作用:允许开发者封装可复用的UI组件。
    • 特点:支持组件间的通信、生命周期管理、样式隔离等。

    11. 事件系统

    • 作用:用于处理用户交互事件。
    • 常见事件
      • 触摸事件:如bindtapbindlongpress等。
      • 表单事件:如bindinputbindchange等。
      • 滚动事件:如bindscroll等。

    12. 路由

    • 作用:管理页面之间的跳转。
    • 常见API
      • wx.navigateTo:保留当前页面,跳转到新页面。
      • wx.redirectTo:关闭当前页面,跳转到新页面。
      • wx.navigateBack:返回上一个页面。
      • wx.switchTab:跳转到tabBar页面。

    13. 数据绑定

    • 作用:将数据与视图进行绑定,实现数据的动态更新。
    • 特点:支持单向数据流,数据变化会自动更新视图。

    14. 模块化

    • 作用:支持将代码拆分为多个模块,便于管理和复用。
    • 特点:支持CommonJS模块化规范,使用require引入模块。

    15. 云开发

    • 作用:提供云端一体化的开发能力,包括数据库、存储、云函数等。
    • 特点:无需搭建服务器,开发者可以直接使用云端资源。

    16. 插件

    • 作用:允许开发者使用第三方插件,扩展小程序的功能。
    • 特点:插件可以独立开发、发布,供其他小程序使用。

    17. 分包加载

    • 作用:将小程序代码拆分为多个包,按需加载,减少首次启动时间。
    • 特点:支持主包和多个分包,分包可以独立加载。

    18. 性能优化

    • 作用:提升小程序的运行效率和用户体验。
    • 常见优化手段
      • 减少setData调用:避免频繁更新视图。
      • 使用自定义组件:提高代码复用性和维护性。
      • 图片优化:压缩图片,使用合适的图片格式。
      • 分包加载:减少首次启动时的代码量。

    19. 安全

    • 作用:保障小程序的安全运行。
    • 常见安全措施
      • 数据加密:对敏感数据进行加密存储。
      • 权限控制:限制API的调用权限。
      • 代码混淆:防止代码被反编译。

    20. 调试工具

    • 作用:帮助开发者调试小程序。
    • 特点:提供实时预览、代码调试、性能分析等功能。
  • 【Webpack】学习笔记

    构建作用

    构建工具就是将源代码转换成可执行的 JavaScript、CSS、HTML 代码,包括以下内容:

    • 代码转换:将 TypeScript 编译成 JavaScript、将 SCSS 编译成 CSS 等;
    • 文件优化:压缩 JavaScript、CSS、HTML 代码,压缩合并图片等;
    • 代码分割:提取多个页面的公共代码,提取首屏不需要执行部分的代码,让其异步加载;
    • 模块合并:在采用模块化的项目里会有很多个模块和文件,需要通过构建功能将模块分类合并成一个文件;
    • 自动刷新:监听本地源代码的变化,自动重新构建、刷新浏览器;
    • 代码校验:在代码被提交到仓库前需要校验代码是否符合规范,以及单元测试是否通过;
    • 自动发布:更新代码后,自动构建出线上发布代码并传输给发布系统。

    基本概念

    • Entry:入口,Webpack 执行构建的第一步将从 Entry 开始,可抽象成输入。

    • Module:模块,在 Webpack 里一切皆模块,一个模块对应着一个文件。Webpack 会从配置的 Entry 开始递归找出所有依赖的模块。

    • Chunk:代码块,一个 Chunk 由多个模块组合而成,用于代码合并与分割。

    • Loader:模块转换器,用于把模块原内容按照需求转换成新内容。

    • Plugin:扩展插件,在 Webpack 构建流程中的特定时机会广播出对应的事件,插件可以监听这些事件的发生,在特定时机做对应的事情。

    • module,chunk 和 bundle 其实就是同一份逻辑代码在不同转换场景下的取了三个名字:我们直接写出来的是 module,webpack 处理时是 chunk,最后生成浏览器可以直接运行的 bundle。

    • filename 指列在 entry 中,打包后输出的文件的名称;

    • chunkFilename 指未列在 entry 中,却又需要被打包出来的文件的名称。

    • webpackChunkName 是为预加载的文件取别名,

    • webpackPrefetch 会在浏览器闲置下载文件,

    • webpackPreload 会在父 chunk 加载时并行下载文件。

    • hash 计算与整个项目的构建相关;

    • chunkhash 计算与同一 chunk 内容相关;

    • contenthash 计算与文件内容本身相关。(注:chunkhash, contenthash不能同时和HMR使用)

    • source-map 大而全,啥都有,就因为啥都有可能会让 webpack 构建时间变长,看情况使用;

    • cheap-module-eval-source-map 这个一般是开发环境(dev)推荐使用,在构建速度报错提醒上做了比较好的均衡;

    • cheap-module-source-map 一般来说,生产环境是不配 source-map 的,如果想捕捉线上的代码报错,我们可以用这个。

    流程概括

    Webpack 的运行流程是一个串行的过程,从启动到结束会依次执行以下流程:

    1. 初始化参数:从配置文件和 Shell 语句中读取与合并参数,得出最终的参数;
    2. 开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的 run 方法开始执行编译;
    3. 确定入口:根据配置中的 entry 找出所有的入口文件;
    4. 编译模块:从入口文件出发,调用所有配置的 Loader 对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理;
    5. 完成模块编译:在经过第4步使用 Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系;
    6. 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会;
    7. 输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统。

    在以上过程中,Webpack 会在特定的时间点广播特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,并且插件可以调用 Webpack 提供的 API 改变 Webpack 的运行结果。

    流程细节

    Webpack 的构建流程可以分为以下三大阶段:

    1. 初始化:启动构建,读取与合并配置参数,加载 Plugin,实例化 Compiler。
    2. 编译:从 Entry 发出,针对每个 Module 串行调用对应的 Loader 去翻译文件内容,再找到该 Module 依赖的 Module,递归地进行编译处理。
    3. 输出:对编译后的 Module 组合成 Chunk,把 Chunk 转换成文件,输出到文件系统。

    关键的配置

    • context:上下文。
    • entry:入口文件,是所有依赖关系的入口,webpack 从这个入口开始静态解析,分析模块之间的依赖关系。
    • output:打包输出的配置。
    • devtools:SourceMap 选项,便于开发模式下调试。
    • watch:监听模式,增量更新,开发必备!
    • profile:优化。
    • cache:webpack构建的过程中会生成很多临时的文件,打开 cache 可以让这些临时的文件缓存起来,从而更快的构建。
    • module.loaders:如前文介绍,loaders 用来对文件做预处理。这样 webpack 就可以打包任何静态文件。
    • resolve.alias:模块别名,这样可以更方便的引用模块。
    • plugins:如前文介绍,webpack 的一些内置功能均是以插件的形式提供。
  • 前端知识点汇总(持续更新)

    HTML5:

    新增标签元素

    header, footer, aside, nav, section, canvas, video, audio

    新增 Input 类型

    date, datetime, email, number, range, tel, color

    本地存储

    生命周期

    • cookie:可设置过期时间
    • localStorage:永久存储
    • sessionStorage:关闭标签页自动清除

    存储大小

    • cookie:4KB
    • sessionStorage:5MB – 10MB
    • localStorage:5MB – 10MB

    作用域

    • cookie:可设置 Domain 和 Path,控制哪些域名和路径可以访问
    • localStorage:同源策略下的所有窗口和标签页共享
    • sessionStorage:仅当前标签页有效,即使同源的其他标签页也无法访问

    <script> 加载方式

    • 默认同步阻塞 HTML 解析
    • defer 延迟执行直至DOM解析完后
    • async 异步引入,下载完成后立即执行

    CSS3:

    新增属性

    • 边框:border-radius, box-shadow, border-image
    • 背景:background-size, background-origin
    • 文字:text-shadow
    • transfrom:translate, rotate, scale, skew, matrix

    自定义字体:@font-face

    动画

    rgba 颜色 / 线性渐变
    .test {
      background-color: rgba(0, 0, 0, 0.5);
        background: linear-gradient(to bottom, rgba(255, 255, 255, 0), rgba(255, 255, 255, 1));
    }

    flex 布局

    媒体查询

    命名规范

    BEM

    JS:

    小数精度处理

    • 使用 toFixed 取后几位小数
    • 把小数转为整数再进行运算
    • 使用精度运算库,如:big.js

    for…infor…of 的区别

    • for-in 历遍对象,通常获取 key(类似 Object.keys)
    • for-of 历遍可迭代对象,如 ArrayMapSet

    任务队列(Task Queue)

    • 先执行同步再执行异步
    • 核心作用:处理异步代码的调度和执行
    • 宏任务:setTimeoutsetIntervalI/O
    • 微任务:Promise 回调(.then / .catch/ .finally)、MutationObserver 回调等
    • 微任务优先级高于宏任务
    • 调用 fetch 会同步执行并立即返回一个 promise

    call | apply | bind

    均用于改变函数内部 this 的指向

    const obj = { name: "Alice" };
    
    function greet() {
      console.log(`Hello, ${this.name}!`);
    }
    
    greet.call(obj);      // Hello, Alice!
    greet.apply(obj);     // Hello, Alice!
    const boundGreet = greet.bind(obj);
    boundGreet();         // Hello, Alice!

    ES:

    有哪些新特性?

    变量声明

    letconst

    箭头函数

    简化函数语法,自动绑定 this

    模板字符串

    `Hello ${name}`

    解构赋值

    const { age, name } = user;
    const [first, second] = [1, 2];

    默认参数

    扩展运算符

    const arr1 = [1, 2];
    const arr2 = [...arr1, 3]; // [1, 2, 3]; // 合并数组
    const objCopy = { ...originalObj }; // 合并对象

    Promise 和 异步处理

    Promise.all – 等待所有 Promise 对象都执行完成 Promise.race – 返回第一个完成的 Promise(无论成功失败) Promise.any – 返回第一个成功的 Promise

    模块化:importexport

    Set, Map

    let s = new Set(); s.add(‘a’).add(‘b’)
    let m = new Map(); m.set(’age’, 16)

    数组的 includes,检查是否包含某元素

    async / await

    Generator 函数的语法糖,省去手动 next() 的步骤

    Object.values() 和 Object.entries()

    Object.values({ a: 1, b: 2 }); // [1, 2]
    Object.entries({ a: 1, b: 2 }); // [["a", 1], ["b", 2]]

    字符串填充:padStart() 和 padEnd()

    "5".padStart(2, "0"); // "05"

    空值合并运算符

    const value = input ?? "default";

    动态导入模块

    const module = await import('./module.js')

    replaceAll 替换所有匹配的子串

    "a.b.c".replaceAll(".", "-"); // "a-b-c"

    require 和 import

    • 分别属于 CommonJS 和 ES 两种不同模块系统
    • require 动态加载,运行时解析
    • import 静态加载,编译时解析
    • Proxy
      • 数据绑定与响应式系统:通过 set 拦截属性赋值,触发副作用(如重新渲染)
      • 属性访问控制和校验:限制对象属性的访问或赋值

    微信小程序:

    OpenID & UnionID

    OpenID

    • 用户在当前小程序中的唯一标识
    • 用途:用于识别用户在当前小程序内的身份(如用户数据存储、业务逻辑处理)
    • 获取:通过 wx.login() 获取 code,后端用 code 调用微信接口换取 OpenID

    UnionID

    • 用户在微信的唯一标识
    • 用途:实现跨小程序、公众号用户身份统一
    • 获取:通过 wx.getUserInfo() 获取 encryptedData, iv,发送到后端解密,或者通过按钮触发授权

    性能优化:

    • 文本压缩(css, js, html)
    • 图片压缩
    • 合并资源(合并文本、雪碧图)
    • 图片懒加载
    • 合并请求
    • 缓存资源(设置浏览器头、设置 html head)
    • 使用 CDN
    • gzip 压缩
    • 减少 DOM 操作
    • CSS 样式置顶、JS 脚本置底
    • 防抖和节流
      • 防抖:保证N秒内执行一次,如果N秒内触发将再执行并重新计算时间
      • 节流:保证N秒内只能触发一次