---
title: "JavaScript & TypeScript"
author: "Perrin Yong"
author_profile: https://www.pystone.net/profile/
published_by: "Perrin Yong"
canonical: https://www.pystone.net/notes/javascript-typescript-overview/
type: note
content_role: unspecified
visibility: public
id_stability: rename-stable
source_path: "10-计算机、信息技术与工程/05-游戏图形与运行时/WebGL/JavaScript & TypeScript.md"
content_hash: 909bdccc70243e3d6e092e188fbd75b289bddb686a6eb993be692fd0940ba055
knowledge_version: 224c990773de.5fa8af6e39fa
site_commit: 224c990773de166d23a886306577dd90379529ce
notes_commit: 5fa8af6e39fa3891d1b9b4832bfa6c4e0ecaaf0a
---
```text
本文介绍了JaavScript与TypeScript的基础概念以及互相关系。介绍了两者的核心语法以及差异，并说明 TS 编译时删除类型、按环境保留或降级语法。
```

# JavaScript & TypeScript
**ECMAScript（简称 ES）是一部由 _Ecma International_ 制定的脚本语言规范，文件编号 ECMA-262**。它定义了语言的语法、类型系统、内建对象、错误模型、并发抽象（Promise Jobs）等核心语义，用来保证不同实现之间可以运行同一段脚本代码。

> - **1995 年** Brendan Eich 在 Netscape 浏览器中实现了早期的 _LiveScript/JavaScript_。
> - 为了避免与 Sun 的“Java”商标纠纷，1996 年 Netscape 把这门语言送交标准机构 _ECMA_，双方同意用 **“ECMAScript” 作为标准名称**，浏览器实现继续对外叫 “JavaScript”。

ECMAScript 是 JavaScript 的规范。

| 维度   | JavaScript                     | TypeScript                                                   |
| ---- | ------------------------------ | ------------------------------------------------------------ |
| 核心定位 | *ECMAScript* 标准的脚本语言，动态类型、解释执行 | *JavaScript 的静态类型超集*。在 JS 语法之上加入类型系统、装饰器、枚举、命名空间等，并在编译期做类型检查 |
| 设计目标 | 浏览器脚本、通用运行时语言                  | JS 的_静态类型超集_，为中大型项目提供类型安全                                    |
| 运行方式 | 解释 / JIT 执行                    | 必须先编译为 JS (`tsc`, `esbuild`, `vite`, `webpack`…)             |
| 更新节奏 | ECMAScript 年度规范 (ES2024…)      | TS 每月/季度发版（当前 5.8, 2025-03）                                  |
| 生态依赖 | 浏览器、Node.js、Bun…               | 与 JS 共用生态，编译后 100 % 兼容                                       |

## 代码结构与模块系统
|主题|JavaScript|TypeScript|
|---|---|---|
|文件扩展名|`.js`, `.mjs`, `.cjs`|`.ts`, `.tsx` (React JSX)|
|顶级模块化|**ESM** `import/export`、**CommonJS** `require/module.exports`|完全同 JS；编译器可输出多种模块格式|
|`tsconfig.json`|—|描述编译目标 (`target`)、模块格式 (`module`)、路径别名等|

## 语法与差异

## 1. 代码结构与模块系统

### 1.1 文件后缀

* JS：`*.js` / `*.mjs` / `*.cjs`
* TS：`*.ts` / `*.tsx`（含 React JSX）

### 1.2 模块化语法

* **ES Modules** → `import/export`
* **CommonJS**   → `require/module.exports`
* TS 与 JS 写法一致，但可通过 `tsconfig.json` 选择输出格式

### 1.3 `tsconfig.json` 要点

```jsonc
{
  "target": "es2022",        // 语法下限
  "module": "esnext",        // 模块格式
  "strict": true,            // 全面类型严格模式
  "paths": { "@/*": ["src/*"] }
}
```

---

## 2. 基础语法

### 2.1 变量与作用域

```js
// JavaScript
var oldVar = 1;          // 函数级作用域
let count = 42;          // 块级作用域
const PI = 3.14;         // 只读

// TypeScript（加类型）
let count: number = 42;
```

### 2.2 原始类型

* JS 运行时：`number`, `string`, `boolean`, `undefined`, `null`, `symbol`, `bigint`
* TS 静态补充：`any`, `unknown`, `never`, `void`

### 2.3 运算符 / 流程控制

* 与 C 家族基本一致
* TS 仅做 “**类型是否合理**” 检查，不改变写法

---

## 3. 函数与高阶能力

```js
// JS：无类型限制
function add(a, b) {
  return a + b;
}

// TS：显式标注
function add(a: number, b: number): number {
  return a + b;
}

// 默认 / 剩余参数
function greet(name = 'world', ...extras) {}

// 箭头函数固定 this
const inc = (x: number) => x + 1;

// 泛型（TS 专属）
function identity<T>(value: T): T {
  return value;
}
```

