【JavaScript】运算符

算术运算符

1. 加法运算符(+)

加法运算符用于将两个值相加。如果两个操作数都是数字,则它们将被加在一起。如果其中一个操作数是字符串,则另一个操作数将被转换为字符串,然后执行字符串连接。

运算子不同,导致执行不同的语法,这种现象叫做重载。

let result1 = 5 + 3; // result1 等于 8
let result2 = 'Hello' + ' ' + 'World'; // result2 等于 'Hello World'

依次调用 valueOf() 和 toString() 转为原始类型,再进行相加。

console.log(Number({}))
console.log({} + 1) // [object Object]1
console.log({}.toString())  // [object Object]

注:特例 -> 如果运算子是一个 Date 对象的实例,那么会优先执行 toString 方法。

let obj = new Date()
obj.valueOf = function () {return 1
};
obj.toString = function () {return 'hello'
};
console.log(obj + 2) // hello2

四则运算中的 - * / 都是转换成数值进行运算即可。如果无法转换成数值,那么最终得到的结果就是 NaN。

2. 余数运算符(%)

余数运算符返回除法操作的余数。它可以用于确定一个数字是否为另一个数字的倍数,或者在循环中获取周期性的值。

let remainder = 10 % 3; // remainder 等于 1,因为 10 除以 3 的余数是 1

需要注意的是,运算结果的正负号是由第一个运算子的正负号决定的。

console.log(-1 % 2) // -1
console.log(1 % -2) // 1

所以,为了得到正确的结果,可以使用绝对值函数。

// 错误写法
function isOdd(n) {return n % 2 === 1
}
isOdd(-2) // false
isOdd(-1) // false// 正确写法
function isOdd(n) {return Math.abs(n % 2) === 1
}
isOdd(-2) // false
isOdd(-1) // true

余数运算符还可以用于浮点数的运算。但是无法得到精确的结果。

3. 自增和自减运算符(++ 和 --)

自增运算符(++)用于将变量的值增加 1,而自减运算符(–)用于将变量的值减少 1。它们可以在变量前缀(前置递增/递减)或后缀(后置递增/递减)使用,根据其位置在表达式中的不同,会产生不同的效果。

let x = 5;
let y = ++x; // x 现在等于 6,y 等于 6
let z = x--; // x 现在等于 5,z 等于 6

4. 数值运算符和负数值运算符(+ 和 -)

数值运算符(+)用于将操作数转换为数字,而负数值运算符(-)用于将操作数转换为负数。(NaN 也是数值)。连用两个负数值运算符等同于数值运算符(-(-x))。

数值运算符是一元运算符(只操作一个数),而加法运算符是二元运算符(需要两个操作数)。都会返回一个新值,而不会改变原始值。

let num1 = +'10'; // num1 等于 10,将字符串转换为数字
let num2 = -10; // num2 等于 -10

运算之后,变量的值发生改变,这种效应叫做运算的副作用。自增和自减是仅有的两个具有副作用的运算符。

5. 指数运算符(**)

指数运算符计算第一个操作数的第二个操作数次幂。

let result = 2 ** 3; // result 等于 8,2 的 3 次幂是 8

指数运算符是右结合,所以多个连用时,先进行最后边的计算。

console.log(2 ** 3 ** 2)  // 512

6. 赋值运算符(=)

赋值运算符用于将右侧的值赋给左侧的变量或属性。它将右侧的值计算出来,并将结果赋给左侧的变量。

let x = 5;
x += 3; // 等同于 x = x + 3,x 现在等于 8

比较运算符

比较运算符用于比较两个值的大小,返回一个布尔值。

NaN 进行比较运算返回都是 false(即使与自己做全等运算),计算时返回都是 NaN。

1. 非相等运算符(字符串的比较)

非相等运算符(!=)用于比较两个值是否不相等。

先看两个运算子是否都是字符串,如果是,就按照字典顺序比较(比较 Unicode 码点,几乎包含所有字符),位数不相同依次比较各位上的字符;否则,就将两个运算子转成数值,再比较数值的大小。

