JavaScript运算符详解

2023-11-03

JavaScript运算符详解

目录


JavaScript中的运算符大致可以分为以下几类:

  1. 算术运算符
  2. 比较运算符
  3. 布尔值运算符
  4. 二进制位运算符
  5. 其它运算符

1. 算术运算符

javaScript提供了以下算术运算符:

  • 加法运算符
  • 减法运算符
  • 乘法运算符
  • 除法运算符
  • 指数运算符
  • 余数运算符
  • 自增运算符
  • 自减运算符
  • 正负数值运算符

减法,乘法,除法运算就是正常的数学计算,这里不做详细讲解。

1.1 加法运算符

1.1.1 基本运算规则

加法运算符(+),用来求两个运算子的和。但是JavaScript中,允许非数值相加,而且涉及到字符串时,加法运算符会变成连接运算符。

// 正常的数值相加
1 + 1; // 2

// 非数值相加,布尔值会自动转换为数值,然后进行加法运算
true + true ; // 2
false + false; // 0
true + false; // 1
1 + true; // 2
1 + false; // 1 

// 运算子有字符串时,变为连接运算符
"hello " + "world!"; // "hello world!"
1 + "a"; // "1a"
true + "a"; // "truea"

加法运算符是在运行时决定,到底是执行相加,还是执行连接。这种现象称为“重载”。

// 加法运算的重载
1 + 1 + "a"; // "2a"
"a" + 1 + 1; // "a11"
1.1.2 对象的相加

如果运算子是对象,必须先转成原始类型的值,然后再相加。

var x = { name: "jidi" };
x + 2 // "[object Object]2"

对象转换为原始类型的值,规则如下:

  1. 调用对象的valueOf方法(一般情况下,对象的valueOf方法总是返回对象自身)。
  2. 调用对象的toString方法(对象的toString方法默认返回[Object,Object])。

上面那个例子,实际上可以看成是:

var x = { name: "jidi" };

var y = x.valueOf(); // {name: "jidi"}

var z = y.toString(); // "[object Object]"

z + 2; // "[object Object]2"

我们可以自己定义valueOftoString方法。以得到想要的结果。

// 自定义valueOf方法
var x = {
	name: "jidi",
	valueOf: function(){
		return 5;
	}
};
// 自定义toString方法
var y = {
	name: "jidi",
	toString: function(){
		return 10;
	}
}

5 + x; // 10
5 + y; // 15

注意:如果参与加法运算的两个运算子,其中有一个是Date对象实例,会先执行toStrnig方法。

var now = new Date();

now.valueOf = function(){
	return 5;
}
now.toString = function(){
	return 10;
}

5 + now; // 15

1.2 余数运算符

余数运算符(%)返回前一个运算子被后一个运算子除,所得的余数。余数运算的结果的正负号由第一个运算子决定。

12 % 5; // 2

// 余数运算结果正负情况由第一个运算子正负情况决定
-12 % 5; // -2
-12 % -5; // -2

1.3 自增和自减运算符

自增和自减运算符,是一元运算符,只需要一个运算子。它们的作用是将运算子首先转为数值,然后加上1或者减去1。它们会修改原始变量。

var x = 1;
++x // 2
x // 2

--x // 1
x // 1

自增和自减是仅有的两个具有运算副作用(参与运算后,变量的值发生改变)的运算符。

自增和自减运算符又分为前置和后置两种:前置自增(自减),会先进行自增(自减),然后返回变量操作后的值;后置自增(自减)会先返回变量操作之前的值,然后再进行自增(自减)操作。

var x = 1;
var y = 1;

x++ // 1
++y // 2

1.4 正负数值运算符

数值运算符(+)是一元运算符,可以将任何数值转为数值。
负数值运算符(-)也是一元运算符,可以将任何数值转为数值,只是结果值正负相反。

var x = 1;

// 正数值运算符
+x; // 1
+true; // 1
+[]; // 0