---

## 4. 面向对象（类机制）

### 4.1 类与实例字段

```ts
class Animal {
  // ES2022 公有字段写法
  speed = 0;

  // ① 运行期真正私有
  #id: number;

  // ② 仅编译期私有（旧环境友好）
  private name: string;

  constructor(name: string, id: number) {
    this.name = name;
    this.#id = id;
  }

  move(distance: number = 0) {
    this.speed = distance;
    console.log(`${this.name} moved ${distance}m`);
  }
}
```

### 4.2 高级特性（TS 增强）

* 访问修饰符：`public` (默认) / `private` / `protected` / `readonly`
* 抽象类 & 抽象方法：`abstract class Base { abstract foo(): void }`
* 接口契约：`interface Shape { area(): number }`
* 参数属性速写：`constructor(private id: number) {}`
* 泛型类：`class Box<T> { value: T }`

---

## 5. 类型系统（TS 专属精华）

```ts
// 联合 & 交叉
type ID = number | string;
type Position = { x: number } & { y: number };

// 条件类型
type IsString<T> = T extends string ? 'yes' : 'no';

// 映射类型
type Readonly<T> = { readonly [K in keyof T]: T[K] };

// 模板字面量类型
type Hex = `#${string}`;
```

---

## 6. 异步编程

```ts
// Promise
function fetchData(): Promise<User[]> { ... }

// async / await
async function main() {
  const list = await fetchData();
}

// Axios 响应体泛型
axios.get<User[]>('/api/user');
```


---

## 10. 常用参考

* TypeScript Handbook [https://www.typescriptlang.org/docs/handbook/intro.html](https://www.typescriptlang.org/docs/handbook/intro.html)
* ECMAScript 提案追踪 [https://tc39.es](https://tc39.es)
* TS Playground 在线实验 [https://www.typescriptlang.org/play](https://www.typescriptlang.org/play)


## 其他特性

## 对象字面量
用一对花括号 `{ … }` 当场写出 _键 → 值_ 的映射，马上得到一个对象实例，而 **不** 需要先声明类或构造函数。

```javascript
const user = {
  id: 42,                       // 数值字段
  name: "Perrin",               // 字符串字段
  isAdmin: true,                // 布尔字段
  sayHi() {                     // 函数字面量（方法）
    console.log(`Hi, I’m ${this.name}`);
  }
};
```

* 运行期可增删属性
```js
const p = { x:1, y:2 };
p.z = 3; delete p.x;
```

* 字段值可为函数
```js
do: () => {}
```

| 写法          | 例子                           | 说明                         |
| ----------- | ---------------------------- | -------------------------- |
| **基本键值对**   | `{ a: 1, b: 2 }`             | 冒号左边是键、右边是任何表达式            |
| **简写属性**    | `{ a, b }`                   | 当变量名与键名相同时写一次即可            |
| **方法定义简写**  | `{ calc(x) { return x*2 } }` | 等价于 `calc: function(x){…}` |
| **计算得出的键名** | `{ [prefix + id]: val }`     | 方括号里写表达式，求值后当键             |
| **解构合并**    | `{ ...base, extra: 1 }`      | 扩展运算符 `...` 复制字段           |

常见枚举方式
```js
for (const k in obj) { ... }          // 可遍历原型链 & 可枚举属性
Object.keys(obj)                      // 自有可枚举键数组
Object.getOwnPropertyNames(obj)       // 包含不可枚举
```

**与 类 (class) 的关系**
- `class` 语法本质是语法糖：编译后仍然生成 **函数 (constructor)** 与 **原型对象**。
- 对象字面量适合“一次性数据包”或“配置表”；若需要多个实例共享方法、属性访问控制，则用 `class`。


## 闭包
1. **定义**
   闭包是指**函数与其创建时的词法环境（Lexical Environment）共同组成的实体**。该环境记录了函数在定义位置能够访问的所有变量（包括参数、本地变量及外层作用域变量）。
2. **词法环境与环境记录**
   * 每次执行上下文（函数调用、全局、Eval）会创建一个**环境记录**，存放该上下文的所有标识符绑定。
   * 闭包中的函数对象会持有对其所属环境记录的引用，即使外层函数已返回，环境记录也不会被 GC 回收。
1. **多闭包共享变量**
   同一词法作用域内定义的多个闭包，都会**引用同一个环境记录**，从而可读写同一份变量。修改该变量会影响所有引用它的闭包。

2. **与 C 语言对比**

   * C 语言无内建闭包；要跨函数共享状态，需使用**全局/静态变量**或**显式传递指针/结构体**。
   * JavaScript 通过闭包实现**私有化**且**可多函数共享**的状态管理，无需暴露全局。

### 示例

```javascript
// 外层函数，返回两个闭包
function createPair() {
  let shared = 0;  // 环境记录中的共享变量

  function inc() {
    shared += 1;
    console.log('inc ->', shared);
  }

  function dec() {
    shared -= 1;
    console.log('dec ->', shared);
  }

  return { inc, dec };
}

