---
# System prepended metadata

title: 现代 JavaScript 教程 重要的
tags: [javaScript]

---

# 现代 JavaScript 教程 重要的

##  JavaScript 基础知识
浏览器中嵌入了 JavaScript 引擎，有时也称作“JavaScript 虚拟机”。

不同的引擎有不同的“代号”，例如：

V8 —— Chrome 和 Opera 中的 JavaScript 引擎。
SpiderMonkey —— Firefox 中的 JavaScript 引擎。
……还有其他一些代号，像 “Chakra” 用于 IE，“ChakraCore” 用于 Microsoft Edge，“Nitro” 和 “SquirrelFish” 用于 Safari，等等。

**f12**
開發工具 f12 換行 用shift + enter

**script**
老的 HTML4 标准中，要求 script 标签有 type 特性。通常是 type="text/javascript"

**分號**
javaScript 将换行符理解成“隐式”的分号。这也被称为 自动分号插入。
但最好不要省


**分開寫的原因**
獨立文件的好处是浏览器会下载它，然后将它保存到浏览器的 缓存 中

**use strict**
为了保证旧的功能能够使用，大部分的修改是默认不生效的。你需要一个特殊的指令 —— "use strict" 来明确地激活这些特性

现代 JavaScript 支持 “classes” 和 “modules” —— 高级语言结构（本教程后续章节会讲到），它们会自动启用 use strict

