JavaScript 并不天生难,真正难点在于执行模型、异步机制和对象动态性;undefined 是未赋值的默认状态,null 是主动声明的空值;=== 比 == 更安全;?? 比 || 更精准处理空值;catch 只捕获前一个 Promise 的 rejection;this 由调用方式决定,箭头函数继承外层 this。
JavaScript 并不天生难,但它的“灵活”和“隐式行为”常让人误以为难——真正卡住人的,往往不是语法本身,而是对执行模型、异步机制和对象动态性的误解。
undefined 和 null 总分不清?这不是记不住,是没看到它们在引擎里的真实角色:undefined 是变量声明了但没赋值的默认状态;null 是开发者主动表示“这里本该有值,但现在为空”的信号。类型检查时用 === 比 == 更安全,因为后者会强制转换:
console.log(null == undefined); // true console.log(null === undefined); // false
undefined,不是 null
void 0 是获取原始 undefined 值最可靠的方式(防篡改)??(空值合并)处理可能为 null 或 undefined 的情况,比 || 更精准Promise 链里为什么 catch 捕不到错误?常见错觉:只要最后加个 .catch() 就万事大吉。实际它只捕获前一个 Promise 的 rejection,如果中间某步用了 try/catch 却没 throw,或写了 .then(success, fail) 但 fail 函数内部出错,错误就丢了。
.then().catch() 链式写法,避免在 .then() 的第二个参数里处理错误throw 或返回被 reject 的 Promiseunhandledrejection 事件,能帮你发现漏掉的 Promise 错误this 在回调里总是不对?
根本原因:JavaScript 的 this 不由函数定义位置决定,而由**调用方式**决定。箭头函数没有自己的 this,它继承外层作用域的 this,这是最常用解法:
class Button {
constructor() {
this.label = 'Click me';
}
handleClick() {
console.log(this.label); // 正确输出
}
init() {
// ❌ 普通函数:this 指向 button 元素,不是实例
document.getElementById('btn').onclick = this.handleClick;
// ✅ 箭头函数:this 保持指向实例
document.getElementById('btn').onclick = () => this.handleClick();
// ✅ 或显式绑定
document.getElementById('btn').onclick = this.handleClick.bind(this);
}
}
map)的回调里,this 默认丢失handleClick = () => { ... } 自动绑定,但注意它每次实例化都会创建新函数arguments.callee 或 caller,它们在严格模式下禁用最难的部分不在 API 数量,而在调试时能否快速判断:这个值是从哪来的?这个 this 到底绑在哪?这个 Promise 是被谁 resolve 的?把执行上下文、原型链和微任务队列当成日常排查工具,比死记语法重要得多。