3_TypeScript 运算符 --[深入浅出 TypeScript 测试]

TypeScript 支持所有 JavaScript 的运算符,并且由于其静态类型系统,还提供了一些额外的功能和改进。以下是 TypeScript 中常见的运算符分类及其用法:

1. 算术运算符(Arithmetic Operators)

用于执行数学计算。

  • + 加法
  • - 减法
  • * 乘法
  • / 除法
  • % 取模(余数)
  • ** 幂运算
typescript 复制代码
let sum = 5 + 3; // 加法
let difference = 10 - 2; // 减法
let product = 4 * 6; // 乘法
let quotient = 8 / 4; // 除法
let remainder = 9 % 4; // 取模
let power = 2 ** 3; // 幂运算

在 TypeScript 中,算术运算符用于执行基本的数学计算。这些运算符与 JavaScript 中的算术运算符相同,并且可以在数值类型(number)上操作。以下是 TypeScript 支持的所有算术运算符及其用法:

1. 加法 (+)

加法运算符用于将两个数相加。它也可以用于字符串拼接。

typescript 复制代码
let sum = 5 + 3; // 结果为 8
let greeting = "Hello, " + "world!"; // 结果为 "Hello, world!"

2. 减法 (-)

减法运算符用于从一个数中减去另一个数。

typescript 复制代码
let difference = 10 - 4; // 结果为 6

3. 乘法 (*)

乘法运算符用于将两个数相乘。

typescript 复制代码
let product = 7 * 6; // 结果为 42

4. 除法 (/)

除法运算符用于将一个数除以另一个数。注意,结果可能是浮点数。

typescript 复制代码
let quotient = 8 / 4; // 结果为 2
let divisionResult = 9 / 2; // 结果为 4.5

5. 取模 (%)

取模运算符返回两数相除后的余数。这对于检查奇偶性或循环非常有用。

typescript 复制代码
let remainder = 10 % 3; // 结果为 1

6. 幂运算 (**)

幂运算符用于计算一个数的指数次方。

typescript 复制代码
let power = 2 ** 3; // 结果为 8 (2 的 3 次方)

7. 自增 (++) 和自减 (--)

自增和自减运算符分别用于将变量的值增加或减少 1。它们可以出现在变量之前(前缀形式)或之后(后缀形式),这会影响表达式的求值顺序。

  • 前缀形式:先进行自增/自减运算,然后使用更新后的值。
  • 后缀形式:先使用当前值,然后再进行自增/自减运算。
typescript 复制代码
let counter = 1;
counter++; // 后缀形式,先使用 counter 的原始值,然后自增
console.log(counter); // 输出 2

++counter; // 前缀形式,先自增,然后使用新的值
console.log(counter); // 输出 3

示例代码

下面是一些综合使用上述算术运算符的例子:

typescript 复制代码
function calculate() {
    let a = 10;
    let b = 3;

    console.log(`a + b = ${a + b}`); // 加法
    console.log(`a - b = ${a - b}`); // 减法
    console.log(`a * b = ${a * b}`); // 乘法
    console.log(`a / b = ${a / b}`); // 除法
    console.log(`a % b = ${a % b}`); // 取模
    console.log(`a ** b = ${a ** b}`); // 幂运算

    a++;
    console.log(`After incrementing a: ${a}`); // 自增
}

calculate();

注意事项

  • 算术运算符主要用于 number 类型的数据。如果尝试对非数字类型的值使用算术运算符,TypeScript 编译器可能会抛出类型错误,除非你明确地进行了类型转换。
  • 对于字符串,+ 运算符用于连接字符串,而不是执行数学加法。
  • 在进行除法时要注意可能产生的浮点数结果,因为这可能导致精度问题。

通过熟练掌握这些算术运算符,你可以更高效地处理数值数据,在 TypeScript 中构建复杂的数学逻辑和算法。

2. 赋值运算符(Assignment Operators)

用于给变量赋值。

  • = 简单赋值
  • +=, -=, *=, /=, %=, **= 复合赋值
typescript 复制代码
let x = 10;
x += 5; // 相当于 x = x + 5;

