Files
learning/JavaScript.md
2026-07-06 21:56:17 +08:00

492 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## name 变量名与 window.name
```js
// 假设你想声明一个数字类型的 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](https://developer.mozilla.org/en-US/docs/Web/API/Window/name)
## 交互alert、prompt 和 confirm
```js
alert("Hello");
result = prompt(title, [default]);
result = confirm(question); // true | false
```
## 类型转换
### 字符串转换
我们也可以显式地调用 `String(value)` 来将 value 转换为字符串类型:
```js
let value = true;
alert(typeof value); // boolean
value = String(value); // 现在,值是一个字符串形式的 "true"
alert(typeof value); // string
```
### 数字型转换
在算术函数和表达式中,会自动进行 number 类型转换。
```js
alert( "6" / "2" ); // 3, string 类型的值被自动转换成 number 类型后进行计算
```
显式转换。
```js
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`-`,它的作用是对数字进行正负转换:
```js
let x = 1;
x = -x;
alert( x ); // -1一元负号运算符生效
```
如果一个运算符拥有两个运算元,那么它是 **二元运算符**。减号还存在二元运算符形式:
```js
let x = 1, y = 3;
alert( y - x ); // 2二元运算符减号做减运算
```
### 数学运算
支持以下数学运算:
- 加法 `+`,
- 减法 `-`,
- 乘法 `*`,
- 除法 `/`,
- 取余 `%`,
- 求幂 `**`.
### 数字转化,一元运算符 `+`
加号 `+` 有两种形式。一种是上面我们刚刚讨论的二元运算符,还有一种是一元运算符。
一元运算符加号,或者说,加号 `+` 应用于单个值,对数字没有任何作用。但是如果运算元不是数字,加号 `+` 则会将其转化为数字。
```JS
let apples = "2";
let oranges = "3";
alert( apples + oranges ); // "23",二元运算符加号合并字符串
```
```JS
let apples = "2";
let oranges = "3";
// 在二元运算符加号起作用之前,所有的值都被转化为了数字
alert( +apples + +oranges ); // 5
// 更长的写法
// alert( Number(apples) + Number(oranges) ); // 5
```
### 逗号运算符
逗号运算符能让我们处理多个表达式,使用 , 将它们分开。每个表达式都运行了,但是只有最后一个的结果会被返回。
```js
let a = (1 + 2, 3 + 4);
alert( a ); // 73 + 4 的结果)
// 一行上有三个运算符
for (a = 1, b = 3, c = a * b; a < 10; a++) {
...
}
```
## 值的比较
### 字符串比较
在比较字符串的大小时JavaScript 会使用 **Unicode 编码顺序** 顺序进行判定。
换言之,字符串是按字符(母)逐个进行比较的。
例如:
```javascript
alert( 'Z' > 'A' ); // true
alert( 'Glow' > 'Glee' ); // true
alert( 'Bee' > 'Be' ); // true
```
字符串的比较算法非常简单:
1. 首先比较两个字符串的首位字符大小。
2. 如果一方字符较大(或较小),则该字符串大于(或小于)另一个字符串。算法结束。
3. 否则,如果两个字符串的首位字符相等,则继续取出两个字符串各自的后一位字符进行比较。
4. 重复上述步骤进行比较,直到比较完成某字符串的所有字符为止。
5. 如果两个字符串的字符同时用完,那么则判定它们相等,否则未结束(还有未比较的字符)的字符串更大。
### 不同类型间的比较
当对不同类型的值进行比较时,除了 `null``undefined`JavaScript 会首先将其转化为数字number再判定大小。
```js
alert( '2' > 1 ); // true字符串 '2' 会被转化为数字 2
alert( '01' == 1 ); // true字符串 '01' 会被转化为数字 1
alert( true == 1 ); // true
alert( false == 0 ); // true
```
### 严格相等
普通的相等性检查 `==` 存在一个问题,它不能区分出 `0``false`
```js
alert( 0 == false ); // true
```
也同样无法区分空字符串和 `false`
```javascript
alert( '' == false ); // true
```
**严格相等运算符 `===` 在进行比较时不会做任何的类型转换。**
```js
alert( 0 === false ); // false因为被比较值的数据类型不同
```
### null 与 undefined 比较
它们不相等,因为它们属于不同的类型。
```js
alert( null === undefined ); // false
```
JavaScript 存在一个特殊的规则,会判定它们相等。
```js
alert( null == undefined ); // true
```
`undefined``null` 在相等性检查 `==` 中不会进行任何的类型转换,它们有自己独立的比较规则,所以除了它们之间互等外,不会等于任何其他的值。
```js
alert( null > 0 ); // (1) false, null => 0
alert( null == 0 ); // (2) false, null => null
alert( null >= 0 ); // (3) true, null => 0
```
### undefined 与其他值比较
`undefined` 不应该被与其他值进行比较:
```javascript
alert( undefined > 0 ); // false
alert( undefined < 0 ); // false
alert( undefined == 0 ); // false
```
## 条件分支if 和 '?'
### 布尔转换
- 数字 `0`、空字符串 `""``null``undefined``NaN` 都会被转换成 `false`。因为它们被称为“假值falsy”。
- 其他值被转换为 `true`所以它们被称为“真值truthy”。
## 逻辑运算符
JavaScript 中有四个逻辑运算符:`||`(或),`&&`(与),`!`(非),`??`(空值合并运算符)。
### 或运算
或运算:寻找**第一个真值**或**最后一个假值**。
一个或运算 `||` 的链,将返回第一个真值,如果不存在真值,就返回该链的最后一个值。
```js
alert( 1 || 0 ); // 11 是真值)
alert( null || 1 ); // 11 是第一个真值)
alert( null || 0 || 1 ); // 1第一个真值
alert( undefined || null || 0 ); // 0都是假值返回最后一个值
```
有趣的用法:
```js
let firstName = "";
let lastName = "";
let nickName = "SuperCoder";
alert( firstName || lastName || nickName || "Anonymous"); // SuperCoder
true || alert("not printed");
false || alert("printed");
```
### 与运算
与运算:寻找第一个假值或最后一个真值
```js
// 如果第一个操作数是真值,
// 与运算返回第二个操作数:
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)`
### !(非)
两个非运算 `!!` 有时候用来将某个值转化为布尔类型:
```javascript
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`,像这样:
```javascript
result = (a !== null && a !== undefined) ? a : b;
```
### 与 `||` 比较
它们之间重要的区别是:
- `||` 返回第一个 **真** 值。
- `??` 返回第一个 **已定义的** 值。
```js
let height = 0;
alert(height || 100); // 100
alert(height ?? 100); // 0
```
## "switch" 语句
### 类型很关键
强调一下,这里的相等是严格相等。被比较的值必须是相同的类型才能进行匹配。
比如,我们来看下面的代码:
```js
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' )
}
```
1.`prompt` 对话框输入 `0``1`,第一个 `alert` 弹出。
2. 输入 `2`,第二个 `alert` 弹出。
3. 但是输入 `3`,因为 `prompt` 的结果是字符串类型的 `"3"`,不严格相等 `===` 于数字类型的 `3`,所以 `case 3` 不会执行!因此 `case 3` 部分是一段无效代码。所以会执行 `default` 分支。
## 函数
```js
function name(parameter1, parameter2, ... parameterN) {
...body...
}
name();
```
### 参数默认值
```js
function showMessage(from, text = "no text given") {
alert( from + ": " + text );
}
showMessage("Ann"); // Ann: no text given
```
```js
function showMessage(from, text = anotherFunction()) {
// anotherFunction() 仅在没有给定 text 时执行
// 其运行结果将成为 text 的值
}
```
### 后备的默认参数
有些时候,将参数默认值的设置放在函数执行(相较更后期)而不是函数声明时,也行得通。
我们可以通过将参数与 `undefined` 进行比较,来检查该参数是否在函数执行期间被传递进来:
```js
function showCount(count) {
// 如果 count 为 undefined 或 null则提示 "unknown"
alert(count ?? "unknown");
}
showCount(0); // 0
showCount(null); // unknown
showCount(); // unknown
```
### 返回值
**空值的** `return` **或没有** `return` **的函数返回值为** `undefined`
```js
function doNothing() { /* 没有代码 */ }
function doNothing() {
return;
// return undefined;
}
alert( doNothing() === undefined ); // true
```
## 函数表达式
在 JavaScript 中,函数不是“神奇的语言结构”,而是一种特殊的值。
函数声明语法:
```js
function sayHi() {
alert( "Hello" );
}
alert(sayHi); // 显示函数代码
```
函数表达式语法:
```js
let sayHi = function() {
alert( "Hello" );
};
alert(sayHi); // 显示函数代码
```
### 回调函数
```js
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 准备 运行脚本时,首先会在脚本中寻找全局函数声明,并创建这些函数。
## 箭头函数
```js
let func = (arg1, arg2, ..., argN) => expression;
let func = function(arg1, arg2, ..., argN) {
return expression;
};
```