const { inc, dec } = createPair();

inc(); // inc -> 1
inc(); // inc -> 2
dec(); // dec -> 1
dec(); // dec -> 0
```

* `shared` 变量存在于 `createPair` 的环境记录中。
* `inc` 和 `dec` 两个闭包都捕获并共享同一份 `shared`。
* 对 `shared` 的增减对另一个闭包可见，实现了多闭包之间的状态同步。

## JS与TS面向对象差异与编译方法

## class语法差异
### 1. JavaScript：原型链 + 语法糖

```js
class Animal {
  constructor(name) {
    this.name = name;   // 实例字段
  }
  move(dist = 0) {      // 原型方法（所有实例共享）
    console.log(`${this.name} moved ${dist}m`);
  }
}

class Dog extends Animal {
  bark() {
    console.log('Woof!');
  }
}
```

> **幕后**：`class` 只是把早年的 “构造函数 + prototype” 写法包装得更像 C#/Java。继承时 `Dog.prototype` 会把原型链指向 `Animal.prototype`，调用 `super()` 本质就是执行父构造函数。

---

### 2. TypeScript：在同一套语法上贴“类型安全标签”

```ts
abstract class Animal {
  #id: number;                  // 运行期私有
  protected speed = 0;          // 编译期受保护

  constructor(private name: string, id: number) { // “参数属性”自动赋值 name
    this.#id = id;
  }

  abstract sound(): void;       // 抽象方法

  move(distance: number = 0) {
    this.speed = distance;
    console.log(`${this.name} moved ${distance} m`);
  }
}

class Dog extends Animal {
  sound() { console.log('Woof!'); }
}
```

## TS class 编译过程

### TypeScript 面向对象代码示例

```ts
// file: animal.ts  —— TypeScript 源码
export default class Animal {
  #id: number;          // ECMAScript 私有字段
  private name: string; // TS 私有修饰符（仅编译期检查）
  protected speed = 0;  // 受保护成员

  constructor(id: number, name: string) {
    this.#id = id;
    this.name = name;
  }

  move(distance: number = 0) {
    this.speed = distance;
    console.log(`${this.name} moved ${distance} m`);
  }
}
```


### `target: "es2015"`（**现代浏览器/Node 18+**）

因为运行环境原生支持 `class` 与 `#private` 字段，**TypeScript 只删掉类型信息**，其余几乎原封不动：

```js
// animal.js  —— ES2015 输出
export default class Animal {
    #id;
    name;      // ← 仅保留属性，private 被擦除
    speed = 0;
    constructor(id, name) {
        this.#id = id;
        this.name = name;
    }
    move(distance = 0) {
        this.speed = distance;
        console.log(`${this.name} moved ${distance} m`);
    }
}
```

* `private name` → `name`：**修饰符只存在于 .ts，运行时代码里消失**。
* `#id` 保留：这是 ES 私有字段的语法，浏览器自己支持。

### `target: "es5"`（**老浏览器/IE 仍在时的写法**）

老环境不认识 `class`，编译器会降级为 **立即执行函数 + 原型** 模式：

```js
// animal.js  —— ES5 输出
"use strict";
exports.__esModule = true;
var _id = new WeakMap();       // 用 WeakMap 模拟 #id 私有字段
var Animal = /** @class */ (function () {
    function Animal(id, name) {
        _id.set(this, id);     // 维护私有值
        this.name = name;      // private 修饰符依旧被擦除
        this.speed = 0;
    }
    Animal.prototype.move = function (distance) {
        if (distance === void 0) { distance = 0; }
        this.speed = distance;
        console.log(this.name + " moved " + distance + " m");
    };
    return Animal;
}());
exports["default"] = Animal;
```

 IIFE + 原型链：把 `class` 降级为构造函数

> **IIFE** _Immediately-Invoked Function Expression_：写完就立刻调用自己，用来**制造一个私有作用域**，避免里面的变量泄漏到外面。`...`() 最后那对小括号就是“立刻执行”。


(function () { ... }()):  这是一个 **自执行函数 (IIFE)**，返回值是一个构造函数Animal, 赋给变量 `Animal`。

原型方法 `Animal.prototype.move = function (distance) { ... }`

|元素|说明|
|---|---|
|`Animal.prototype`|**原型对象**：挂在这里的方法会被 **所有实例共享**，节省内存。|
|`move`|方法名。|
|`function (distance) { ... }`|普通匿名函数，实现真正的业务逻辑。|