赋值运算符在 TypeScript 中用于将一个值赋予变量。除了简单的赋值操作外,TypeScript(以及 JavaScript)还提供了一组复合赋值运算符,它们可以简化某些常见的编程模式。以下是 TypeScript 中支持的赋值运算符及其用法:

1. 简单赋值 (=)

最基础的赋值运算符,用于直接给变量赋值。

typescript 复制代码
let x: number;
x = 10; // 将 10 赋值给变量 x

2. 复合赋值运算符

复合赋值运算符结合了算术、位运算或字符串连接运算与赋值操作,使得代码更加简洁。它们执行相应的运算后,将结果赋值给左边的操作数。

算术复合赋值运算符
  • +=:加法赋值
  • -=:减法赋值
  • *=:乘法赋值
  • /=:除法赋值
  • %=:取模赋值
  • **=:幂赋值
typescript 复制代码
let a = 5;
a += 3; // 等价于 a = a + 3; 结果为 8
a -= 2; // 等价于 a = a - 2; 结果为 6
a *= 4; // 等价于 a = a * 4; 结果为 24
a /= 3; // 等价于 a = a / 3; 结果为 8
a %= 5; // 等价于 a = a % 5; 结果为 3
a **= 2; // 等价于 a = a ** 2; 结果为 9
位运算复合赋值运算符
  • &=:按位与赋值
  • |=:按位或赋值
  • ^=:按位异或赋值
  • <<=:左移赋值
  • >>=:带符号右移赋值
  • >>>=:无符号右移赋值
typescript 复制代码
let b = 5; // 二进制表示为 0101
b &= 3;    // 二进制表示为 0011, 结果为 1 (0101 & 0011 = 0001)
b |= 6;    // 二进制表示为 0110, 结果为 7 (0001 | 0110 = 0111)
b ^= 4;    // 二进制表示为 0100, 结果为 3 (0111 ^ 0100 = 0011)
b <<= 1;   // 左移一位, 结果为 6 (0011 << 1 = 0110)
b >>= 1;   // 右移一位, 结果为 3 (0110 >> 1 = 0011)
字符串连接复合赋值运算符
  • +=:字符串连接赋值
typescript 复制代码
let greeting = "Hello";
greeting += ", world!"; // 结果为 "Hello, world!"

示例代码

以下是一些综合使用上述赋值运算符的例子:

typescript 复制代码
function demonstrateAssignmentOperators() {
    let num = 10;

    console.log(`Original value of num: ${num}`);
    
    num += 5;
    console.log(`After adding 5 using +=: ${num}`); // 输出 15
    
    num -= 3;
    console.log(`After subtracting 3 using -=: ${num}`); // 输出 12
    
    num *= 2;
    console.log(`After multiplying by 2 using *=: ${num}`); // 输出 24
    
    num /= 4;
    console.log(`After dividing by 4 using /=: ${num}`); // 输出 6
    
    num %= 5;
    console.log(`After modulus division by 5 using %=: ${num}`); // 输出 1
    
    num **= 2;
    console.log(`After exponentiation by 2 using **=: ${num}`); // 输出 1

    // Bitwise assignment operators example
    let bitNum = 5; // Binary: 0101
    bitNum &= 3; // Binary: 0011
    console.log(`After bitwise AND with 3 using &=: ${bitNum}`); // 输出 1

    bitNum |= 6; // Binary: 0110
    console.log(`After bitwise OR with 6 using |=: ${bitNum}`); // 输出 7

    bitNum ^= 4; // Binary: 0100
    console.log(`After bitwise XOR with 4 using ^=: ${bitNum}`); // 输出 3

    bitNum <<= 1;
    console.log(`After left shift by 1 using <<=: ${bitNum}`); // 输出 6

    bitNum >>= 1;
    console.log(`After right shift by 1 using >>=: ${bitNum}`); // 输出 3
}

demonstrateAssignmentOperators();