let result1 = 'hello' != 'world'; // result1 等于 true,因为 'hello' 不等于 'world'
let result2 = 'hello' != 'hello'; // result2 等于 false,因为 'hello' 等于 'hello'

2. 非相等运算符(非字符串的比较)

同样的非相等运算符也可以用于比较非字符串的值,它会在必要时将值进行类型转换,然后再进行比较。

原始类型值

如果两个运算子都是原始类型的值,则是先转为数值再进行比较。

对象

如果运算子是对象,先转成原始类型的值,再进行比较。

转为原始类型,先调用 valueOf(),如果还是对象,再调用 toString()。两个对象之间的比较也是如此。

console.log([2] > [1])  // true
console.log({x: 2} >= {x: 1})  // true  [object Object] >= [object Object]

3. 严格相等运算符(===)

严格相等运算符(===)用于比较两个值是否完全相等,包括它们的值和数据类型。只有在值和类型都相同时,才返回 true,否则返回 false

普通比较
let result5 = 5 === 5; // result5 等于 true,因为 5 的值和类型都等于 5
let result6 = 5 === '5'; // result6 等于 false,因为 5 的类型是数字,而 '5' 的类型是字符串
同一类的原始类型值
console.log(1 === 0x1) // true
console.log(NaN === NaN)  // false
console.log(+0 === -0) // true
复合(引用)类型值

此时不再是比较值,而是比较地址。

对象两个对象的比较,严格相等比较的是地址,而大于或者小于比较的是值。

console.log({} === {}) // false
console.log([] === []) // false
console.log(function () {} === function () {}) // false
console.log({} >= {})  // true
null 和 undefined
console.log(undefined === undefined)  //true
console.log(null === null)  //true

4. 严格不相等运算符(!==)

严格不相等运算符(!==)与严格相等运算符相反,用于比较两个值是否不完全相等,包括它们的值和数据类型。

逻辑是先求严格相等运算符的结果,然后返回相反值。

let result7 = 5 !== '5'; // result7 等于 true,因为 5 的类型是数字,而 '5' 的类型是字符串
let result8 = 5 !== 10; // result8 等于 true,因为 5 的值和类型都不等于 10

5. 相等运算符(==)

相等运算符(==)用于比较两个值是否相等。它会在必要时进行类型转换,然后再进行比较。

原始类型值

原始类型值会转换成数值后再进行严格比较。

console.log(2 == true)  // false
console.log('true' == true)  // false
console.log('' == 0)  // true
// 字符串转成数字时,省略前置和后置的空格
console.log('\n   1  \t' == 1)  // true
对象与原始类型值比较

对象会先转为原始类型值,再进行比较。

对象先调用 valueOf(),得到原始类型的值进行比较;如果还是对象再调用 toString(),得到字符串形式再进行比较。

console.log([1,2] == '1,2')  // true
console.log([1, 2] == '1,2')  // true  // 注意空格
console.log([1,2] == '1, 2')  // false // 注意空格
console.log([1] == true)  // true
undefined 和 null

undefined 和 null 只有和自身比较时,或者相互比较时,才返回 true;与其他类型的值比较时,都返回 false。

console.log(undefined == undefined) // true
console.log(null == null) // true
console.log(null == undefined) // true
console.log(undefined == 0) // false
console.log(null == 0) // false
console.log(undefined == false) // false
console.log(null == false) // false
相等运算符的缺点

一些反直觉的隐式类型转换。

console.log(0 == '') //true
console.log(0 == '0') // true
console.log(2 == false) // false
console.log(2 == true) // false
console.log(0 == null) // false
console.log(0 == undefined) // false
console.log(0 == NaN)  // false
console.log(false == 'false') // false
console.log(false == '0') // true
console.log(false == undefined) // false
console.log(false == null) // false
console.log(null == undefined) // true
console.log(' \t\r\n ' == 0) // true

所以还是使用===吧。

6. 不相等运算符(!=)

不相等运算符(!=)与相等运算符相反,用于比较两个值是否不相等。它也会在必要时进行类型转换,然后再进行比较。