**变量**
三種寫法
![](https://i.imgur.com/1zlylKj.png)

**数据类型**
JavaScript 中的 null 不是一个“对不存在的 object 的引用”或者 “null 指针”。
JavaScript 中的 null 仅仅是一个代表“无”、“空”或“值未知”的特殊值。

undefined 的含义是 未被赋值。
如果一个变量已被声明，但未被赋值，那么它的值就undefined

**用户交互的 3 个浏览器的特定函数**

* alert
显示信息。
* prompt
显示信息要求用户输入文本。点击确定返回文本，点击取消或按下 Esc 键返回 null。
* confirm
显示信息等待用户点击确定或取消。点击确定返回 true，点击取消或按下 Esc 键返回 false。

**类型转换**

数字型转换
`alert( "6" / "2" ); // 3,` string 类型的值被自动转换成 number 类型后进行计算


number 类型转换规则：
值	变成……
* undefined	變成 NaN
* null 變成0
* true 和 false 變成	1 and 0
* string 變成
  去掉首尾空格后的纯数字字符串中含有的数字。如果剩余字符串为空，则转换结果为 0。否则，将会从剩余字符串中“读取”数字。当类型转换出现 error 时返回 NaN。


**请注意**：包含 0 的字符串 "0" 是 true
对 "0" 和只有空格的字符串（比如：" "）进行布尔型转换时，输出结果为 true
alert( Boolean("0") ); // true
alert( Boolean(" ") ); // 空白，也是 true（任何非空字符串都是 true）

**基础运算符**

a % b 的结果是 a 整除 b 的 余数

通常，加号 + 用于求和。
但是如果加号 + 被应用于字符串，它将合并（连接）各个字符串：

**注意**：只要任意一个运算元是字符串，那么另一个运算元也将被转化为字符串。
```
alert( '1' + 2 ); // "12"
alert( 2 + '1' ); // "21"
```
**数字转化，一元运算符 +**
// 转化非数字
alert( +true ); // 1
alert( +"" );   // 0
它的效果和 Number(...) 相同，但是更加简短。

用在
```
let apples = "2";
let oranges = "3";

// 在二元运算符加号起作用之前，所有的值都被转化为了数字
alert( +apples + +oranges ); // 5

// 更长的写法
// alert( Number(apples) + Number(oranges) );//5
```

**字符串比较**
，JavaScript 会使用“字典（dictionary）”或“词典（lexicographical）”顺序进行判定。

换言之，字符串是按字符（母）逐个进行比较的
非真正的字典顺序，而是 Unicode 编码顺序
```
alert( 'Z' > 'A' ); // true
alert( 'Glow' > 'Glee' ); // true
alert( 'Bee' > 'Be' ); // true
```
**不同类型间的比较**
```
alert( '2' > 1 ); // true，字符串 '2' 会被转化为数字 2
alert( '01' == 1 ); // true，字符串 '01' 会被转化为数字 1
```
* 除了严格相等 === 外，其他但凡是有 undefined/null 参与的比较，我们都需要格外小心。
* 除非你非常清楚自己在做什么，否则永远不要使用 >= > < <= 去比较一个可能为 null/undefined 的变量。对于取值可能是 null/undefined 的变量，请按需要分别检查它的取值情况。

**当使用数学式或其他比较方法 < > <= >= 时：**
null/undefined 会被转化为数字：null 被转化为 0，undefined 被转化为 NaN。

下面让我们看看，这些规则会带来什么有趣的现象。同时更重要的是，我们需要从中学会如何远离这些特性带来的“陷阱”。

奇怪的结果：null vs 0
通过比较 null 和 0 可得：

alert( null > 0 );  // (1) false
alert( null == 0 ); // (2) false
alert( null >= 0 ); // (3) true
是的，上面的结果完全打破了你对数学的认识。在最后一行代码显示“null 大于等于 0”的情况下，前两行代码中一定会有一个是正确的，然而事实表明它们的结果都是 false。

为什么会出现这种反常结果，这是因为相等性检查 == 和普通比较符 > < >= <= 的代码逻辑是相互独立的。进行值的比较时，null 会被转化为数字，因此它被转化为了 0。这就是为什么（3）中 null >= 0 返回值是 true，（1）中 null > 0 返回值是 false。

另一方面，undefined 和 null 在相等性检查 == 中不会进行任何的类型转换，它们有自己独立的比较规则，所以除了它们之间互等外，不会等于任何其他的值。这就解释了为什么（2）中 null == 0 会返回 false。


**多个 ‘?’**
```
let age = prompt('age?', 18);

let message = (age < 3) ? 'Hi, baby!' :
  (age < 18) ? 'Hello!' :
  (age < 100) ? 'Greetings!' :
  'What an unusual age!';

alert( message );
```

* 第一个问号检查 age < 3。
* 如果为真 — 返回 'Hi, baby!'。否则，会继续执行冒号 ":" 后的表达式，检查 age < 18。
* 如果为真 — 返回 'Hello!'。否则，会继续执行下一个冒号 ":" 后的表达式，检查 age < 100。
* 如果为真 — 返回 'Greetings!'。否则，会继续执行最后一个冒号 ":" 后面的表达式，返回 'What an unusual age!'。

**'??'**

另一方面，空值合并运算符 ?? 是最近才被添加到 JavaScript 中的，它的出现是因为人们对 || 不太满意。

**它们之间重要的区别是**：

|| 返回第一个 真 值。
?? 返回第一个 已定义的 值。

换句话说，|| 无法区分 false、0、空字符串 "" 和 null/undefined。它们都一样 —— 假值（falsy values）。如果其中任何一个是 || 的第一个参数，那么我们将得到第二个参数作为结果。

?? 首先会检查是否为 null/undefined，发现它不是才會往後

?? 优先级很低
```
// 重要：使用括号
let area = (height ?? 100) * (width ?? 50);
```

?? 与 && 或 || 一起使用
出于安全原因，JavaScript 禁止将 ?? 运算符与 && 和 || 运算符一起使用，除非使用括号明确指定了优先级

總結
?? 它被用于为变量分配默认值

**if**
数字 0、空字符串 ""、null、undefined 和 NaN 都会被转换成 false。因为它们被称为“假值（falsy）”值。
其他值被转换为 true，所以它们被称为“真值（truthy）”。


**while 和 for**

break
跳出循环


continue
继续下一次迭代

continue 指令是 break 的“轻量版”。它不会停掉整个循环。而是停止当前这一次迭代，并强制启动新一轮循环

```
for (let i = 0; i < 10; i++) {

  //如果为真，跳过循环体的剩余部分。
  if (i % 2 == 0) continue;

  alert(i); // 1，然后 3，5，7，9
}
```
**switch**
“case” 分组
```
let a = 3;

switch (a) {
  case 4:
    alert('Right!');
    break;

  case 3: // (*) 下面这两个 case 被分在一组
  case 5:
    alert('Wrong!');
    alert("Why don't you take a math class?");
    break;

  default:
    alert('The result is strange. Really.');
}
```

**函数**

只有在没有局部变量的情况下才会使用外部变量。

如果在函数内部声明了同名变量，那么函数会 遮蔽 外部变量
，不會覆蓋跟更改喔，是遮蔽

一个函数是一个行为，所以函数名通常是动词。
目前有许多优秀的函数名前缀，如 create…、show…、get…、check… 等等。使用它们来提示函数的作用吧

**函数表达式**
跟上面不一樣
上面是
函数声明

函數表達式
```
let sayHi = function() {
  alert( "Hello" );
};
```

**重點**
```
function sayHi() {
  alert( "Hello" );
}

alert( sayHi ); // 显示函数代码
```
在其他编程语言中，只要提到函数的名称都会导致函数的调用执行，但 JavaScript 可不是这样。

在 JavaScript 中，函数是一个值，所以我们可以把它当成值对待。上面代码显示了一段字符串值，即函数的源码

**函数表达式 vs 函数声明**

* 函数表达式是在代码执行到达时被创建，并且仅从那一刻起可用。一旦代码执行到赋值表达式 let sum = function… 的右侧，此时就会开始创建该函数，并且可以从现在开始使用（分配，调用等）。

* 函数声明则不同。在函数声明被定义之前，它就可以被调用。
例如，一个全局函数声明对整个脚本来说都是可见的，无论它被写在这个脚本的哪个位置。这是内部算法的原故。当 JavaScript 准备 运行脚本时，首先会在脚本中寻找全局函数声明，并创建这些函数。我们可以将其视为“初始化阶段”。在处理完所有函数声明后，代码才被执行。所以运行时能够使用这些函数。

**函数声明的另外一个特殊的功能是它们的块级作用域。
严格模式下，当一个函数声明在一个代码块内时，它在该代码块内的任何位置都是可见的。但在代码块外不可见。**

```
let age = prompt("What is your age?", 18);

// 有条件地声明一个函数
if (age < 18) {

  function welcome() {
    alert("Hello!");
  }

} else {

  function welcome() {
    alert("Greetings!");
  }

}

// ……稍后使用
welcome(); // Error: welcome is not defined
```

如果要在外面能用呢

正确的做法是使用函数表达式，并将 welcome 赋值给在 if 外声明的变量，并具有正确的可见性。

```
let age = prompt("What is your age?", 18);

let welcome;

if (age < 18) {

  welcome = function() {
    alert("Hello!");
  };

} else {

  welcome = function() {
    alert("Greetings!");
  };

}

welcome(); // 现在可以了
```
## 測試
完全看不懂 之後再看
https://zh.javascript.info/testing-mocha
## Chrome 中调试(變強在回去看)
**“资源（Sources）”面板**

![](https://i.imgur.com/BorhyVR.png)


**控制台（Console）**
不解釋 都會的

**断点（Breakpoints）**
![](https://i.imgur.com/dGfu3Q5.png)


**Debugger 命令**
![](https://i.imgur.com/e4khaei.png)

**暂停并查看**
![](https://i.imgur.com/oyn56kB.png)
请打开右侧的信息下拉列表（箭头指示出的地方）。这里允许你查看当前的代码状态：

* 察看（Watch） —— 显示任意表达式的当前值。

你可以点击加号 + 然后输入一个表达式。调试器将随时显示它的值，并在执行过程中自动重新计算该表达式。

* 调用栈（Call Stack） —— 显示嵌套的调用链。

此时，调试器正在 hello() 的调用链中，被 index.html 中的一个脚本调用（这里没有函数，因此显示 “anonymous”）

如果你点击了一个堆栈项，调试器将跳到对应的代码处，并且还可以查看其所有变量。

*  作用域（Scope） —— 显示当前的变量。

Local 显示当前函数中的变量，你还可以在源代码中看到它们的值高亮显示了出来。

Global 显示全局变量（不在任何函数中）。

这里还有一个 this 关键字，目前我们还没有学到它，不过我们很快就会学习它了。


###### tags: `javaScript`