注意事项

  • 类型兼容性:确保赋值运算符右边的表达式返回的类型与左边变量声明的类型兼容。例如,不能将字符串赋值给数字类型的变量。

    typescript 复制代码
    let age: number;
    // age = "twenty"; // 错误:类型 'string' 不是类型 'number' 的子类型
  • 复合赋值运算符的行为:复合赋值运算符会先对两边的值进行相应运算,然后将结果赋值给左侧的变量。因此,在使用这些运算符时要注意可能产生的副作用,特别是当左侧是一个复杂表达式时。

通过理解和正确使用赋值运算符,你可以编写更简洁、易读且高效的 TypeScript 代码。

3. 比较运算符(Comparison Operators)

用于比较两个值并返回布尔结果。

  • == 等于(不推荐,因为会进行类型转换)
  • === 严格等于
  • != 不等于(不推荐)
  • !== 严格不等于
  • <, >, <=, >= 大小比较
typescript 复制代码
let isEqual = 5 === "5"; // false, 因为类型不同
let isNotEqual = 10 !== "10"; // true, 因为类型不同

比较运算符在 TypeScript 中用于比较两个值,并返回一个布尔值 (truefalse)。TypeScript 继承了 JavaScript 的比较运算符,但其静态类型系统可以帮助避免一些常见的类型转换错误。以下是 TypeScript 支持的比较运算符及其用法:

1. 等于和不等于

  • ==:相等(宽松相等),会进行类型转换后比较。
  • ===:严格相等,不会进行类型转换,只在类型和值都相同的情况下返回 true
  • !=:不相等(宽松不相等),会进行类型转换后比较。
  • !==:严格不相等,不会进行类型转换。

推荐使用严格相等 (===) 和严格不相等 (!==) 运算符,因为它们可以避免由于类型转换导致的意外行为。

typescript 复制代码
console.log(5 == "5"); // true, 因为进行了类型转换
console.log(5 === "5"); // false, 因为类型不同

console.log(5 != "5"); // false, 因为进行了类型转换
console.log(5 !== "5"); // true, 因为类型不同

2. 比较大小

  • <:小于
  • >:大于
  • <=:小于等于
  • >=:大于等于

这些运算符通常用于数值类型的比较,但也可以用于字符串(按字典顺序)和其他可比较的类型。

typescript 复制代码
console.log(3 < 5); // true
console.log("apple" < "banana"); // true, 字母表顺序上 "apple" 在 "banana" 之前

3. 特殊值的比较

对于特殊值如 nullundefinedNaN,比较结果可能会有所不同:

  • null == undefined 返回 true,但 null === undefined 返回 false
  • NaN 不等于任何值,包括它自己。即 NaN !== NaN 返回 true
typescript 复制代码
console.log(null == undefined); // true
console.log(null === undefined); // false

console.log(NaN == NaN); // false
console.log(NaN !== NaN); // true

4. 使用 Object.is()

为了处理 NaN+0-0 的特殊情况,JavaScript 提供了一个更严格的比较方法 Object.is()。这个函数在 TypeScript 中同样适用。

typescript 复制代码
console.log(Object.is(NaN, NaN)); // true
console.log(Object.is(+0, -0)); // false

示例代码

以下是一些综合使用上述比较运算符的例子:

typescript 复制代码
function demonstrateComparisonOperators() {
    let a = 5;
    let b = "5";
    let c = 10;

    console.log(`a == b: ${a == b}`); // true, 因为进行了类型转换
    console.log(`a === b: ${a === b}`); // false, 因为类型不同

    console.log(`a < c: ${a < c}`); // true
    console.log(`a >= c: ${a >= c}`); // false

    console.log(`null == undefined: ${null == undefined}`); // true
    console.log(`null === undefined: ${null === undefined}`); // false

    console.log(`NaN == NaN: ${NaN == NaN}`); // false
    console.log(`NaN !== NaN: ${NaN !== NaN}`); // true

    console.log(`Object.is(NaN, NaN): ${Object.is(NaN, NaN)}`); // true
    console.log(`Object.is(+0, -0): ${Object.is(+0, -0)}`); // false
}

demonstrateComparisonOperators();