// 负数值运算符
-x; // -1
-true; // -1

1.5 指数运算符

指数运算符(**)是二元运算符,前一个运算子是底数,后一个运算子是指数。指数运算是右结合

5 ** 2; // 25

// 指数运算的右结合
// 相当于5 ** (2 ** 2)
5 ** 2 ** 2; //  625

1.6 赋值运算符

赋值运算符用于给变量赋值。但是赋值运算符可以与其他运算符结合,形成变体。

// 普通赋值运算符

var x = 2; // 将数值2赋值给变量x
var y = x; // 将变量x赋值给变量y

// 与其他运算符结合使用
x += 2; // 等价于 x = x + 2;
x -= 2; // 等价于 x = x - 2;
x *= 2; // 等价于 x = x * 2;
x /= 2; // 等价于 x = x / 2;
x %= 2; // 等价于 x = x % 2;
x **= 2; // 等价于 x = x ** 2;

2. 比较运算符

比较运算符用来比较两个值的大小,返回一个布尔值。
JavaScript中提供了以下比较运算符:

  • >,大于运算符
  • <,小于运算符
  • >=,大于等于运算符
  • <=,小于等于运算符
  • ==,等于运算符
  • ===,严格相等运算符
  • !=,不相等运算符
  • !==,严格不相等运算符

上述运算符可以分为两类:相等比较运算符与非相等比较运算符,两者规则不一样。

2.1 非相等运算符:字符串的比较

对于非相等运算符,如果运算子都是字符串,则是按照字典顺序进行比较。JavaScript引擎会首先比较首字符的Unicode码点,如果相等,则比较第二个字符的Unicode码点,以此类推…

"this".charCodeAt(); // 首字符Unicode码点为116
"is".charCodeAt(); // 首字符Unicode码点为105
"this" > "is"; // 116>105,true

"This".charCodeAt(); // 首字符Unicode码点为84
"this">"This"; // true

2.2 非相等运算符:非字符串的比较

如果两个运算子中至少有一个不是字符串,则存在以下情况:

(1) 原始类型值

如果两个运算子都为原始类型值,则先转换成数值,然后再进行比较。但是任何值与NaN比较,返回值都为false

4 > "3"; // true
2 > true; // true
1 < false; // false
1 > null; // true

2 > NaN // false
1 <= NaN // false
'1' > NaN // false
'1' <= NaN // false
NaN > NaN // false
NaN <= NaN // false

注意:underfined转换为数值会转换成为NaN,即任何值与underfinedNaN进行比较,结果都是false

(2) 对象
如果运算子是对象,则会转换成为原始类型的值,然后再进行比较。
对象转换为原始类型的值按照以下步骤进行的:

  1. 调用对象的valueOf方法(对象调用valueOf方法一般返回对象自身),如果返回原始类型的值,不再进行后续步骤。
  2. 如果valueOf方法结果仍旧是对象,则调用toString方法(对象的toString方法默认返回[Object,Object])。
var x = [2];
x.valueOf(); // [2]
x.valueOf().toString(); // "2"
x > "11" // true ,等同于 [2].valueOf().toString() > "11",即"2">“11”

// 改写valueOf方法
x.valueOf = function () { return "1" };
x > "11" // false,等同于 [2].valueOf() > "11",即 "1" > "11"

上述例子中,数组x调用valueOf方法返回x本身,然后调用toString方法,返回"2",此时是"2""11"两个字符串之间进行比较,比较的是 Unicode码点位置。

2.3 严格相等运算符

严格相等运算符(===)是二元运算符,比较的是两个运算子是否为同一个值。参与运算的运算子情况不同,具有不同的结果:

  • 如果两个运算子值类型不同,直接返回false
  • 如果两个运算子值类型相同,且都是原始数据类型,只要值相等就返回true,否则返回false
  • 如果两个运算子值为复合类型,比较的是两个运算子的值是否指向同一个地址,如果地址相同,返回true,否则返回false
  • 特殊值nullunderfined与自身严格相等。
