js运算符
loyalvi Lv7

js操作符

js运算顺序
instanceof和typeof

运算符

JavaScript 中的运算符用于执行各种运算,包括数学运算、字符串连接、逻辑运算等。以下是 JavaScript 中常见的运算符分类及其具体介绍:

算术运算符

  • +:加法。用于数字相加或字符串连接。
  • -:减法。
  • *:乘法。
  • /:除法。
  • %:取余(模运算),返回两数相除的余数。
  • ++:自增运算符,将变量的值增加 1。可以是前自增(++x)或后自增(x++)。
  • --:自减运算符,将变量的值减少 1。可以是前自减(--x)或后自减(x--)。
1
2
3
4
5
var one   = 0.1
var two = 0.2
var six = 0.6
var eight = 0.8
console.log([two - one == one, eight - six == two] ); //true false
1
2
3
var x = 1
console.log(1 + x++); //2
console.log(x);//2
1
2
3
4
5
6
7
8
var x = 0; 
switch(++x) {
case 0: ++x;
case 1: ++x;
case 2: ++x;
}
console.log(x);//3
//没有break switch继续执行

++

在 JavaScript 中,++ 运算符用于将变量的值增加 1。它有两种形式:前置递增(++x)和后置递增(x++),这两种形式在某些情况下会有不同的行为。