注意事项

  • 避免使用 ==!= :由于这些运算符会自动进行类型转换,可能导致意外的结果。因此,在大多数情况下应该使用严格相等 (===) 和严格不相等 (!==)。

  • 理解 NaN 和零的行为 :了解 NaN 和正负零的比较特性非常重要,特别是在数学计算中。

  • 类型安全:利用 TypeScript 的类型检查功能,确保你比较的是同类型的值,这可以减少运行时错误的发生几率。

通过正确地选择和使用比较运算符,你可以编写出更加可靠且不易出错的代码。

4. 逻辑运算符(Logical Operators)

用于组合条件表达式。

  • && 逻辑与
  • || 逻辑或
  • ! 逻辑非
typescript 复制代码
let hasPermission = true && isAdmin; // 如果两者都是 true,则为 true
let canAccess = isLoggedIn || isGuest; // 如果有一个是 true,则为 true
let isBlocked = !isAllowed; // 如果 isAllowed 是 false,则为 true

逻辑运算符在 TypeScript 中用于组合多个条件表达式,从而构建更复杂的布尔逻辑。TypeScript 支持三种主要的逻辑运算符:逻辑与 (&&)、逻辑或 (||) 和逻辑非 (!)。这些运算符可以应用于任何返回布尔值(truefalse)的表达式,并且它们也遵循短路求值规则。

1. 逻辑与 (&&)

逻辑与运算符返回第一个为 false 的操作数(如果存在),否则返回最后一个操作数。所有操作数都被隐式转换为布尔值进行评估。当所有操作数都为真时,最终结果为 true;只要有一个操作数为假,则结果为 false

短路行为 :如果第一个操作数为 false,则不会评估第二个操作数。

typescript 复制代码
let hasPermission = true;
let isAdmin = false;

if (hasPermission && isAdmin) {
    console.log("Access granted.");
} else {
    console.log("Access denied."); // 输出 "Access denied."
}

2. 逻辑或 (||)

逻辑或运算符返回第一个为 true 的操作数(如果存在),否则返回最后一个操作数。同样,所有操作数都被隐式转换为布尔值进行评估。只要有一个操作数为真,则结果为 true;只有当所有操作数都为假时,最终结果才为 false

短路行为 :如果第一个操作数为 true,则不会评估第二个操作数。

typescript 复制代码
let isLoggedIn = true;
let isGuest = false;

if (isLoggedIn || isGuest) {
    console.log("Welcome!"); // 输出 "Welcome!"
}

3. 逻辑非 (!)

逻辑非运算符用于反转一个布尔表达式的值。它将 true 变为 false,将 false 变为 true。对于非布尔值,! 会先将其转换为布尔值再取反。

typescript 复制代码
let isActive = true;

if (!isActive) {
    console.log("Account is inactive.");
} else {
    console.log("Account is active."); // 输出 "Account is active."
}

短路求值

逻辑运算符具有短路求值特性,这意味着一旦可以确定整个表达式的结果,就会停止进一步评估剩余的操作数。这不仅可以提高性能,还可以用来实现安全的属性访问或提供默认值。

安全属性访问
typescript 复制代码
let user = { details: { name: "Alice" } };

// 使用逻辑与确保在访问嵌套属性之前检查每个层级是否存在
console.log(user && user.details && user.details.name); // 输出 "Alice"
提供默认值
typescript 复制代码
let username = null;
let defaultName = "Guest";

// 如果 username 是 falsy 值(如 null 或 undefined),则使用 defaultName
console.log(username || defaultName); // 输出 "Guest"

注意事项

  • 避免不必要的复杂性:虽然逻辑运算符非常强大,但过度使用可能导致代码难以阅读和维护。尽量保持条件表达式的简洁。

  • 理解类型转换:逻辑运算符会对操作数执行隐式的布尔转换。了解哪些值被认为是"真"(truthy)和"假"(falsy)非常重要,以避免意外的行为。

  • 空值合并运算符 (??) :从 ES2020 开始,JavaScript 引入了空值合并运算符,它可以作为逻辑或运算符的一种替代方案,专门用于处理 nullundefined 的默认值替换。例如:

    typescript 复制代码
    let nickname = null;
    let fallbackName = "Stranger";
    
    console.log(nickname ?? fallbackName); // 输出 "Stranger"

