《TypeScript 面试八股:高频考点与核心知识点详解》

“你好啊!能把那天没唱的歌再唱给我听吗? ”
前言
因为主包还是主要学习js,ts浅浅的学习了一下,在简历中我也只会写了解,所以我写一些比较基础的八股,如果是想要更深入的八股的话还是建议找别人的。
Ts基础
为社么要使用ts?ts相对于js的优势在哪?
TypeScript是JS的超集,包括所有的JS规范版本。同时拥有强大的类型系统,包括泛型。是一个面向对象的语言,提供类,接口和模块。
TS对JS的改进主要是静态类型检查(强类型语言)“静态类型更有利于构建大型应用”。 同时TS多了接口,泛型这些JS所没有的特性,内置的数据类型也比较多。
TypeScript的内置数据类型有哪些
在Typescript中,内置的数据类型也称为原始数据类型。
- boolean(布尔类型)
- number(数字类型)
- string(字符串类型)
- void 类型
- null 和 undefined 类型
- array(数组类型)
- tuple(元组类型):允许表示一个已知元素数量和类型的数组,各元素的类型不必相同
- enum(枚举类型):
enum类型是对JavaScript标准数据类型的一个补充,使用枚举类型可以为一组数值赋予友好的名字 - any(任意类型)
- never 类型
- object 对象类型
TypeScript 中 const 和 readonly 的区别?
const可以防止变量的值被修改,在运行时检查,使用const变量保存的数组,可以使用push,pop等方法。
readonly可以防止变量的属性被修改,在编译时检查,使用Readonly Array声明的数组不能使用push,pop等方法
TypeScript 中 any 类型的作用是什么?
为编程阶段还不清楚类型的变量指定一个类型。 这些值可能来自于动态的内容,比如来自用户输入或第三方代码库(不确定用户输入值的类型,第三方代码库是如何工作的)。 这种情况下,我们不希望类型检查器对这些值进行检查而是直接让它们通过编译阶段的检查。使用any就失去了ts带来的类型检查。
any的问题
- 类型污染:any
类型的对象会导致后续的属性类型都会变成any - 使用不存在的属性或方法而不报错
TypeScript 中 any、never、unknown、null & undefined 和 void 有什么区别?
any: 动态的变量类型(失去了类型检查的作用)。never: 永不存在的值的类型。例如:never 类型是那些总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的返回值类型。unknown: 任何类型的值都可以赋给 unknown 类型,但是 unknown 类型的值只能赋给 unknown 本身和 any 类型。null & undefined: 默认情况下 null 和 undefined 是所有类型的子类型。 就是说你可以把 null 和 undefined 赋值给 number 类型的变量。当你指定了 --strictNullChecks 标记,null 和 undefined 只能赋值给 void 和它们各自。void: 没有任何类型。例如:一个函数如果没有返回值,那么返回值可以定义为void。
TS中any和unknown有什么区别?
unknown 和 any 的主要区别是 unknown 类型会更加严格:在对 unknown 类型的值执行大多数操作之前,我们必须进行某种形式的检查。而在对 any 类型的值执行操作之前,我们不必进行任何检查。
any 和 unknown 都是顶级类型,但是 unknown 更加严格,不像 any 那样不做类型检查,反而 unknown 因为未知性质,不允许访问属性,不允许赋值给其他有明确类型的变量。
我在之前的博客中提到了:unkonw因为我们不知道他里面是什么,所以我们不能对他进行任何操作。
解释一下TypeScript中的枚举
枚举就是一个对象的所有可能取值的集合(和数学中的思想一样);
enum Day {SUNDAY, MONDAY,TUESDAY, WEDNESDAY,THURSDAY,FRIDAY,SATURDAY}
TypeScript 中如何联合枚举类型的 Key?————用下标
enum Status {xiaoming, xiaohong, xiaogang,}
console.log(Status.xiaoming,Status[0]);console.log(Status.xiaohong,Status[1]);console.log(Status.xiaogang,Status[2]);//输出: 0 xiaoming// 1 xiaohong// 2 xiaogang
keyof 和 typeof 关键字的作用?
keyof 关键字
keyof 用于获取对象类型的键的联合类型。它可以让你从一个对象类型中提取出所有键的名称,并将它们组合成一个联合类型。
interface Person {name: string;age: number;address: string;
}type PersonKeys = keyof Person; // "name" | "age" | "address"function getProperty(obj: Person, key: PersonKeys) {return obj[key];
}const person: Person = {name: "Alice",age: 30,address: "123 Main St"
};console.log(getProperty(person, "name")); // 输出: Alice
console.log(getProperty(person, "age")); // 输出: 30
typeof 关键字
typeof 用于获取变量或表达式的类型。它可以让你在类型上下文中引用一个变量的类型。
const person = {name: "Alice",age: 30,address: "123 Main St"
};type PersonType = typeof person;
// PersonType 的类型为:
// {
// name: string;
// age: number;
// address: string;
// }function printPerson(p: PersonType) {console.log(p.name, p.age, p.address);
}printPerson(person); // 输出: Alice 30 123 Main St
TS中的泛型是什么
泛型允许我们在编写代码时使用一些以后才指定的类型,在定义函数,接口或者类的时候,不预先定义好具体的类型,而在使用的时候在指定类型的一种特性。
泛型的主要作用是:
- 提高代码的复用性:可以编写适用于多种类型的通用代码。
- 增强类型安全性:通过类型参数,可以在编译时捕获类型错误。
- 减少冗余代码:避免为每种类型编写单独的函数或类。
泛型函数
泛型函数可以接受任意类型的参数,并返回相应类型的值。
function identity<T>(arg: T): T {return arg;
}// 使用泛型函数
let output1 = identity<string>("Hello"); // 类型为 string
let output2 = identity<number>(42); // 类型为 number
泛型接口
泛型接口允许你定义可以适用于多种类型的接口
interface KeyValuePair<K, V> {key: K;value: V;
}// 使用泛型接口
let pair1: KeyValuePair<string, number> = { key: "age", value: 30 };
let pair2: KeyValuePair<number, boolean> = { key: 1, value: true };
泛型类
泛型类允许你创建可以处理多种类型的类。
class Box<T> {private value: T;constructor(value: T) {this.value = value;}getValue(): T {return this.value;}
}// 使用泛型类
let box1 = new Box<string>("Hello"); // 类型为 Box<string>
let box2 = new Box<number>(42); // 类型为 Box<number>
在这个例子中,Box 类可以存储任意类型的值,并通过 getValue 方法返回该值。
any和泛型的区别?
泛型有类型推断,编译器会根据传入的参数自动地帮助我们确定T的类型
any则是不检验
接口和Type
TypeScript 中同名的 interface 或者同名的 interface 和 class 可以合并吗?
同名的interface会自动合并,同名的interface和class会自动聚合。
接口和类型别名的区别?
两者都可以用来描述对象或函数的类型。与接口不同,类型别名还可以用于其他类型,如基本类型(原始值)、联合类型、元组。
TypeScript 中 type 和 interface 的区别?
相同点:
- 都可以描述 '对象' 或者 '函数'
- 都允许拓展(extends):interface 和 type 都可以拓展,并且两者并不是相互独立的,也就是说 interface 可以 extends type, type 也可以 extends interface 。 虽然效果差不多,但是两者语法不同。
不同点:
| 特性 | interface | type |
|---|---|---|
| 扩展方式 | 通过 extends 扩展 | 通过 &(交叉类型)扩展 |
| 声明合并 | 支持 | 不支持 |
| 适用场景 | 对象类型、类的接口 | 任何类型(基本类型、联合类型、元组等) |
| 性能 | 在大型项目中稍好 | 处理复杂类型时可能稍慢 |
| 兼容性 | 支持 implements | 不能直接用于 implements |
| 灵活性 | 较低,只能定义对象或函数类型 | 较高,可以定义任何类型 |
类
TS中什么是方法重载?
方法重载是指在一个类中定义多个同名的方法,但要求每个方法具有不同的参数的类型或参数的个数。 基本上,它在派生类或子类中重新定义了基类方法。
方法覆盖规则:
- 该方法必须与父类中的名称相同。
- 它必须具有与父类相同的参数。
- 必须存在IS-A关系或继承。
TS中的类及其特性
在 TypeScript 中,类(Class) 是面向对象编程(OOP)的核心概念之一。TypeScript 的类不仅支持 ES6 的类特性,还增加了一些额外的功能,如访问修饰符、抽象类、只读属性等。
1. 基本语法
TypeScript 中定义类的语法与 ES6 类似,使用 class 关键字。
class Person {// 属性name: string;age: number;// 构造函数constructor(name: string, age: number) {this.name = name;this.age = age;}// 方法greet() {console.log(`Hello, my name is ${this.name} and I'm ${this.age} years old.`);}
}// 创建类的实例
const person = new Person("Alice", 30);
person.greet(); // 输出: Hello, my name is Alice and I'm 30 years old.
2. 访问修饰符
TypeScript 提供了三种访问修饰符,用于控制类成员的访问权限:
- **
public**(默认):成员可以在任何地方访问。 - **
private**:成员只能在类内部访问。 - **
protected**:成员可以在类内部和子类中访问。
class Person {public name: string; // 默认是 publicprivate age: number; // 只能在类内部访问protected gender: string; // 可以在子类中访问constructor(name: string, age: number, gender: string) {this.name = name;this.age = age;this.gender = gender;}public greet() {console.log(`Hello, my name is ${this.name} and I'm ${this.age} years old.`);}
}class Employee extends Person {constructor(name: string, age: number, gender: string) {super(name, age, gender);console.log(this.gender); // 可以访问 protected 成员// console.log(this.age); // 错误: age 是 private 成员}
}const person = new Person("Alice", 30, "female");
console.log(person.name); // 可以访问 public 成员
// console.log(person.age); // 错误: age 是 private 成员
// console.log(person.gender); // 错误: gender 是 protected 成员
3. 只读属性
使用 readonly 关键字可以将属性标记为只读,只能在构造函数中初始化,之后不可修改。
class Person {readonly name: string;constructor(name: string) {this.name = name;}changeName(newName: string) {// this.name = newName; // 错误: name 是只读属性}
}const person = new Person("Alice");
// person.name = "Bob"; // 错误: name 是只读属性
4. 静态成员
静态成员属于类本身,而不是类的实例。使用 static 关键字定义静态成员。
class MathUtils {static PI = 3.14;static calculateArea(radius: number) {return this.PI * radius * radius;}
}console.log(MathUtils.PI); // 输出: 3.14
console.log(MathUtils.calculateArea(5)); // 输出: 78.5
5. 抽象类
抽象类不能被实例化,只能被继承。它可以包含抽象方法(没有实现的方法)和具体方法。
abstract class Animal {abstract makeSound(): void; // 抽象方法,子类必须实现move() {console.log("Moving...");}
}class Dog extends Animal {makeSound() {console.log("Woof!");}
}const dog = new Dog();
dog.makeSound(); // 输出: Woof!
dog.move(); // 输出: Moving...
// const animal = new Animal(); // 错误: 不能实例化抽象类
6. getter 和 setter
可以使用 get 和 set 关键字定义属性的访问器。
class Person {private _age: number;constructor(age: number) {this._age = age;}get age() {return this._age;}set age(value: number) {if (value >= 0) {this._age = value;} else {throw new Error("Age cannot be negative.");}}
}const person = new Person(30);
console.log(person.age); // 输出: 30
person.age = 25;
console.log(person.age); // 输出: 25
// person.age = -5; // 抛出错误: Age cannot be negative.
7. 类的继承
使用 extends 关键字实现类的继承,子类可以继承父类的属性和方法。
class Animal {constructor(public name: string) {}move(distance: number) {console.log(`${this.name} moved ${distance} meters.`);}
}class Dog extends Animal {bark() {console.log("Woof! Woof!");}
}const dog = new Dog("Buddy");
dog.move(10); // 输出: Buddy moved 10 meters.
dog.bark(); // 输出: Woof! Woof!
8. 方法重写
子类可以重写父类的方法。
class Animal {move() {console.log("Moving...");}
}class Dog extends Animal {move() {console.log("Running...");}
}const dog = new Dog();
dog.move(); // 输出: Running...
9. 构造函数重载
TypeScript 支持构造函数重载,可以根据不同的参数创建对象。
class Point {constructor(public x: number, public y: number);constructor(x: number, y: number, public z: number);constructor(public x: number, public y: number, public z?: number) {// 实现逻辑}
}const point1 = new Point(1, 2);
const point2 = new Point(1, 2, 3);
10. 类与接口
类可以实现接口,接口可以定义类的结构。
interface Animal {name: string;makeSound(): void;
}class Dog implements Animal {constructor(public name: string) {}makeSound() {console.log("Woof!");}
}const dog = new Dog("Buddy");
dog.makeSound(); // 输出: Woof!
TS原理
简单介绍一下 TypeScript 模块的加载机制?
假设有一个导入语句 import { a } from "moduleA";
- 首先,编译器会尝试定位需要导入的模块文件,通过绝对或者相对的路径查找方式;
- 如果上面的解析失败了,没有查找到对应的模块,编译器会尝试定位一个
外部模块声明(.d.ts); - 最后,如果编译器还是不能解析这个模块,则会抛出一个错误
error TS2307: Cannot find module 'moduleA'.
对 TypeScript 类型兼容性的理解?
TypeScript 类型兼容性指的是 TypeScript 中的类型系统能够自动进行类型检查和类型推导,以确保类型的兼容性。具体来说,如果两个类型 A 和 B 满足一定的关系,那么 A 类型的变量或参数可以赋值给 B 类型的变量或参数。
TypeScript 的类型兼容性规则基于结构子类型化的原则,即只要目标类型(被赋值的类型)的成员属性包含来源类型(待赋值的类型)的成员属性,或者来源类型可以转换为目标类型,就认为这两个类型是兼容的。
例如,下面代码中的 a 变量和 b 变量都是 Animal 类型,但是它们的属性不完全相同:
interface Animal {name: string;age: number;
}class Cat implements Animal {name = 'Tom';age = 2;type = 'mammal';
}let a: Animal = { name: 'Kitty', age: 1 };
let b: Animal = new Cat();
尽管 Cat 类型比 Animal 类型具有更多的属性,但是由于其中的属性包含了 Animal 的所有属性,因此 Cat 是兼容于 Animal 的。因此,let b: Animal = new Cat() 是合法的。
在 TypeScript 中,类型兼容性是非常重要的,因为它允许我们编写更加灵活和可复用的代码,同时保证类型的安全性。在使用类型兼容性时,需要注意一些细节,如类型保护等,以确保程序的正确性。
TypeScript 中的 this 和 JavaScript 中的 this 有什么差异?
- TypeScript:noImplicitThis: true 的情况下,必须去声明 this 的类型,才能在函数或者对象中使用this。
- Typescript 中箭头函数的 this 和 ES6 中箭头函数中的 this 是一致的。
tsconfig.json有什么作用?
tsconfig.json文件是JSON格式的文件。
在tsconfig.json文件中,可以指定不同的选项来告诉编译器如何编译当前项目。
相关文章:
《TypeScript 面试八股:高频考点与核心知识点详解》
“你好啊!能把那天没唱的歌再唱给我听吗? ” 前言 因为主包还是主要学习js,ts浅浅的学习了一下,在简历中我也只会写了解,所以我写一些比较基础的八股,如果是想要更深入的八股的话还是建议找别人的。 Ts基…...
Golang os模块功能详解与示例
os 是 Go 语言标准库中与操作系统交互的核心模块,提供了丰富的功能来操作文件系统、进程、环境变量等。下面我将详细介绍 os 模块的主要功能,并提供相应的代码示例。 1. 文件与目录操作 1.1 文件操作 创建文件 package mainimport ("fmt"&…...
SICAR 标准 KUKA 机器人标准功能块说明手册
功能块名称:LSicar_Robot_KUKA_PrD 目录 1. 概述 2. 功能说明 2.1 程序控制 2.2 状态监控 2.3 报警与故障处理 2.4 驱动控制 3. 关键参数说明 4. 操作步骤指南 4.1 初始化配置 4.2 运行控制 4.3 状态监控 5. 常见故障处理 6. 注意事项 附录1:程序段索引 附录…...
linux中如何修改文件的权限和拥有者所属组
目录标题 chmod指令八进制形式权限修改文件拥有者所属组的修改umask有关内容 chmod指令 chmod指令可以用来修改人员的权限其形式如下: u代表的是拥有者,g代表的是所属组,o代表的是其他人,a表示所有人,如果你想增加权…...
掌握Linux项目自动化构建:从零入门make与Makefile
文章目录 前言: 一、初识自动化构建工具1.1 什么是make/Makefile?1.2 快速体验 二、深入理解核心机制2.1 依赖关系与依赖方法2.2 伪目标的妙用2.3 具体语法a.makefile的基本雏形b.makefile推导原则! 三、更加具有通用型的makefile1. 变量定义…...
Jenkins 配置python项目和allure
Jenkins新建项目 新建ry-api-auto-test。 添加项目描述,选择gitee令牌。 源码管理,设置仓库地址和凭证。参考我上一篇文章的链接:配置gitee私人令牌和凭证 构建步骤,因为我Jenkins部署在Windows,因此选择batch。…...
优化 Docker 镜像 技巧
优化 Docker 镜像可以提高构建速度、减少镜像大小、提高安全性和效率。以下是一些优化 Docker 镜像的方法: 使用适当的基础镜像 选择合适的基础镜像可以减小镜像大小,并确保基础镜像的安全性和更新性。Alpine、Ubuntu Minimal 等轻量级基础镜像是常用选…...
从简单场景认识建造者模式
建造者设计模式总的来说常见的形式无非就两种。 一种是具体产物样式多,故通过中间者(指挥者)来统筹决定产生哪种对象(组装电脑,都是电脑,只是参数配置不同)。 一种是构造的可选参数多…...
Maven工具学习使用(四)——仓库
仓库分类 对于Mavne来说,仓库只分为两类:本地仓库和远程仓库。当Maven根据坐标查询寻找构件的时候,它首先会查看本地仓库,如果本地仓库存在此构件,则直接使用;如果本地仓库不存在此构件,或者需要查看是否有更新的构件版本,Maven就会去远程仓库查找,发现需要的构件之后…...
vue3:十一、主页面布局(进入指定菜单页面,默认锁定到左侧菜单)
一、效果 直接进入home页面,直接展开对应的菜单项 二、具体实现 1、菜单容器增加默认选中变量 在菜单容器中将默认展开菜单default-openeds修改为默认选中菜单default-active 2、引入useRoute方法 引入该方法为了获取当前页面的路径 import { useRoute } from …...
linux,防火墙,firewall,常用命令
文章目录 1. 查看防火墙状态2. 查看当前开放的端口和服务查看所有开放的端口查看所有允许的服务查看所有区域的详细信息 3. 开放指定端口开放端口(临时生效)开放端口(永久生效)开放指定端口范围 4. 删除指定端口删除端口ÿ…...
SQL 函数
SQL 函数 概述 SQL 函数是数据库查询语言(Structured Query Language)的核心组成部分之一。它们是用于执行特定任务的预定义过程,可以在查询中使用以增强查询的灵活性和功能性。SQL 函数可以分为两大类:内置函数和用户自定义函数…...
【蓝桥杯】每日练习 Day13
前言 今天做了不少题,但是感觉都太水了,深思熟虑之下主播决定拿出两道相对不那么水的题来说一下(其实还是很水)。 两道问题,一道是日期问题(模拟),一道是区间合并问题。 日期差值 …...
【Docker系列七】Docker Compose 命令详解
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...
【AI学习】Transformer 模型
1,概念 是一种基于自注意力机制(Self-Attention Mechanism)的深度学习架构,在自然语言处理、计算机视觉等多个领域都有着极为重要的应用。 2,基本结构 1)编码器(Encoder) 通常由多个相同的编码器层堆叠而成。 每个编码器层包含了多头自注意力机制、前馈神经网络以及…...
大数据学习栈记——HBase操作(shell java)
本文介绍HBase在shell终端的常见操作以及如何利用java api操作HBase,操作系统:Ubuntu24.04 参考: https://blog.51cto.com/u_16099228/8016429 https://blog.csdn.net/m0_37739193/article/details/73618899 https://cloud.tencent.com/d…...
React多层级对象改变值--immer
reduxjs/toolkit底层就是immer,,,所以在使用redux的时候,直接赋值,就会响应式的数据 如果不使用reduxjs/toolkit,可以自己使用immer来实现 安装immer npm install immer引入produce函数,,prod…...
服务器硬盘爆满100%问题解决
问题 在工作中遇到一个服务器,服务器硬盘100%,查找哪个目录文件中占用大量空间。发现加起来才150G,硬盘空间大概有500G。 处理问题,排查是否有某个进程正在删除文件,进程卡住了,所以过滤一下有哪些进程&am…...
智能制造:物联网和自动化之间的关系
工业自动化 工业自动化是机器设备或生产过程在不需要人工直接干预的情况下按预期的目标实现测量、操纵等信息处理和过程控制的统称。 在传统的工业生产过程中,很多环节需要人工操作,比如设备调试、生产监控、质量检测等。然而,随着工业自动化…...
Axure项目实战:智慧城市APP(三)教育查询(显示与隐藏交互)
亲爱的小伙伴,在您浏览之前,烦请关注一下,在此深表感谢! 课程主题:教育查询 主要内容:教育公告信息,小升初、初升高、高考成绩查询;教育公告信息为传统的信息页面,小升…...
01 设计模式和设计原则
类设计原则: 单一职责原则(Single Responsibility Principle,SRP):实现类要职责单一开闭原则(Open Close Principle,OCP):对扩展开放,对修改关闭里氏替换原则…...
Github 2025-03-23 php开源项目日报Top10
根据Github Trendings的统计,今日(2025-03-23统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量PHP项目10TypeScript项目1JavaScript项目1Shell项目1Laravel: 以优雅语法简化Web开发 创建周期:4028 天开发语言:PHP协议类型:MIT LicenseSt…...
macbook电脑如何清理键盘防止误触
M1芯片的MacBook电脑关机后按任意键开机,是苹果的功能设计。这样设计的目的是为了方便用户,让用户在想要使用电脑时能快速开机。但是清理电脑键盘的时候却成为了一种苦恼 以下是一些清理 MacBook 键盘防止误触的方法: 使用工具锁定键盘 Cle…...
AIMB-ASMB-788B(PPC-MB-620B)RAID驱动安装(笔记版)
创建RAID后安装系统时看不到磁盘信息,以下案例是安装windows10系统时如何安装主板RAID驱动,由于是笔记版不做过多介绍。 RAID驱动链接:https://advdownload.advantech.com.cn/productfile/Downloadfile1/1-2MAHDQD/AIMB-788_788E_RAID_AHCI_…...
深度分页优化思路
深度分页优化思路 思考以下问题 查询以下SQL的流程是怎么样的呢? 为什么只查询10条数据需要7秒? # 查询时间7秒 SELECT * FROM user ORDER BY age LIMIT 1000000, 10问题分析 为什么分页查询随着翻页的深入,会变得越来越慢。 其实࿰…...
K8S学习之基础五十四:jenkins新建测试流水线
jenkins新建测试流水线 新建任务 node(testak) {stage(第1步:从gitee上下载源代码) {git url: "https://gitee.com/akang007/jenkins-sample"script {build_tag sh(returnStdout: true, script: git rev-parse --short HEAD).trim()}}stage(第2步:基…...
HarmonyOS NEXT(九) :图形渲染体系
HarmonyOS NEXT(九) :图形渲染体系 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,可以分享一下给大家。点击跳转到网站。 https://www.captainbed.cn/ccc 文章目录 HarmonyOS NEXT࿰…...
SQLAlchemy关键词搜索技术深度解析:从基础过滤到全文检索
在数据驱动的应用开发中,基于关键词的模糊查询是常见的业务需求。SQLAlchemy作为Python生态中最流行的ORM框架,提供了多种实现关键词搜索的技术方案。本文将从性能、适用场景和技术复杂度三个维度,系统对比分析SQLAlchemy中关键词搜索的最佳实…...
ES数据过多,索引拆分
公司企微聊天数据存储在 ES 中,虽然按照企业分储在不同的ES 索引中,但某些常用的企微主体使用量还是很大。4年中一个索引存储数据已经达到46多亿条数据,占用存储3.1tb, ES 配置 由于多一个副本,存储得翻倍,成本考虑…...
Rust 与 FFmpeg 实现视频水印添加:技术解析与应用实践
引言 在短视频、直播、影视制作等领域,视频水印是一种常见的工具,用于保护版权、提升品牌辨识度或满足合规性要求。然而,开发者在实现水印添加时往往面临以下挑战: 手动处理效率低:使用图像编辑软件(如 P…...