let result11 = 5 != '5'; // result11 等于 false,因为在比较时会将字符串 '5' 转换为数字 5,然后比较它们的值
let result12 = 5 != 10; // result12 等于 true,因为 5 不等于 10

布尔运算符(逻辑运算符)

1. 取反运算符(!)

取反运算符(!)用于取反一个布尔值,将 true 变为 false,将 false 变为 true

使用!!快速将某变量转为布尔值。

let isTrue = true;
let isFalse = !isTrue; // isFalse 等于 false

对于非布尔值,取反运算符会将其转为布尔值。可以认为以下六个取反后为 true(使用 Boolean() 方法调用后都是 false),其他都是 false:

  • undefined
  • null
  • false
  • 0
  • NaN
  • 空字符串(‘’)
console.log(![]) // false
console.log(!{}) // false

2. 且运算符(&&)

运算规则:如果第一个运算子的布尔值为 true,则返回第二个运算子的值(是值!!!,而非布尔值!);如果第一个运算子的布尔值为 false,则直接返回第一个运算子的值,不再对第二个运算子求值。

console.log('t' && 'f')  // f
console.log('' && 'y')  // ''

通过第一个表达式的值,控制第二个运算子的机制叫做短路。等价于 if 结构。

console.log('t' && 'f')  // f
// 等价于
if ('t') {'f'
}

当存在多个表达式时,返回第一个布尔值为 false 的表达式的值;如果所有表达式的布尔值都为 true,则返回最后一个表达式的值。

3. 或运算符(||)

运算规则:如果第一个运算子的布尔值为 true,则返回第一个运算子的值(是值!!!,而非布尔值!);如果第一个运算子的布尔值为 false,则返回第二个运算子的值。

当存在多个表达式时,返回第一个布尔值为 true 的表达式的值;如果所有表达式的布尔值都为 false,则返回最后一个表达式的值。

常用于为一个变量设置默认值:

text = text || ''

4. 三元条件运算符(? :)

三元条件运算符(? :)是 JavaScript 中的条件运算符,用于简洁地表示一个条件。它由一个条件表达式,一个问号 ?,一个返回值为真时执行的表达式和一个冒号 :,一个返回值为假时执行的表达式组成。

是 js 中唯一一个需要三个表达式的值。

let age = 20;
let allowed = (age >= 18) ? 'Allowed' : 'Not Allowed'; // 如果年龄大于等于 18,allowed 等于 'Allowed',否则等于 'Not Allowed'

和 if…else… 的区别是:if…else… 是语句,没有返回值;三元表达式是表达式。具有返回值。

位运算符

按位运算符是将操作数换算成 32 位的二进制整数,然后按每一位来进行运算。

1. 按位非(NOT)(~)

按位非操作符(~)用于对一个二进制数的每一位取反。它将操作数的每个位取反,0 变为 1,1 变为 0。

let x = 5; // 二进制表示为 00000000000000000000000000000101
let result = ~x; // 二进制表示为 11111111111111111111111111111010,对应的十进制为 -6

按位非,实质上是对操作数求负,然后减去 1.

2. 按位与(AND)(&)

按位与操作符(&)用于对两个二进制数的每一位执行逻辑与操作。只有当两个相应位都为 1 时,结果才为 1,否则为 0。

let x = 5; // 二进制表示为 00000000000000000000000000000101
let y = 3; // 二进制表示为 00000000000000000000000000000011
let result = x & y; // 二进制表示为 00000000000000000000000000000001,对应的十进制为 1

3. 按位或(OR)(|)

按位或操作符(|)用于对两个二进制数的每一位执行逻辑或操作。只要两个相应位中的至少有一个为 1,结果就为 1。

let x = 5; // 二进制表示为 00000000000000000000000000000101
let y = 3; // 二进制表示为 00000000000000000000000000000011
let result = x | y; // 二进制表示为 00000000000000000000000000000111,对应的十进制为 7

4. 按位异或(XOR)(^)

按位异或操作符(^)用于对两个二进制数的每一位执行逻辑异或操作。如果两个相应位不同,则结果为 1,否则为 0。