通过正确使用逻辑运算符,你可以创建出清晰、高效的条件逻辑,使代码更加健壮和易于理解。

5. 条件(三元)运算符(Conditional (Ternary) Operator)

用于根据条件选择不同的值。

typescript 复制代码
let message = isLoggedIn ? "Welcome back!" : "Please sign up.";

条件(三元)运算符是 TypeScript 和 JavaScript 中的一种简短的 if-else 语法,它允许在一行代码中根据条件选择两个值中的一个。其结构为 condition ? exprIfTrue : exprIfFalse,其中:

  • condition 是一个布尔表达式。
  • exprIfTrue 是当条件为真时返回的表达式。
  • exprIfFalse 是当条件为假时返回的表达式。

语法

typescript 复制代码
let result = condition ? exprIfTrue : exprIfFalse;

示例

简单的例子
typescript 复制代码
let age = 20;
let beverage = age >= 21 ? "Beer" : "Juice";
console.log(beverage); // 输出 "Juice"

在这个例子中,如果 age 大于或等于 21,则 beverage 将被设置为 "Beer";否则,它将被设置为 "Juice"

嵌套使用

你也可以嵌套多个三元运算符来处理更复杂的逻辑,但要注意保持代码的可读性。

typescript 复制代码
let score = 85;
let grade = score >= 90 ? "A" :
            score >= 80 ? "B" :
            score >= 70 ? "C" :
            score >= 60 ? "D" : "F";

console.log(grade); // 输出 "B"
与逻辑运算符结合使用

有时你可以将三元运算符与逻辑运算符结合起来,以提供默认值或进行安全检查。

typescript 复制代码
let username = null;
let displayName = username || "Guest"; // 使用逻辑或运算符提供默认值
console.log(displayName); // 输出 "Guest"

// 或者使用三元运算符更加明确地表示意图
let safeDisplayName = username ? username : "Guest";
console.log(safeDisplayName); // 输出 "Guest"

类型推断和类型兼容性

TypeScript 的静态类型系统会推断三元运算符的结果类型,并确保 exprIfTrueexprIfFalse 的类型是兼容的。如果两者类型不同,TypeScript 会尝试找到它们之间的共同超类型。

typescript 复制代码
let isMember = true;
let message = isMember ? "Welcome back!" : 42;

// 如果两个分支可能返回不同类型,TypeScript 会尝试找到共同类型
// 在这个例子中,message 的类型会被推断为 string | number

注意事项

  • 保持简洁 :虽然三元运算符可以使代码更紧凑,但过度使用或嵌套过多可能会降低代码的可读性。对于复杂的条件逻辑,考虑使用传统的 if-else 语句。

  • 类型一致性 :尽量保证 exprIfTrueexprIfFalse 返回相同类型的值,这有助于避免潜在的类型错误并提高代码的健壮性。

  • 空值合并运算符 (??) :从 ES2020 开始,JavaScript 引入了空值合并运算符,它可以作为三元运算符的一种替代方案,专门用于处理 nullundefined 的默认值替换。例如:

    typescript 复制代码
    let nickname = null;
    let fallbackName = "Stranger";
    
    console.log(nickname ?? fallbackName); // 输出 "Stranger"

通过合理使用条件(三元)运算符,你可以编写出既简洁又易读的代码,同时利用 TypeScript 的类型系统来确保类型安全性。

6. 类型运算符(Type Operators)

TypeScript 特有的运算符,用于处理类型信息。

  • typeof:检查变量的类型。
  • instanceof:判断对象是否为某个类的实例。
  • as 或尖括号 <>:类型断言(Type Assertion),告诉编译器一个表达式的类型。
typescript 复制代码
let str: string = "Hello";
console.log(typeof str); // 输出 "string"

class Animal {}
let dog = new Animal();
console.log(dog instanceof Animal); // true

let someValue: any = "this is a string";
let strLength = (someValue as string).length;

TypeScript 提供了几种类型运算符,用于处理和检查变量的类型。这些运算符在编写类型安全的代码时非常有用,特别是在需要进行类型断言或类型保护的情况下。以下是 TypeScript 中主要的类型运算符:

