Yuan的博客
EN

JavaScript的基础、型别

JavaScript 的资料型别是什么?如何判断?

  1. 两大类:Primitive 与 Object
  • Primitive(原始型别,不可变)

string、number、boolean、null、undefined、bigint、symbol

  • 原始型别 不可变:修改变量 = 重新赋值,而不是修改原值。

  • Object(物件,可变) • 一般 Object • Array • Array.isArray([1, 2, 3]) // true • Function • Object.prototype.toString.call(fn) // [object Function]

  1. 为什么 typeof 容易误导? • typeof null === “object” → 历史遗留 bug • typeof [] === “object” → 分不出数组
  • 最稳的判断:Object.prototype.toString.call(value) 可区分几乎所有类型。

在 JavaScript 当中,==、=== 与 Object.is()的区别

整体结论:

  • 实际开发主用 ===。
  • 需要区分 +0 / -0 和 NaN 时,选 Object.is()。
  • 避免 ==。
console.log(Object.is(+0, -0)); // false
console.log(Object.is(NaN, NaN)); // true

JavaScript null、undefined 与 undeclared 的区别?

  • undefined:已声明,未赋值 → 尚未
  • null:已声明,值为空 → 没有
  • undeclared:未声明 → 不存在

在 JavaScript 中,Map 与 object 的差别?为什么有 object 还需要 Map?

  1. Map 不是 Object 的一种。两者用途不一样:Object 表示数据;Map 表示关联。
  • 需要大量查找/删除/任意类型 key → 用 Map。做映射(ID → 对象,DOM → 状态,缓存、图结构、计数器)
  • 结构化数据 → 用 Object。描述数据结构(用户、订单、配置、表单等)
  1. Object 的 key 是“名字”(string/symbol),Map 的 key 是“真实的引用”(any type)

  2. 原始物件不支援迭代 (iteration),但 Map 物件有

  • forEach(callback)遍历所有键值对。forEach 的本质就是“对每一项执行副作用”。
const users = [
  { first: 'Tom', last: 'Smith' },
  { first: 'Jane', last: 'Doe' },
  { first: 'Lily', last: 'Deng' }
];

users.forEach((user) => {
  user.fullName = `${user.first} ${user.last}`;
});

console.log(users);

输出

[
  { first: 'Tom', last: 'Smith', fullName: 'Tom Smith' },
  { first: 'Jane', last: 'Doe', fullName: 'Jane Doe' },
  { first: 'Lily', last: 'Deng', fullName: 'Lily Deng' }
]
  • for…of,按顺序执行异步任务,并且一旦出错就提前中断。
const urls = [
  '/api/user',
  '/api/orders',
  '/api/notifications'
];

async function fetchSequential() {
  for (const url of urls) {
    try {
      const res = await fetch(url);      // for...of 支持 await
      if (!res.ok) {
        console.log('Failed at:', url);
        break;                           // 可提前中断
      }

      const data = await res.json();
      console.log('Success:', url, data);

    } catch (error) {
      console.log('Error:', url, error);
      break;                             // 可提前中断
    }
  }
}

fetchSequential();
  1. 原始物件的元素没有顺序性,Map 物件则有顺序

  2. Map 提供许多键值对常用的方法,但原始物件没有。因为在 JS 里,“API”指的不是 HTTP API,而是对象提供给你的可调用方法(public interface)map.forEach() 是 Map 的 API

  • set / get / has / delete / clear / size
  • keys / values / entries
  • for…of 直接遍历 Map

请解释 Set、Map、WeakSet 和 WeakMap 的区别?

  • 内存(Memory, RAM)是程序运行时放数据的地方,是你的应用读写最快的存储资源。
  • 带宽(Bandwidth) = 搬运文件的速度
  • DOM = 浏览器呈现网页时生成的一棵“可操作的对象树”。
  1. Set类似数组,但值唯一。接受所有类型(primitive + object)。常用方法:add、delete、has、size。遍历返回[value, value]

  2. WeakSet(Set 的弱引用版本)核心区别:只能存 object。弱引用:对象如果外部没有引用,会被垃圾回收。因此适合做:记录 DOM 节点状态、避免内存泄漏。

  3. Map类似 Object,但:键可以是任何类型。有序。方法丰富:set、get、has、delete、size。遍历方法:keys、values、entries。

  4. WeakMap(Map 的弱引用版本)核心区别:key 只能是 object 或 Symbol。key 也是弱引用:外部引用断开 → 自动被 GC 清理。Map 则不会自动清理(强引用)。用途:存放与 DOM 相关的状态,而不污染 DOM 本体。避免内存泄漏(当 DOM 被移除后,可自动 GC)

  • 弱引用的适用情境在于,如果引用的物件在未来可能会被删除的情况、且不想防止被垃圾回收时,就适合用 WeakMap 或 WeakSet。例如,如果我们想要记录一些与 DOM 节点相关的数据,有一种方法是使用 Expando 扩充节点上的资讯,但坏处是会直接修改到这个 DOM 节点、且如果未来这个节点被移除时,相关资讯不会被垃圾回收掉,这时如果是使用 WeakMap 就会是很好的替代方案。
  • 解释:DOM 需要存状态,因为 UI 有状态。理想做法:把 DOM 当 key,把业务状态放 WeakMap。节点消失 → 状态自动清理,不污染 DOM,也不泄漏内存。

在 JavaScript 中 0.1 + 0.2 会是多少?为什么?如何避免相关问题?

  • 会是 0.30000000000000004
  • 解决方法参考:nstr
//Step 1: Convert to fixed decimal

0.14499999582767487.toFixed(10)  // "0.1449999958"
//Step 2: Detect consecutive patterns

"0.1449999958"
//    ^^^^^
//    5 consecutive "9"s detected (≥ threshold of 4)
//Step 3: Truncate and clean up

"0.1449999958"  "0.145"

严格模式 (use strict) 的用途?有什么好处?

  • 在脚本或函数开头写 “use strict”,让 JavaScript 用更严格、更规范的方式执行。
  1. 禁止未声明变量
"use strict";
x = 10; // 报错:x 未声明
  1. 禁止重复的函数参数名
"use strict";
function sum(a, a) {} // 报错
  1. 禁止删除不可删除的标识符,在 JavaScript 里,变量(var / let / const 声明的东西)本质上都属于不可删除的标识符。
"use strict";
var y = 20;
delete y; // 报错

写程式时该用三元运算子 (ternary operator) 吗?

  • 三元运算子适合“简单条件分支”,不适合“复杂决策树”。一旦逻辑超过一行看不懂,就不要用它。
  • 短路运算&&:如果左边为 falsy → 直接返回左边。如果左边为 truthy → 返回右边