let x = 5; // 二进制表示为 00000000000000000000000000000101
let y = 3; // 二进制表示为 00000000000000000000000000000011
let result = x ^ y; // 二进制表示为 00000000000000000000000000000110,对应的十进制为 6
console.log(true ^ 'aaa')  // 1  // aaa 此时转为了 NaN,为假

按位异或,如果是非整数值,两个操作数中只有一个为真,就返回 1 ,否则为 0 。

5. 按位左移(Left Shift)(<<)

按位左移操作符(<<)将一个数字的所有位向左移动指定的位数。左侧最高位被丢弃,右侧用 0 补充。

<<: 乘以二的指定次方

let x = 5; // 二进制表示为 000000000000000000000101
let result = x << 2; // 二进制表示为 00000000000000000000000000010100,对应的十进制为 20

6. 按位右移(Right Shift)(>>)

按位右移操作符(>>)将一个数字的所有位向右移动指定的位数。对于无符号数,左侧用 0 填充。对于有符号数,正数左侧用 0 填充,负数左侧用 1 填充。

>>: 除以二的指定次方

let x = 5; // 二进制表示为 00000000000000000000000000000101
let result = x >> 1; // 二进制表示为 00000000000000000000000000000010,对应的十进制为 2

其他运算符

1. void 运算符

void 运算符用于指定一个表达式不返回任何值。它通常用于在 href 属性中使用 JavaScript 代码时,防止页面跳转。

<a href="javascript:void(0)">点击这里不跳转</a>

建议使用括号,避免不必要的错误。比如void 4 + 7 等价于 (void 4) + 7

void 0  //undefined
void(0)  //undefined
void (x = 5) // undefined

防止页面跳转。

// -----
function f() {console.log('hello')
}
<a href="http://localhost:3000" onClick="f(); teturn false;">点击</a> 

2. 逗号运算符

逗号运算符允许在一个语句中执行多个操作,并返回最后一个操作的值。它的优先级是最低的,通常用于在一行中组合多个表达式。

let x = (5 + 3, 10 - 2); // x 等于 8,逗号运算符会依次执行两个操作,并返回最后一个操作的值

在上面的例子中,逗号运算符首先执行了加法操作 5 + 3,然后执行了减法操作 10 - 2,最终返回了减法的结果,即 8。

用途:在返回一个值之前,进行一些辅助操作:

let value = (console.log('hi'), true)
value

运算顺序

JavaScript 中的运算顺序是由运算符的优先级、圆括号的作用以及左结合和右结合规则来决定的。让我们逐个来看:

1. 优先级

每个运算符都有一个固定的优先级,它决定了在没有圆括号的情况下运算符的执行顺序。

常见规则,优先级从高到低依次是:小于等于,严格等于(===),或(||),三元(?:),等号(=)。

let result = 5 + 3 * 2; // result 等于 11,先执行乘法,再执行加法

2. 圆括号的作用

圆括号内只能放表达式,放语句会报错。
作用:

  • 把表达式放在圆括号之中,提升运算优先级
  • 跟在函数后面,调用函数
  • 函数放在圆括号内会返回函数本身
let result = (5 + 3) * 2; // result 等于 16,先执行圆括号内的加法,然后再乘以 2
function f() {return 1
}console.log((f))  // [Function: f]

3. 左结合和右结合

左结合指的是多个具有相同优先级的运算符从左向右计算,右结合则是从右向左计算。大多数运算符都是左结合的,例如加法和乘法运算符。

let result1 = 5 + 3 + 2; // result1 等于 10,先计算 5 + 3 得到 8,然后再加上 2

但是有一些运算符是右结合的,例如赋值运算符、三元条件运算符和指数运算符(**)。右结合意味着先计算右边的操作数,然后将结果赋给左边的操作数。

let x = 5;
let y = 3;
let z = x = y; // z 等于 3,先将 y 的值赋给 x,然后将 x 的值赋给 z
q = a ? b : c ? d : e;

面试题

