JavaScript编程
字符串连接
+
运算符根据其两个操作数的类型执行不同的操作。如果其中一个或两个操作数是字符串,它将作为字符串连接符。如果两个操作数都是数字,它将作为算术加法运算符。
一个字符串连接的例子是 "one " + "world"
,结果是 "one
world"
。如果其中一个操作数不是字符串,它会在执行 +
操作之前被隐式转换为字符串。
"use strict";
// 常规连接
const word_1 = "one";
const word_2 = "world";
let result = word_1 + " " + word_2;
alert(result); // "one world"
// 隐式类型转换
const arr = [41, 42, 43];
result = word_1 + arr + word_2; // 首先,数组被转换为字符串
alert(result); // "one41,42,43world"
// 同样的情况
const x = 1;
result = x + word_2;
alert(result); // "1world"
算术运算符
JavaScript 提供了算术运算符 +
、-
、*
、/
、%
(余数)和 **
(指数)。这些运算符按你在数学中学到的方式工作。乘法和除法优先于加法和减法计算。如果你希望改变这种优先级,可以使用括号。
提示:与某些其他语言不同,除法操作可能返回浮点数——它并不总是纯整数。
const a = 12 + 5; // 17
const b = 12 - 5; // 7
const c = 12 * 5; // 60
const d = 12 / 5; // 2.4 除法结果是浮点数
const e = 12 % 5; // 2 12 除以 5 的余数是 2
const f = 12 - 2 * 5; // 2 乘法优先计算
const g = (12 - 2) * 5; // 50 括号优先计算
某些数学操作(例如除以零)会导致返回值为错误值——例如,infinity
或 NaN
(不是一个数字)。
余数运算符返回的值保持第一个操作数的符号。
+
和 -
运算符也有一元版本,其中它们只作用于一个变量。以这种方式使用时,+
返回对象的数字表示,而 -
返回它的负数。
"use strict";
const a = 42;
const b = +a; // b 是 42
const c = -a; // c 是 -42
如上所述,+
还作为字符串连接运算符使用:如果任何一个操作数是字符串或是非数字类型,所有操作数会被转换为字符串并连接起来。所有其他算术运算符则相反:它们在计算之前会尝试将其操作数转换为数字。
"use strict";
const a = 42;
const b = "2";
const c = "3";
alert(a + b); // "422" (字符串)
alert(a * b); // 84 (数字)
alert(b * c); // 6 (数字)
位运算符
JavaScript 提供了七个位运算符:&
、|
、^
、~
、>>
、<<
和 >>>
。
这些运算符会将其操作数转换为整数(将任何浮点数截断为 0),并对它们执行指定的按位操作。逻辑按位运算符 &
、|
和 ^
会对每个位执行与、或和异或操作,并返回结果值。~
(取反运算符)会反转整数中的所有位,通常与逻辑按位运算符一起使用。
两个位移运算符 >>
和 <<
会将位移动一个方向,类似于乘以或除以 2 的幂。最后一个位移运算符 >>>
以相同的方式操作,但在位移时不保留符号位。
这些运算符保留是为了与相关编程语言兼容,但在大多数 JavaScript 程序中并不常用。
赋值运算符
赋值运算符 =
用于将一个值赋给变量。原始类型(如字符串和数字)会被直接赋值。然而,函数和对象的名称仅仅是指向相应函数或对象的引用。在这种情况下,赋值运算符只会改变对对象的引用,而不会改变对象本身。例如,以下代码执行后,即使传递的是 array_A
给 alert
,但是 array_B
已经被修改,因此弹出 "0, 1, 0"。这是因为它们是指向同一个对象的两个引用。
"use strict";
const array_A = [0, 1, 2];
const array_B = array_A;
array_B[2] = 0;
alert(array_A); // 0, 1, 0
同样,在接下来的代码片段执行后,x
是指向一个空数组的引用。
"use strict";
const z = [5];
const x = z;
z.pop();
alert(x);
如果算术或位运算符的结果需要赋值给第一个操作数,可以使用更简洁的语法。将运算符(如 +
)直接与赋值运算符 =
结合,得到 +=
等简写形式。例如,x = x + 5
可以简写为 x += 5
。
简写的运算符/赋值语法如下:
算术运算符 | 逻辑运算符 | 移位运算符 |
---|---|---|
+= |
&= |
>>= |
-= |
` | =` |
*= |
^= |
>>> |
/= |
||
%= |
例如,在 for
循环中,+=
的常见用法:
"use strict";
const arr = [1, 2, 3];
let sum = 0;
for (let i = 0; i < arr.length; i++) {
sum += arr[i]; // 等价于:sum = sum + arr[i];
}
alert(sum);
增量运算符
增量和减量运算符是特定的算术运算符:++
和 --
。a++
会先返回 a
的原值,然后将 a
自增。++a
会先将 a
自增,再返回自增后的新值。减量运算符的行为类似,只是将变量减去 1。
例如,以下操作执行相同的任务:
"use strict";
let a = 1;
alert(a); // 1
a = a + 1;
alert(a); // 2
a += 1;
alert(a); // 3
a++;
alert(a); // 4
++a;
alert(a); // 5
// 但这显示的内容不同;请参阅下一章节
alert(a++); // 显示 5
alert(a); // 然而,'a' 已自增到 6
前后增量运算符
增量运算符可以写在变量前面或后面。位置决定了它们是前增量(pre-increment)还是后增量(post-increment)运算符,进而影响操作的执行顺序。
"use strict";
// 增量发生在将 a 赋值给 b 之前
let a = 1;
let b = ++a; // a = 2, b = 2;
// 增量发生在将 c 赋值给 d 之后
let c = 1;
let d = c++; // c = 2, d = 1;
由于前后增量行为可能会造成混淆,建议避免使用增量运算符,代码会更容易阅读。
"use strict";
// 增量发生在将 a 赋值给 b 之前
let a = 1;
a += 1;
let b = a; // a = 2, b = 2;
// 增量发生在将 c 赋值给 d 之后
let c = 1;
let d = c;
c += 1; // c = 2, d = 1;
比较运算符
比较运算符用于判断两个操作数是否满足给定的条件,并返回 true
或 false
。
关于“相等”和“不相等”运算符,需要特别注意。==
与 ===
是不同的。==
尝试将两个操作数的类型转换为相同类型后再进行比较,而 ===
比较的是类型和值,只有当类型和值都相等时,才返回 true
。例如,3 == "0003"
返回 true
,而 3 === "3"
返回 false
。
运算符 | 返回值 | 说明 |
---|---|---|
== |
如果两个操作数相等,则返回 true |
可能会改变操作数的类型(例如将字符串转换为整数) |
=== |
如果两个操作数严格相等,则返回 true |
不改变操作数的类型,只有类型和值都相等时才返回 true |
!= |
如果两个操作数不相等,则返回 true |
可能会改变操作数的类型 |
!== |
如果两个操作数不严格相等,则返回 true |
不改变操作数的类型 |
> |
如果第一个操作数大于第二个操作数,则返回 true |
|
>= |
如果第一个操作数大于或等于第二个操作数,则返回 true |
|
< |
如果第一个操作数小于第二个操作数,则返回 true |
|
<= |
如果第一个操作数小于或等于第二个操作数,则返回 true |
建议使用严格版本的运算符(===
和 !==
),因为简单的版本可能会导致一些奇怪且非直观的情况,例如:
0 == '' // true
0 == '0' // true
false == 'false' // false (''Boolean to string'')
false == '0' // true (''Boolean to string'')
false == undefined // false
false == null // false (''Boolean to null'')
null == undefined // true
而你可能希望的是:
0 === '' // false
0 === '0' // false
false === 'false' // false
false === '0' // false
false === undefined // false
false === null // false
null === undefined // false
逻辑运算符
逻辑运算符包括与 (&&
)、或 (||
) 和非 (!
) 运算符。前两个运算符接受两个布尔操作数,而第三个运算符接受一个布尔操作数并返回其逻辑否定。
操作数是布尔值或能够评估为布尔值的表达式。
"use strict";
const a = 0;
const b = 1;
if (a === 0 && b === 1) { // 逻辑 "与"
alert("a 是 0 并且 b 是 1");
}
if (a === 1 || b === 1) { // 逻辑 "或"
alert("a 是 1 或者 b 是 1");
}
&&
和 ||
是短路运算符:如果第一个操作数的结果已经能够确定最终结果,就会跳过第二个操作数的计算。因此,&&
被称为“保护运算符”,而 ||
被称为“默认运算符”。
"use strict";
// 声明 'myArray' 但不初始化
let myArray;
// 运行时错误!
if (myArray.length > 0) {
alert("数组的长度是: " + myArray.length);
}
// 没有错误,因为 '&&' 后面的部分不会被执行!
if (myArray && myArray.length > 0) {
alert("数组的长度是: " + myArray.length);
}
!
运算符用于取给定布尔值的反值:true
变为 false
,false
变为 true
。
注意:JavaScript 将以下值视为 false
:布尔值 false
、数字 0
、NaN
、空字符串、内建类型 undefined
或 null
。其他任何值都视为 true
。
关于这三个运算符的优先级,!
的优先级最高,其次是 &&
,最后是 ||
。
a || b && !c
| | | |
| | └ 1. ┘
| └───── 2. ───┘
└───────── 3. ───────┘
关于优先级和短路运算的更多细节可以参考 MDN。
其他运算符
? :
(三元运算符)
? :
运算符(也叫做“三元运算符”)是 if
语句的简写。首先,它会评估问号前的部分。如果为 true
,则评估问号和冒号之间的部分并返回,否则评估冒号后面的部分。
const target = (a == b) ? c : d;
使用三元运算符时要小心。虽然你可以用三元运算符替代冗长且复杂的 if/then/else
语句链,但这样做可能不是一个好主意。你可以将以下代码:
if (p && q) {
return a;
} else {
if (r != s) {
return b;
} else {
if (t || !v) {
return c;
} else {
return d;
}
}
}
替换为:
return (p && q) ? a
: (r != s) ? b
: (t || !v) ? c
: d;
然而,上面的例子属于不好的编码风格/做法。当其他人编辑或维护你的代码时(很可能是你自己),它会变得更加难以理解和工作。相反,最好将代码写得更易理解。可以从上述示例中去除一些过度嵌套的条件判断。
if (p && q) {
return a;
}
if (r != s) {
return b;
}
if (t || !v) {
return c;
} else {
return d;
}
delete
delete
运算符用于删除对象的属性。它会删除属性的值和属性本身。删除后,该属性不能再次使用,直到它被重新添加回对象。delete
运算符仅设计用于删除对象的属性,对于变量或函数没有影响。
delete obj.x; // 从对象 obj 中删除属性 x
new
new
运算符用于创建 cl
类型的新对象。cl
操作数必须是一个构造函数。
new cl(); // 创建一个新对象,类型为 cl
instanceof
o instanceof c
用于测试对象 o
是否由构造函数 c
创建。
o instanceof c; // 检查对象 o 是否是由构造函数 c 创建的
typeof
typeof x
返回一个描述变量 x
类型的字符串。可以返回以下值:
类型 | 返回值 |
---|---|
boolean |
"boolean" |
number |
"number" |
string |
"string" |
function |
"function" |
undefined |
"undefined" |
null |
"object" |
其他(如数组等) | "object" |