前置递增(++x
  • 含义:先将变量 x 的值增加 1,然后返回增加后的值。
  • 示例
    1
    2
    3
    4
    let x = 5;
    let y = ++x;
    console.log(x); // 输出 6
    console.log(y); // 输出 6
    在这个例子中,x 先被增加 1,变为 6,然后 y 被赋值为 6。
后置递增(x++
  • 含义:先返回变量 x 的当前值,然后将 x 的值增加 1。
  • 示例
    1
    2
    3
    4
    let x = 5;
    let y = x++;
    console.log(x); // 输出 6
    console.log(y); // 输出 5
    在这个例子中,y 先被赋值为 x 的当前值 5,然后 x 的值被增加 1,变为 6。
使用场景
  • 循环计数:在 for 循环等场景中,++ 运算符常用于更新循环变量。
    1
    2
    3
    for (let i = 0; i < 10; i++) {
    console.log(i);
    }
    这里 i++ 用于在每次循环后将 i 的值增加 1。
  • 数组遍历:在遍历数组时,也可以使用 ++ 运算符来更新索引。
    1
    2
    3
    4
    let arr = [1, 2, 3, 4, 5];
    for (let i = 0; i < arr.length; ++i) {
    console.log(arr[i]);
    }
    使用前置递增 ++i 或后置递增 i++ 在这种场景下效果相同,但前置递增在某些情况下可能有轻微的性能优势,因为不需要先返回原始值再进行递增操作。
注意事项
  • 避免滥用:虽然 ++ 运算符很简洁,但在一些复杂表达式中过度使用可能会导致代码难以理解。例如,尽量避免在一行代码中对同一个变量进行多次递增操作。
    1
    2
    3
    // 不推荐
    let x = 0;
    let y = ++x + x++ + ++x;
    这种代码很难一眼看出 y 的值是多少。
  • 与其他运算符结合时要小心:当 ++ 运算符与其他运算符结合使用时,要特别注意运算符的优先级和执行顺序。
    1
    2
    let x = 5;
    let y = 2 * ++x; // 先将 x 增加 1,变为 6,然后计算 2 * 6,结果为 12
    总之,++ 运算符在 JavaScript 中是一个非常实用的工具,但在使用时要注意其前置和后置形式的区别以及在复杂表达式中的使用规范,以确保代码的可读性和正确性。

赋值运算符

  • =:简单赋值。
  • +=:加法赋值。等价于 x = x + y
  • -=:减法赋值。等价于 x = x - y
  • *=:乘法赋值。等价于 x = x * y
  • /=:除法赋值。等价于 x = x / y
  • %=:取余赋值。等价于 x = x % y
  • **=:指数赋值。等价于 x = x ** y
    赋值语句右侧的表达式含有关系运算符、逻辑运算符,其运算符的优先级是:关系运算符>逻辑运算符(先&&后||)。
1
2
var a = 4 >= 6 || true && 1 || false;
console.log(a); //1

比较运算符

js类型转换

  • ==:等于。进行类型转换后再比较值是否相等。
  • ===:严格等于。比较值和类型是否都相等。
  • !=:不等于。进行类型转换后再比较值是否不相等。
  • !==:严格不等于。比较值和类型是否都不相等。
  • >:大于。
  • <:小于。
  • >=:大于等于。
  • <=:小于等于.

逻辑运算符

  • &&:逻辑与。如果第一个操作数为真,则返回第二个操作数的值;否则返回第一个操作数的值。
  • ||:逻辑或。如果第一个操作数为假,则返回第二个操作数的值;否则返回第一个操作数的值。
  • !:逻辑非。返回操作数的布尔值的反值。

位运算符

  • &:按位与。
  • |:按位或。
  • ^:按位异或。
  • ~:按位非。
  • <<:左移。
  • >>:右移(带符号)。
  • >>>:无符号右移。

字符串运算符

  • +:字符串连接。用于将两个或多个字符串连接在一起。

条件运算符(三元运算符)

  • ? ::条件运算符。根据条件表达式的真假来选择两个表达式中的一个进行求值。格式为 condition ? exprIfTrue : exprIfFalse

类型运算符

  • typeof:返回一个值的数据类型。可能的返回值有 "undefined""object""boolean""number""bigint""string""symbol""function"
  • instanceof:用于检测构造函数的原型是否出现在对象的原型链中。

解构赋值运算符

  • =:用于数组或对象的解构赋值。例如:
    1
    2
    let [a, b] = [1, 2]; // 数组解构
    let { x, y } = { x: 1, y: 2 }; // 对象解构

空值合并运算符

  • ??:返回左侧表达式的结果,如果左侧表达式为 nullundefined,则返回右侧表达式的结果。

可选链运算符

  • ?.:用于访问对象的属性或调用方法,如果对象为 nullundefined,则不会抛出错误,而是返回 undefined

空值合并赋值运算符

  • ??=:如果左侧变量的值为 nullundefined,则将其设置为右侧表达式的值。

链式赋值运算符

  • =:可以用于链式赋值,例如:
    1
    2
    let a, b, c;
    a = b = c = 3; // a、b、c的值都为3
    这些运算符在 JavaScript 编程中非常常用,掌握它们的使用对于编写高效、清晰的代码非常重要。

几个问号运算符

1
2
3
4
5
var a = "aaa",obj = {a:1},k;
var b = a?a:"--" //aaa
var c = k??"--" // --
var d = obj?.b; //undefind
k??="abc"//abc

减法的误差

在 JavaScript 中进行小数相减时,常常会遇到精度问题,这是因为 JavaScript 中的浮点数是按照 IEEE 754 标准存储的,无法精确表示某些小数,从而导致计算结果出现误差。例如:

1
console.log(0.1 - 0.2); // 输出 -0.10000000000000003

为了解决这个问题,可以采用以下几种方法:

1. 使用 toFixed 方法

toFixed 方法可以将数字格式化为指定小数位数的字符串,然后可以将其转换为数字类型。这种方法适用于对结果精度要求不是极高的情况。

1
2
const result = Number((0.1 - 0.2).toFixed(10));
console.log(result); // 输出 -0.1

这里 toFixed(10) 表示保留 10 位小数,可以根据实际需要调整小数位数。需要注意的是,toFixed 方法返回的是字符串,所以需要用 Number 函数将其转换为数字。

2. 使用乘除法转换为整数计算

先将小数乘以一个适当的倍数转换为整数,进行整数相减后再除以相同的倍数还原为小数。这种方法可以避免浮点数运算的精度问题。

1
2
3
4
5
function subtract(num1, num2) {
const multiple = 10 ** Math.max(num1.toString().split('.')[1]?.length || 0, num2.toString().split('.')[1]?.length || 0);
return (Math.round(num1 * multiple) - Math.round(num2 * multiple)) / multiple;
}
console.log(subtract(0.1, 0.2)); // 输出 -0.1

在这个例子中,通过计算两个小数的小数位数,确定乘以的倍数,然后进行整数运算,最后还原为小数。这种方法可以精确地进行小数相减运算。

3. 使用第三方库

有一些第三方库如 decimal.jsbignumber.js 等专门用于处理高精度的数值运算,它们可以很好地解决 JavaScript 中浮点数运算的精度问题。
decimal.js 为例:

1
2
3
4
5
const Decimal = require('decimal.js');
const num1 = new Decimal(0.1);
const num2 = new Decimal(0.2);
const result = num1.minus(num2);
console.log(result.toString()); // 输出 -0.1

使用第三方库可以方便地进行各种高精度的数值运算,但会增加项目的依赖和体积。

4. 使用 Math. round 方法结合适当的倍数

这种方法与第二种方法类似,但在进行乘除法转换时,使用 Math.round 方法对结果进行四舍五入,以减少精度误差。

1
2
3
4
5
function subtract(num1, num2) {
const multiple = 10 ** 10; // 可以根据需要调整倍数
return Math.round((num1 - num2) * multiple) / multiple;
}
console.log(subtract(0.1, 0.2)); // 输出 -0.1

这里选择了 10 的 10 次方作为倍数,可以根据实际精度要求调整倍数的大小。这种方法简单易实现,也能在一定程度上解决精度问题。

delete

在 JavaScript 中,delete 运算符用于从对象中删除一个属性。如果删除成功,delete 运算符会返回 true;如果删除失败(例如属性不存在或属性是不可配置的),则返回 false

1. 基本用法

delete 运算符的基本语法如下:

1
2
delete object.property;
delete object['property'];

示例:

1
2
3
4
5
6
7
const obj = { a: 1, b: 2, c: 3 };
console.log(obj); // { a: 1, b: 2, c: 3 }
// 删除属性
delete obj.a;
console.log(obj); // { b: 2, c: 3 }
// 删除不存在的属性
console.log(delete obj.d); // true(因为属性不存在,但操作仍然被认为是“成功”的)

2. 返回值

  • 如果属性被成功删除,delete 返回 true
  • 如果属性不存在,delete 也会返回 true
  • 如果属性是不可配置的(即设置了 configurable: false),delete 将返回 false

示例:

1
2
3
4
const obj = { a: 1 };
Object.defineProperty(obj, 'b', { value: 2, configurable: false });
console.log(delete obj.a); // true
console.log(delete obj.b); // false(因为属性 b 是不可配置的)

3. 删除数组元素

虽然 delete 可以删除数组中的元素,但它不会改变数组的长度,也不会移动后续的元素。被删除的元素会变成 undefined

示例:

1
2
3
4
5
const arr = [1, 2, 3, 4];
console.log(arr); // [1, 2, 3, 4]
delete arr[2];
console.log(arr); // [1, 2, undefined, 4]
console.log(arr.length); // 4(数组长度不变)

注意:如果需要从数组中移除元素,建议使用数组方法(如 splicefilter),而不是 delete

4. 删除对象的原型属性

delete 只能删除对象自身的属性,而不能删除继承自原型链的属性。如果需要删除原型链上的属性,可以使用 deleteObject.getPrototypeOf 结合。

示例:

1
2
3
4
5
6
7
8
const obj = { a: 1 };
Object.prototype.b = 2;
console.log(obj.b); // 2(继承自原型链)
delete obj.b; // false(因为 b 不是 obj 自身的属性)
console.log(obj.b); // 2(仍然可以访问)
// 删除原型链上的属性
delete Object.prototype.b;
console.log(obj.b); // undefined

5. 注意事项

  • 不可配置属性:如果属性的 configurable 属性为 false,则无法使用 delete 删除该属性。
  • 严格模式:在严格模式下,删除不可配置属性会抛出错误,而不是返回 false
  • 数组索引:删除数组元素时,delete 不会改变数组的长度,也不会移动后续元素。

示例(严格模式):

1
2
3
4
5
6
7
8
'use strict';
const obj = { a: 1 };
Object.defineProperty(obj, 'b', { value: 2, configurable: false });
try {
delete obj.b; // TypeError: Cannot delete property 'b'
} catch (e) {
console.error(e);
}

6. 总结

delete 运算符用于从对象中删除属性,但需要注意以下几点:

  • 它只能删除对象自身的属性,不能删除继承自原型链的属性。
  • 如果属性是不可配置的,delete 将返回 false 或抛出错误(严格模式)。
  • 在删除数组元素时,建议使用数组方法(如 splicefilter),而不是 delete,因为 delete 不会改变数组的长度。
    合理使用 delete 可以帮助你动态地管理对象的属性,但在使用时需要清楚它的行为和限制。
由 Hexo 驱动 & 主题 Keep
访客数 访问量