13 KiB
name 变量名与 window.name
// 假设你想声明一个数字类型的 name
var name = 123;
// 你以为它是数字,但它其实变成了字符串
console.log(typeof name); // 输出: "string" ❌
console.log(name + 1); // 输出: "1231" (字符串拼接,而不是数学加法) ❌
在浏览器中,var name = 123; 实际上等同于 window.name = 123;。而 window.name 是一个内置属性,浏览器在底层会强制调用 String(123),将其变为 "123"。
参考:Window: name property - Web APIs | MDN
交互:alert、prompt 和 confirm
alert("Hello");
result = prompt(title, [default]);
result = confirm(question); // true | false
类型转换
字符串转换
我们也可以显式地调用 String(value) 来将 value 转换为字符串类型:
let value = true;
alert(typeof value); // boolean
value = String(value); // 现在,值是一个字符串形式的 "true"
alert(typeof value); // string
数字型转换
在算术函数和表达式中,会自动进行 number 类型转换。
alert( "6" / "2" ); // 3, string 类型的值被自动转换成 number 类型后进行计算
显式转换。
let str = "123";
alert(typeof str); // string
let num = Number(str); // 变成 number 类型 123
alert(typeof num); // number
Number 类型的转换规则:
| 值 | 变成…… |
|---|---|
undefined |
NaN |
null |
0 |
true 和 false |
1 and 0 |
string |
去掉首尾空白字符(空格、换行符 \n、制表符 \t 等)后的纯数字字符串中含有的数字。如果剩余字符串为空,则转换结果为 0。否则,将会从剩余字符串中“读取”数字。当类型转换出现 error 时返回 NaN。 |
布尔型转换
它发生在逻辑运算中,也可以通过调用 Boolean(value) 显式地进行转换。
转换规则如下:
- 直观上为“空”的值(如
0、空字符串、null、undefined和NaN)将变为false。 - 其他值变成
true。
基础运算符,数学运算
术语:“一元运算符”,“二元运算符”,“运算元”
运算元:比如说乘法运算 5 * 2,有两个运算元:左运算元 5 和右运算元 2。有时候人们也称其为“参数”而不是“运算元”。
如果一个运算符对应的只有一个运算元,那么它是 一元运算符。比如说一元负号运算符(unary negation)-,它的作用是对数字进行正负转换:
let x = 1;
x = -x;
alert( x ); // -1,一元负号运算符生效
如果一个运算符拥有两个运算元,那么它是 二元运算符。减号还存在二元运算符形式:
let x = 1, y = 3;
alert( y - x ); // 2,二元运算符减号做减运算
数学运算
支持以下数学运算:
- 加法
+, - 减法
-, - 乘法
*, - 除法
/, - 取余
%, - 求幂
**.
数字转化,一元运算符 +
加号 + 有两种形式。一种是上面我们刚刚讨论的二元运算符,还有一种是一元运算符。
一元运算符加号,或者说,加号 + 应用于单个值,对数字没有任何作用。但是如果运算元不是数字,加号 + 则会将其转化为数字。
let apples = "2";
let oranges = "3";
alert( apples + oranges ); // "23",二元运算符加号合并字符串
let apples = "2";
let oranges = "3";
// 在二元运算符加号起作用之前,所有的值都被转化为了数字
alert( +apples + +oranges ); // 5
// 更长的写法
// alert( Number(apples) + Number(oranges) ); // 5
逗号运算符
逗号运算符能让我们处理多个表达式,使用 , 将它们分开。每个表达式都运行了,但是只有最后一个的结果会被返回。
let a = (1 + 2, 3 + 4);
alert( a ); // 7(3 + 4 的结果)
// 一行上有三个运算符
for (a = 1, b = 3, c = a * b; a < 10; a++) {
...
}
值的比较
字符串比较
在比较字符串的大小时,JavaScript 会使用 Unicode 编码顺序 顺序进行判定。
换言之,字符串是按字符(母)逐个进行比较的。
例如:
alert( 'Z' > 'A' ); // true
alert( 'Glow' > 'Glee' ); // true
alert( 'Bee' > 'Be' ); // true
字符串的比较算法非常简单:
- 首先比较两个字符串的首位字符大小。
- 如果一方字符较大(或较小),则该字符串大于(或小于)另一个字符串。算法结束。
- 否则,如果两个字符串的首位字符相等,则继续取出两个字符串各自的后一位字符进行比较。
- 重复上述步骤进行比较,直到比较完成某字符串的所有字符为止。
- 如果两个字符串的字符同时用完,那么则判定它们相等,否则未结束(还有未比较的字符)的字符串更大。
不同类型间的比较
当对不同类型的值进行比较时,除了 null 和 undefined,JavaScript 会首先将其转化为数字(number)再判定大小。
alert( '2' > 1 ); // true,字符串 '2' 会被转化为数字 2
alert( '01' == 1 ); // true,字符串 '01' 会被转化为数字 1
alert( true == 1 ); // true
alert( false == 0 ); // true
严格相等
普通的相等性检查 == 存在一个问题,它不能区分出 0 和 false:
alert( 0 == false ); // true
也同样无法区分空字符串和 false:
alert( '' == false ); // true
严格相等运算符 === 在进行比较时不会做任何的类型转换。
alert( 0 === false ); // false,因为被比较值的数据类型不同
null 与 undefined 比较
它们不相等,因为它们属于不同的类型。
alert( null === undefined ); // false
JavaScript 存在一个特殊的规则,会判定它们相等。
alert( null == undefined ); // true
undefined 和 null 在相等性检查 == 中不会进行任何的类型转换,它们有自己独立的比较规则,所以除了它们之间互等外,不会等于任何其他的值。
alert( null > 0 ); // (1) false, null => 0
alert( null == 0 ); // (2) false, null => null
alert( null >= 0 ); // (3) true, null => 0
undefined 与其他值比较
undefined 不应该被与其他值进行比较:
alert( undefined > 0 ); // false
alert( undefined < 0 ); // false
alert( undefined == 0 ); // false
条件分支:if 和 '?'
布尔转换
- 数字
0、空字符串""、null、undefined和NaN都会被转换成false。因为它们被称为“假值(falsy)”。 - 其他值被转换为
true,所以它们被称为“真值(truthy)”。
逻辑运算符
JavaScript 中有四个逻辑运算符:||(或),&&(与),!(非),??(空值合并运算符)。
或运算
或运算:寻找第一个真值或最后一个假值。
一个或运算 || 的链,将返回第一个真值,如果不存在真值,就返回该链的最后一个值。
alert( 1 || 0 ); // 1(1 是真值)
alert( null || 1 ); // 1(1 是第一个真值)
alert( null || 0 || 1 ); // 1(第一个真值)
alert( undefined || null || 0 ); // 0(都是假值,返回最后一个值)
有趣的用法:
let firstName = "";
let lastName = "";
let nickName = "SuperCoder";
alert( firstName || lastName || nickName || "Anonymous"); // SuperCoder
true || alert("not printed");
false || alert("printed");
与运算
与运算:寻找第一个假值或最后一个真值
// 如果第一个操作数是真值,
// 与运算返回第二个操作数:
alert( 1 && 0 ); // 0
alert( 1 && 5 ); // 5
// 如果第一个操作数是假值,
// 与运算将直接返回它。第二个操作数会被忽略
alert( null && 5 ); // null
alert( 0 && "no matter what" ); // 0
alert( 1 && 2 && null && 3 ); // null
alert( 1 && 2 && 3 ); // 3,最后一个值
与运算 && 在或运算 || 之前进行
与运算 && 的优先级比或运算 || 要高。
所以代码 a && b || c && d 跟 && 表达式加了括号完全一样:(a && b) || (c && d)。
!(非)
两个非运算 !! 有时候用来将某个值转化为布尔类型:
alert( !!"non-empty string" ); // true
alert( !!null ); // false
alert( Boolean("non-empty string") ); // true
alert( Boolean(null) ); // false
也就是,第一个非运算将该值转化为布尔类型并取反,第二个非运算再次取反。最后我们就得到了一个任意值到布尔值的转化。
非运算符 ! 的优先级在所有逻辑运算符里面最高,所以它总是在 && 和 || 之前执行。
空值合并运算符 '??'
由于它对待 null 和 undefined 的方式类似,所以在本文中我们将使用一个特殊的术语对其进行表示。为简洁起见,当一个值既不是 null 也不是 undefined 时,我们将其称为“已定义的(defined)”。
a ?? b 的结果是:
- 如果
a是已定义的,则结果为a, - 如果
a不是已定义的,则结果为b。
我们可以使用我们已知的运算符重写 result = a ?? b,像这样:
result = (a !== null && a !== undefined) ? a : b;
与 || 比较
它们之间重要的区别是:
||返回第一个 真 值。??返回第一个 已定义的 值。
let height = 0;
alert(height || 100); // 100
alert(height ?? 100); // 0
"switch" 语句
类型很关键
强调一下,这里的相等是严格相等。被比较的值必须是相同的类型才能进行匹配。
比如,我们来看下面的代码:
let arg = prompt("Enter a value?")
switch (arg) {
case '0':
case '1':
alert( 'One or zero' );
break;
case '2':
alert( 'Two' );
break;
case 3:
alert( 'Never executes!' );
break;
default:
alert( 'An unknown value' )
}
- 在
prompt对话框输入0、1,第一个alert弹出。 - 输入
2,第二个alert弹出。 - 但是输入
3,因为prompt的结果是字符串类型的"3",不严格相等===于数字类型的3,所以case 3不会执行!因此case 3部分是一段无效代码。所以会执行default分支。
函数
function name(parameter1, parameter2, ... parameterN) {
...body...
}
name();
参数默认值
function showMessage(from, text = "no text given") {
alert( from + ": " + text );
}
showMessage("Ann"); // Ann: no text given
function showMessage(from, text = anotherFunction()) {
// anotherFunction() 仅在没有给定 text 时执行
// 其运行结果将成为 text 的值
}
后备的默认参数
有些时候,将参数默认值的设置放在函数执行(相较更后期)而不是函数声明时,也行得通。
我们可以通过将参数与 undefined 进行比较,来检查该参数是否在函数执行期间被传递进来:
function showCount(count) {
// 如果 count 为 undefined 或 null,则提示 "unknown"
alert(count ?? "unknown");
}
showCount(0); // 0
showCount(null); // unknown
showCount(); // unknown
返回值
空值的 return 或没有 return 的函数返回值为 undefined。
function doNothing() { /* 没有代码 */ }
function doNothing() {
return;
// return undefined;
}
alert( doNothing() === undefined ); // true
函数表达式
在 JavaScript 中,函数不是“神奇的语言结构”,而是一种特殊的值。
函数声明语法:
function sayHi() {
alert( "Hello" );
}
alert(sayHi); // 显示函数代码
函数表达式语法:
let sayHi = function() {
alert( "Hello" );
};
alert(sayHi); // 显示函数代码
回调函数
function ask(question, yes, no) {
if (confirm(question)) yes()
else no();
}
function showOk() {
alert( "You agreed." );
}
function showCancel() {
alert( "You canceled the execution." );
}
// 用法:函数 showOk 和 showCancel 被作为参数传入到 ask
ask("Do you agree?", showOk, showCancel);
与函数声明区别
函数表达式是在代码执行到达时被创建,并且仅从那一刻起可用。
函数声明则不同,在函数声明被定义之前,它就可以被调用。这是内部算法的缘故。当 JavaScript 准备 运行脚本时,首先会在脚本中寻找全局函数声明,并创建这些函数。
箭头函数
let func = (arg1, arg2, ..., argN) => expression;
let func = function(arg1, arg2, ..., argN) {
return expression;
};