let a = ?;
if (a == 1 && a == 2 && a == 3) {console.log(1)
}
// 方法一
let a = {i:1 ,toString(){return a.i++}
}
// 方法二
let a = {i: 1,valueOf(){return a.i++}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/7211.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于ESP32和ESP8266的物联网开发过程(一)

给大家演示一个小工具&#xff0c;通过Wifi去连接ESP32或者ESP8266出来的一个热点。连接到这个热点之后&#xff0c;可以输密码&#xff0c;也可以不输密码。这里我设置的是不输密码直接进来&#xff0c;我这个是ESP8266。 进来之后直接点配置Wifi&#xff0c;然后可以看到ESP8…

sem_wait 和 sem_post

在给出的 Sem 类中&#xff0c;sem_wait 和 sem_post 是 POSIX 信号量&#xff08;semaphores&#xff09;的操作函数&#xff0c;用于控制对共享资源的访问。 sem_wait(&_sem); sem_wait 函数的作用是等待&#xff08;或称为“P”操作&#xff0c;源于荷兰语 "Prob…

【简单介绍下7-Zip】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

快速入门!学习鸿蒙App开发的终极指南!

鸿蒙&#xff08;HarmonyOS&#xff09;是华为推出的一款分布式操作系统&#xff0c;旨在为不同设备提供统一的操作体验。鸿蒙App开发可以让应用程序在多个设备上实现流畅运行。本文将介绍鸿蒙App开发的终极指南&#xff0c;帮助您快速入门。 开发环境搭建 鸿蒙App开发过程需要…

双色球案例【C#】

【实例类型】 1双色球类 方法的参数是对象。 public List<string> Numbers { get; set; } // 这个是对象的属性 /// <summary>/// 双色球类/// /// 作用&#xff1a;主要是用来封装数据/// </summary>public class DoubleChromosphere{//public str…

JDBC—用户登录功能的实现

实现功能&#xff1a; 1、需求&#xff1a; 模拟用户登录功能 2、业务描述&#xff1a; 程序运行时&#xff0c;提供一个输入的入口&#xff0c;可以让用户输入用户名和密码 用户输入用户名和密码之后&#xff0c;提交信息&#xff0c;java程序收集到用户信息 …

MD hog 实现移动侦测

1. 原图resize到 640*360 大小&#xff0c; resize方法可采用 bilinear interpolation; 2. 计算 Hog水平方向和垂直方向的梯度&#xff0c;滤波 kernel如下 MD_HogGradX "-1,-2,0,2,1" MD_HogGradY "-1,-2,0,2,1" 3.对比帧选择&#xff0c;假如当前…

专业渗透测试 Phpsploit-Framework(PSF)框架软件小白入门教程(五)

本系列课程&#xff0c;将重点讲解Phpsploit-Framework框架软件的基础使用&#xff01; 本文章仅提供学习&#xff0c;切勿将其用于不法手段&#xff01; 继续接上一篇文章内容&#xff0c;讲述如何进行Phpsploit-Framework软件的基础使用和二次开发。 在下面的图片中&#…

如何代码激活service——packageKit 系统更新番外

在访问packageKit服务的过程中&#xff0c;服务一直访问失败&#xff0c;PackageKit::Daemon::global()->isRunning() 一直返回false&#xff0c;他是一个用于检查 PackageKit 守护进程是否正在运行的函数调用。在 Qt 和 PackageKit 的集成中&#xff0c;isRunning 方法通常…

opengait代码运行之gaitedge 未完成版

文章目录 前言一、下载源代码二、配置环境——pycharm,pytorch等1.pycharm虚拟环境设置2.下载相应的包 三、下载数据集四、下载模型1.第一种方式2.第二种方式 五、开始训练 前言 本次任务为运行opengait代码。主要侧重于gaitedge&#xff0c;需要用到的数据集为CASIA-B。 电脑…

小工具 - 用Astyle的DLL封装一个对目录进行代码格式化的工具

文章目录 小工具 - 用Astyle的DLL封装一个对目录进行代码格式化的工具概述笔记效果编译AStyle的DLL初次使用接口的小疑惑测试程序 - 头文件测试程序 - 实现文件测试程序 - RC备注END 小工具 - 用Astyle的DLL封装一个对目录进行代码格式化的工具 概述 上一个实验(vs2019 - ast…

知识图谱在提升大语言模型性能中的应用:减少幻觉与增强推理的综述

幻觉现象指的是模型在生成文本时可能会产生一些听起来合理但实际上并不准确或相关的输出&#xff0c;这主要是由于模型在训练数据中存在知识盲区所致。 为了解决这一问题&#xff0c;研究人员采取了多种策略&#xff0c;其中包括利用知识图谱作为外部信息源。知识图谱通过将信息…

简单介绍IIC通信协议

文章目录 一&#xff0c;简单介绍二&#xff0c;IIC物理层三&#xff0c;IIC通信时序1.起始位与停止位2.IIC读写地址位信号3.IIC应答信号4.IIC数据位收发信号 四&#xff0c;总线速率五&#xff0c;主机发送数据流程六&#xff0c;主机接收数据流程七&#xff0c;IIC的时钟延展…

go语言并发实战——日志收集系统(十一)基于etcd来监视配置文件的变化

前言 在我们实际生产中&#xff0c;我们常常因为新的项目或者新的功能进而要对配置文件进行修改,但是在生产环境下我们不是每次配置文件发生变化都重启一次系统&#xff0c;这无疑是不切实际的&#xff0c;所以我们需要对配置文件进行实时监控,而今天我们所要展示的也就是如何…

【云原生】Pod 的生命周期(二)

【云原生】Pod 的生命周期&#xff08;一&#xff09;【云原生】Pod 的生命周期&#xff08;二&#xff09; Pod 的生命周期&#xff08;二&#xff09; 6.容器探针6.1 检查机制6.2 探测结果6.3 探测类型 7.Pod 的终止7.1 强制终止 Pod7.2 Pod 的垃圾收集 6.容器探针 probe 是…

uniapp文本框上下滚动问题

一个基本需求&#xff0c;textarea标签没有办法通过手拖动的方式进行滚动&#xff0c;当文字超出其容量后&#xff0c;想要编辑上面被遮挡部分的文字这边难以点到&#xff0c;电脑可以鼠标滚轮&#xff0c;但手机需要拖动但无效&#xff1a; 下面提供了我的解决思路&#xff1a…

秋招后端开发面试题 - JVM类加载机制

目录 JVM类加载机制前言面试题能说一下类的生命周期吗&#xff1f;类加载的过程知道吗&#xff1f;类加载器有哪些&#xff1f;什么是双亲委派机制&#xff1f;为什么要用双亲委派机制&#xff1f;如何破坏双亲委派机制&#xff1f;如何判断一个类是无用的类&#xff1f; JVM类…

高精地图是怎么构建的?方案有哪些?高精度语义地图构建的一点思考

高精地图是怎么构建的&#xff1f;方案有哪些&#xff1f;高精度语义地图构建的一点思考 高精度(High-Definition, HD)语义地图是目前自动驾驶领域的一个重要研究方向&#xff0c;近年随着Transformer和BEV的大火&#xff0c;很多大佬团队都开展了HD语义地图构建相关的工作。2…

【005_音频开发_基础篇_ALSA_Codec_驱动-MA120x0P功放】

005_音频开发_基础篇_ALSA_Codec_驱动-MA120x0P功放 文章目录 005_音频开发_基础篇_ALSA_Codec_驱动-MA120x0P功放创作背景MA120X0P输出模式BTLSEPBTLSEBTL 硬件配置方式/硬件Limiter限幅器限幅器作用过程 主要寄存器操作指令 ma120x0p.cma120x0p.h 创作背景 学历代表过去、能…

Vue MVVM这一篇就够啦!

Vue vs React 相似之处: 它们都有使用 Virtual DOM虚拟DOM-CSDN博客&#xff1b;提供了响应式&#xff08;Reactive&#xff09;和组件化&#xff08;Composable&#xff09;的视图组件。将注意力集中保持在核心库&#xff0c;而将其他功能如路由和全局状态管理交给相关的库。R…