1. typeof 运算符

typeof 运算符用于检查变量的类型,并返回一个表示该类型的字符串。尽管 typeof 是 JavaScript 的一部分,但它在 TypeScript 中也有其重要用途。

  • 基本用法 :可以用来检查原始类型(如 number, string, boolean 等)。

    typescript 复制代码
    let num = 42;
    console.log(typeof num); // 输出 "number"
  • 与联合类型一起使用 :可以结合 typeof 和类型保护来缩小联合类型的范围。

    typescript 复制代码
    function padLeft(value: string, padding: string | number) {
        if (typeof padding === "number") {
            return Array(padding + 1).join(" ") + value;
        }
        return padding + value;
    }

2. instanceof 运算符

instanceof 运算符用于检查对象是否为某个类的实例。这对于确保对象属于特定的构造函数或类非常有用。

typescript 复制代码
class Animal {}
class Dog extends Animal {}

let dog = new Dog();
console.log(dog instanceof Dog); // true
console.log(dog instanceof Animal); // true

3. 类型断言(Type Assertion)

类型断言允许你告诉编译器某个表达式的类型,从而覆盖其默认的类型推断。这在你知道运行时类型比编译器更准确时特别有用。

  • 尖括号语法

    typescript 复制代码
    let someValue: any = "this is a string";
    let strLength = (<string>someValue).length;
  • as 关键字:推荐使用这种方式,尤其在 JSX 或 React 环境中。

    typescript 复制代码
    let someValue: any = "this is a string";
    let strLength = (someValue as string).length;

4. 用户定义的类型保护(User-Defined Type Guards)

用户定义的类型保护是自定义函数,它们返回一个布尔值,并且当返回 true 时,可以缩小参数的类型范围。通过这种方式,可以在函数体内对参数进行更精确的类型检查。

typescript 复制代码
interface Bird {
    fly(): void;
    layEggs(): void;
}

interface Fish {
    swim(): void;
    layEggs(): void;
}

function isFish(animal: Fish | Bird): animal is Fish {
    return (animal as Fish).swim !== undefined;
}

function getFood(animal: Fish | Bird) {
    if (isFish(animal)) {
        animal.swim(); // 编译器知道此时 animal 是 Fish 类型
    } else {
        animal.fly(); // 编译器知道此时 animal 是 Bird 类型
    }
}

5. 空值合并运算符 (??)

虽然严格来说这不是一个类型运算符,但它是 TypeScript 和现代 JavaScript 中用于处理 nullundefined 的一种方式。它提供了一种简洁的方法来指定默认值。

typescript 复制代码
let nickname: string | null = null;
let userName = nickname ?? "Guest";

console.log(userName); // 输出 "Guest"

总结

TypeScript 的运算符涵盖了从基本的算术到复杂的类型操作的各种需求。理解这些运算符可以帮助你编写更清晰、更有效的代码。尤其是类型运算符、空值合并运算符和可选链运算符等特性,它们提供了强大的工具来处理复杂的数据结构和类型问题。

相关推荐
捕鲸叉40 分钟前
QT自定义工具条渐变背景颜色一例
开发语言·前端·c++·qt
傻小胖1 小时前
路由组件与一般组件的区别
前端·vue.js·react.js
Elena_Lucky_baby1 小时前
在Vue3项目中使用svg-sprite-loader
开发语言·前端·javascript
重生之搬砖忍者2 小时前
uniapp使用canvas生成订单小票图片
前端·javascript·canva可画
万水千山走遍TML2 小时前
console.log封装
前端·javascript·typescript·node·log·console·打印封装
赵大仁2 小时前
uni-app 多平台分享实现指南
javascript·微信小程序·uni-app
阿雄不会写代码2 小时前
使用java springboot 使用 Redis 作为消息队列
前端·bootstrap·html
m0_748236583 小时前
【Nginx 】Nginx 部署前端 vue 项目
前端·vue.js·nginx
@C宝3 小时前
【前端面试题】前端中的两个外边距bug以及什么是BFC
前端·bug
Burt3 小时前
@antfu/eslint 支持 globals 全局变量
前端·uni-app·eslint