// 两个运算子值类型不同,直接返回false
1 === "1"; // false
true === "true"; // false
true === 1; // false
"1"===new String("1"); // false

// 两个运算子值类型相同,且为原始数据类型,值相等就返回true
true === true; // true
1 === 1; // true
"a" === "a"; // true

// 两个运算子为复合数据类型,比较的是地址是否一样
{} === {} // false
[] === [] // false

var x = new String("a");
y = x;
x === y // true

// 特殊值 nul,undefined与自身严格相等 
null === null;	
undefined === undefined ;

2.4 严格不相等运算符

严格不相等运算符(!==),它的算法就是先求严格相等运算符(===)的结果,然后返回相反值。

true !== "true"; // true,等价于 !(true === "true")

2.5 相等运算符

相等运算符(==)是二元运算符,用来比较时,会进行数据类型转换。 参与运算的运算子情况不同,也具有不同的结果:

  • 如果运算子数据类型一致,与严格相等运算符完全一样`。
  • 如果运算子数据类型不一致:
    • 都是原始类型,则会转换成数值进行比较。
    • 对象与原始类型,对象会转换为原始类型的值然后进行比较。
    • 特殊值nullNaNundefined
// 数据类型一致,与严格相等运算符一样
1 == 1; // true
true == true; // true
{} == {} // false
[] == [] // false


// 数据类型不一致
// 都是原始数据类型,先转换为数值再进行比较
1 == true; // true
0 == false; // true
1 == "1"; // true
'' == 0; // true
'' == false;  // true

// 对象与原始数据类型比较,对象会先转为原始数据类型然后再进行比较
var person = {
	name: "jidi",
	sex: "男",
	valueOf: function(){
		return 1;
	},
	toString: function(){
		return "jidi";
	}
}
//对象与数值比较,对象转换为数值然后进行比较
person == 1; // true

person.valueOf = function(){return {}};// 自定义valueOf方法返回一个空对象
// 对象与字符串比较,对象转换为字符串然后进行比较
person == "jidi"; // true

// 对象与布尔值比较,对象与布尔值都转换为数值然后进行比较
[1] == true; // true
[] == false; // true


// 特殊值null,NaN,undefined
// NaN与任何值(包括本身),都为false
NaN == true; // false
NaN == 1; // false
NaN == null; //false
NaN == undefined; // false
NaN == NaN; // false
NaN == ""; // false

//null与undefined与其他值进行比较时,都会false,只有相互比较或者自身比较时返回true
null == 0;
null == false;
null == "null";
null == "";
null == null;

undefined == 0;
undefined == "0";
undefined == ""; 
undefined == "undefined";
undefined == false;
undefined == undefined;

null == undefined;

注意:由于相等运算符(==)会进行数据类型转换,可能会出现一些违反常理的结果:

"" == 0; // true
false == "0"; // true
5 == true;    // false
5 == false;   // false

2.6 不相等运算符

相等运算符(==)有一个对应的“不相等运算符”(!=),它的算法就是先求相等运算符的结果,然后返回相反值。

3. 布尔值运算符

布尔值运算符用于将表达式转为布尔值,一共有四个运算符。

  • !,取反运算符
  • &&,且运算符
  • ||,或运算符
  • ?:,三元运算符

3.1 取反运算符

取反运算符用于将布尔值变成相反值,即原来为true取反后变为false,原来为false取反后为true
对于非布尔值,取反运算符会将其转换为布尔值。

!true; // false
!false; // true

// 非布尔值取反
!undefined // true
!null // true
!0 // true
!NaN // true
!"" // true

![] // false
!{} // false

数据类型转换的时候,以下几个值对它们进行取反为true,其它的值取反都为false

  • undefined
  • null
  • ’ ’
  • NaN
  • 0
  • false

3.2 且运算符

且运算符(&&)是二元运算符。且运算符(&&)的运算规则:如果第一个运算子布尔值true,返回第二个运算子的;如果第一个运算子布尔值false,直接返回第一个运算子的,且不再对第二个运算子进行求值,即会出现短路现象。

true && false; // false
5 > 3 && 200; // 200
var x = 1;
23>12 && x++; //2, x=2

false && true; // false
3>5 && 200; // false

var y = 20;
// 发生短路现象
0 && y--; // 0,y=20

且运算符(&&)可以多个连用,此时返回第一个布尔值为false的表达式的;如果表达式的布尔值都为true,则返回最后一个表达式的

// 返回第一个布尔值为false的表达式的值
1 && true && null && "example"; // null
1 && 0 && null && "example"; // 0

//表达式布尔值全为true,返回最后一个表达式的值
1 && true && 23 && "example"; // "example"

3.3 或运算符

或运算符(||) 也是二元运算符。或运算符(||)的运算规则:第一个运算子的布尔值为true,则返回第一个运算子的,且不会对第二个运算子进行计算,即发生短路现象;如果第一个运算子的布尔值为false,则返回第二个运算子的

1 || 2; // 1

//发生短路
var x = 3;
3 > 2 || x++; // true,x=3

3 < 2 || x++; // 4,x=4

利用或运算符(||) 的短路现象,可以给函数参数设置默认值。

function f(x){
	x = x || 5; // 如果x没有传值,则默认x=5
	return x;
}

//  调用函数
f(); // 此时返回默认值5

或运算符(||) 可以多个连用,这时返回第一个布尔值为true的表达式的值。如果所有表达式都为false,则返回最后一个表达式的值。

// 返回第一个布尔值为true的表达式的值
false || 0 || '' || 4 || 'foo' || true; // 4

// 所有表达式的布尔值为false,返回最后一个表达式的值
false || 0 || '' || null; // null

3.4 三元运算符

三元运算符是JavaScript唯一一个需要三个运算子的运算符。三元运算符的规则是:如果第一个运算子的布尔值为true,返回第二个运算子的值,否则返回第三个运算子的值。

true ? 1 : 2; // 1
false ? 1 : 2; // 2

4. 二进制位运算符

JavaScript中提供了以下位运算符:

  • |,二进制或运算符
  • &,二进制与运算符
  • ~,二进制否运算符
  • ^,异或运算符
  • <<,左移运算符
  • >>,右移运算符
  • >>>,头部补零的右移运算符

位运算符只对整数起作用,如果一个运算子不是整数,会自动转为整数后再执行。另外,在 JavaScript 内部,数值是以64位浮点数的形式储存的,但是在参与位运算的时候,是以32位带符号的整数进行运算的,并且返回值也是一个32位带符号的整数

4.1 二进制或运算符

二进制或运算符(|),逐位比较运算子,两个二进制位中只要有一个为1,就返回1,否则返回0

0 | 4; // 4

上面例子中,04的的二进制形式分别为:000100(只截取了部分,完整的是一个32位的二进制数字),二进制或运算结果为:100,即4。

小数参与位运算时,小数部分会舍去,只保留整数部分参与位运算。所以二进制或运算的一个常用场景是小数取整。

// 定义一个函数,获得整数部分的值
function getIntNumber(x){
	return x | 0;
}

// 调用该函数
getIntNumber(2.3); // 2
getIntNumber(-2.9); // 2

4.2 二进制与运算符

二进制与运算符(&),逐位比较两个运算子,两个二进制位之中只要有一个位为0,就返回0,否则返回1

2 & 3; // 1

4.3 二进制否运算符

二进制否运算符(~)将每个二进制位都变为相反值(0变为11变为0)。

~ 2; // -3

从上面例子看到,一个整数进行二进制否运算,结果并不是简单的改变值正负情况,这是因为计算机内部是使用补码来存储负数的。负数按位取反然后加1就得到补码。
简单的记法就是,一个数与自身的取反值相加等于-1

4.4 异或运算符

异或运算符(^)在两个二进制位不同时返回1,相同时返回0

0 ^ 3; // 3

上述代码中,03的二进制表示为0011,异或的结果为11,即为3。

我曾经碰到过一个面试题,在不引入新变量的前提下,交换变量ab的值。在这里就可以用异或解决。

var a = 3;
var b = 4;
a ^= b;
b ^= a;
a ^= b;
a; // 4
b; // 3

4.5 左移运算符

左移运算符(<<)表示将一个数的二进制值向左移动指定的位数,尾部以0填充,向左移动的时候,最高位的符号位是一起移动的。左移n位,相当于乘以2n次方。
如果左移0位,就相当于将数值转为32位整数,也可以取的一个数的整数部分。

4.6 右移运算符

右移运算符(>>)表示将一个数的二进制值向右移动指定的位数。如果是正数,头部全部补0;如果是负数,头部全部补1

4.7 头部补零的右移运算符

头部补零的右移运算符(>>>)与右移运算符(>>)只有一个差别,就是一个数的二进制形式向右移动时,头部一律补零,而不考虑符号位。

5. 其它运算符

5.1 void运算符

void运算符的作用是执行一个表达式,返回undefined

void(7 +7 ); // undefined

void运算符可以在超链接中插入代码但是不会发生网页跳转。

<a href="javascript: void(document.form.submit())">
  提交
</a>

5.2 逗号运算符

逗号运算符()用于对两个表达式求值,并返回后一个表达式的值。

"x", "y"; // "y"

var x = 0;
var y = (x++, 10);
x // 1
y // 10

6. 参考链接

本博客是自己学习笔记,原文请参考JavaScript教程
如有问题,请及时指出!
欢迎沟通交流,邮箱:jidi_jidi@163.com

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JavaScript运算符详解 的相关文章

随机推荐

  • 论"大数据"时代下的海量数据存储技术

    高清 长周期呈现海量存储需求 高清已经在安防行业全面铺开应用 除了带给用户能够看得更清的良好视觉感受外 对存储容量的需求亦成几何式增长 例如 前端IPC有130W到500W像素 码流也从有2Mbps到8Mbps 而一个130W像素 8Mbp
  • 开源OCR引擎Tesseract-OCR

    Overview Tesseract的OCR引擎最先由HP实验室于1985年开始研发 至1995年时已经成为OCR业内最准确的三款识别引擎之一 然而 HP不久便决定放弃OCR业务 Tesseract也从此尘封 数年以后 HP意识到 与其将
  • VSCode 必装的 10 个高效开发插件

    本文介绍了目前前端开发最受欢迎的开发工具 VSCode 必装的 10 个开发插件 用于大大提高软件开发的效率 VSCode 的基本使用可以参考我的原创视频教程 VSCode 高效开发必装插件 VSCode Visual Studio Cod
  • jquery val() 获取不到值的问题排查

    表单校验用jquery validation 实现 基本功能很快实现 在测试时发现自定义的一个比较开始结束日期的校验不起作用 var begin param val var reg new RegExp g begin begin repl
  • arcgis 9.3 sde 安装 启动服务问题

    1 arcgis 9 3 注册 服务 命令 sdeservice o create d oracle orcl p sde i esri sde 2 启动 sde 服务 报错 3 以上1命令在机器上执行不认 用以下命令 sdeservice
  • 【DevOps-监控】生产环境是如何落地一套全方位的监控系统

    生产环境监控究竟需什么样的功能 我们试想一下 如果部署一个监控系统到生产环境 需要满足哪些功能呢 既然是监控 肯定需要监控我们的主机资源信息包括cpu 内存 网络 磁盘等信息吧 其次还得监控容器的相关资源信息 然后我们可能还需要历史数据 几
  • uni-app vuex全局计时

    功能需求 在A页面进入时候开始计时中间会去到B页面查看数据 但是并没有销毁当前页面 所以计时一直在 直到在B页面提交数据 才结束计时 在根文件夹创建 store文件夹 同时创建index js文件 import Vue from vue i
  • TensorFlow:实战Google深度学习框架(二)实现简单神经网络

    3 4 TensorFlow实现神经网络 3 4 1 TensorFlow游乐场 3 4 2 前向传播 3 4 3 神经网络参数与TensorFlow变量 变量和张量的关系 变量的三个属性 张量 维度 类型 3 4 4通过TensorFlo
  • flask-sqlalchemy插件使用

    1 Flask SQLAlchemy插件的使用 该插件对SQLAlchemy进行了简单的封装 使得我们可以更加简单的使用 初始化数据库 无需导入create engine from flask import Flask from flask
  • win10怎么设置WiFi与有线优先级

    原文 https blog csdn net u010921682 article details 88964982 经过测试 文章中第二种方式有效 不过我的优先级与原文中的不同 我是wifi优先于有线 如下 二 修改 接口跃点数 这个名词
  • Android的中http协议HttpURLConnection中post请求

    public class MainActivity extends AppCompatActivity private TextView textView Override protected void onCreate Bundle sa
  • Idea里面关于时间date报错Unhandled exception: java.text.ParseException的解决方案

    我一直报这个错找不到 结果是因为我导包的原因 idea自动导包导出来是这个 但是咱们需要的是这个 就不报错了
  • Lerna包管理

    认识lerna 导读 本章节主要讲解Lerna是什么 Lerna有什么用 如何使用Lerna进行npm包管理 大厂的Lerna版本管理策略是怎么做的 Lerna是如何实现本地包依赖管理以及底层原理是什么 读者可以带着这些问题去阅读 使学习事
  • 利用jni将Eclipse与C++、Opencv无缝连接

    利用jni将Eclipse与C Opencv无缝连接 博主 w风的季节 日期 2018 4 11 现在越来越多的大学生实验室或者创新项目需要用到将JAVA与C 之间的混合编程 因此本篇就来讲解一下Eclipse中用java写的APP如何将C
  • Spring Boot favicon.ico自定义设置

    做网页的都知道 网页打开后几乎都会有一个favicn的小图标 但是在spring boot中如何设置呢 下面告诉大家一个自定制的方法 非常简单 1 在配置application properties中加入 spring mvc favico
  • 信息熵,信息增益

    信息熵 信息增益 概要 实例一 实例二 概要 信息增益表示得知特征A的信息而使得类Z的信息的不确定性减少的程度 特征A对数据集D的信息增益 G D A 定义为集合的信息熵 H D 与特征A给定条件下D的信息条件熵 H D A 之差 即公式为
  • 机器学习入门-提取文章的主题词 1.jieba.analyse.extract_tags(提取主题词)

    1 jieba analyse extract tags text text必须是一连串的字符串才可以 第一步 进行语料库的读取 第二步 进行分词操作 第三步 载入停用词 同时对分词后的语料库进行停用词的去除 第四步 选取一段文本分词列表
  • 关于ASP.NET邮件发送的学习心得

    ASP net邮件发送是一种非常常见的功能 它可以让我们在网站中实现发送邮件的功能 比如用户注册成功后发送欢迎邮件 或者是找回密码时发送重置密码邮件等等 在学习ASP net邮件发送的过程中 我总结了以下几点心得 一 SMTP服务器的配置
  • 【解决问题】Transaction was marked for rollback only; cannot commit

    问题现象 导入文件的时候直接报错 Transaction was marked for rollback only cannot commit nested exception is org hibernate TransactionExc
  • JavaScript运算符详解

    JavaScript运算符详解 目录 JavaScript运算符详解 1 算术运算符 1 1 加法运算符 1 1 1 基本运算规则 1 1 2 对象的相加 1 2 余数运算符 1 3 自增和自减运算符 1 4 正负数值运算符 1 5 指数运