> For the complete documentation index, see [llms.txt](https://jaimecheng.gitbook.io/javascript/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://jaimecheng.gitbook.io/javascript/content/chapter03.md).

# 3. JavaScript 基本概念

## 基本概念    <a href="#basics" id="basics"></a>

* 标识符、关键字、操作符、语句、函数；
* ECMAScript的一切（变量、函数名和操作符）都区分大小写；
* 语句末尾建议加 `;`，某些情况增进代码性能；
* var未初始化的变量会保存一个特殊的值；
* 一条语句定义多个变量，用 `,` 分隔开；

## 数据类型    <a href="#data-types" id="data-types"></a>

* 基本数据类型
  * **Undefined**
  * **Null**
  * **Number**
  * **Boolean**
  * **String**
* 复杂数据类型
  * **Object**
* ES6新增
* 数据类型见[详解](/javascript/datatype.md)

## `typeof`操作符    <a href="#typeof" id="typeof"></a>

* `typeof null`返回值；
* 从技术角度讲，函数在 ES 中是对象，不是一种数据类型。然而，函数也确实有一些特殊的属性，因此通过 `typeof` 操作符来区分函数和其他对象是有必要的；

## 操作符    <a href="#operators" id="operators"></a>

* 一元操作符：`a++` 和 `++a` 的重要区别，联想记忆看顺序变量在前就先用再计算 `++`；
* 布尔操作符：
  * 逻辑非 `!` ：`!!变量` 等同于 `Boolean(变量)` 用于将一个值转换为与其对应的布尔值；
  * 逻辑与 `&&`：逻辑与属于短路操作，即如果第一个操作数能够决定结果 `false`，那么就不会再对第二个操作数求值；
  * 逻辑或 `||`：逻辑或也是短路操作符。也就是说，如果第一个操作数的求值结果为 `true`，就不会对第二个操作数求值了,可以利用逻辑或的这一行为来避免为变量赋 `null` 或 `undefined` 值；
  * ```javascript
    var myObject = preferredObject || backupObject;
    ```
  * 逻辑与和逻辑或运算的返回值不是true和false.而是和true或false等价的原值；
* 乘性操作符：`*`，`/`，`%` ；
* 加性操作符：`+`，`-` ；
* 关系操作符：`>`，`<`，`>=`，`<=` ；
* 相等操作符：`==`，`!=`，`===`，`!==` ；
* 条件操作符：`variable = boolean_expression ? true_value : false_value` ；
* 赋值操作符：`=`，复合赋值操作符；
* 逗号操作符：
  * `var num1=1, num2=2, num3=3;`，可执行多条语句；
  * `var num = (5, 1, 4, 8, 0); // num的值为0`，赋值时用最后一项，这种写法不常用；
* 位操作符：`~`，`&`，`|`，`^`，`<<`，`>>`，`>>>` ；
* 操作符特殊规则见[附录](/javascript/appendix/operator-rules.md)；

## 语句    <a href="#statements" id="statements"></a>

* **if**语句；
* **do-while**语句，后测试循环语句，在对条件表达式求值之前，循环体内的代码至少会被执行一次；
* **while**语句，前测试循环语句，在循环体内的代码被执行之前，就会对出口条件求值，循环体内的代码有可能永远不会被执行；
* **for**语句，`i++`  其实相当于while循环结束之前的最后一句执行，使用 `while` 循环做不到的，使用 `for` 循环同样也做不到；
* **for-in**语句，是一种精准的迭代语句，可以用来枚举对象的属性；
* **label**语句，`label: statement`，可以在代码中添加标签，以便将来使用，常搭配嵌套循环语句；
* **break**语句，立即退出循环， 强制继续执行循环后面的语句；
* **continue**语句，退出循环，但退出循环后会从循环的顶 部继续执行；
* **with**语句，目的主要是为了简化多次编写同一个对象的工作，大量使用 `with` 语句会导致性能下降，在开发大型应用程序时，不建议使用 `with` 语句，严格模式不允许使用 `with` 语句；
* **switch**语句，每一种情形 `case` 的含义是:“如果表达式等于这个值 `value`，则执行后面的 语句(statement)”。而 `break` 关键字会导致代码执行流跳出 `switch` 语句。如果省略 `break` 关键字， 就会导致执行完当前 `case` 后，继续执行下一个 `case`。最后的 `default` 关键字则用于在表达式不匹配前 面任何一种情形的时候，执行机动代码(因此，也相当于一个 `else` 语句)；
* 各语句详解见[示例](/javascript/quiz/statement.md)；

## 函数    <a href="#function" id="function"></a>

* 理解参数，可传递任意数量、类型参数，原因是 ECMAScript 中的参数在内部是用一个数组来表示的，在函数体内可以通过类数组 `arguments` 对象来 访问这个参数数组，获取传递给函数的每一参数。`arguments` 对象的 `length` 属性可以获知有多少个参数传递给了函数；
* 非严格模式下，`arguments` 和命名参数的值保持同步，但内存空间独立，没有传递值的参数自动赋予`undefined`，如果只传入了一个参数，那么为 `arguments[1]` 设置的值不会反应到命名参数中。这是因为 `arguments` 对象的长度是由传入的参数个数决定的，即多余的 `arguments` 会被忽略；

  ```javascript
  function add (num1, num2) {
    arguments[1] = 10;
    return num1 + num2;
  }
  add(2,3) // 12
  add(2) // NaN

  function fnArguments2(a,b,c){
    console.log(arguments.length);    // 2，arguments中自动获取的是实参个数，和形参无关。
  }
  fnArguments2(1,2);
  ```
* 严格模式下，`arguments[1]`设置值，命名参数的值仍然还是 `undefined`。其次，重写 `arguments` 的值会导致语法错误(代码将不会执行)；
* ECMAScript中的所有参数传递的都是值，不可能通过引用传递参数；
* 实际上，未指定返回值的函数返回的是一个特殊的 `undefined` 值；
* 由于不存在函数签名的特性，ECMAScript函数不能被重载，命名相同只会被后来的覆盖；
* 函数详解见[Function专题](/javascript/reference/function.md)；
