August 16, 2026 in 编程与软件开发4 minutes
介绍JavaScript基础知识以及常用的浏览器调试代码
JavaScript(简称 JS)是目前世界上最流行的编程语言之一,也是 Web 开发的三大核心技术之一(另外两个是 HTML 和 CSS)。它最初被设计用于浏览器端,实现网页的动态交互,但如今通过 Node.js 等技术,已经发展成为一门全栈语言。
这是编程的基石。现代 JS 推荐使用 let 和 const,尽量避免使用 var(存在变量提升和作用域问题)。
Number: 整数和浮点数(注意精度问题)。String: 文本字符串。Boolean: true / false。Undefined: 声明了但未赋值。Null: 表示“空”或“无”的对象引用。Symbol: ES6 新增,表示独一无二的值。BigInt: 表示任意精度的整数。Object: 键值对集合。Array: 有序列表。Function: 函数也是对象。=== 和 !==,避免使用 ==(会发生隐式类型转换,导致奇怪的结果)。&& (与), || (或), ! (非)。ES2020 新增了 ?? (空值合并运算符) 和 ?. (可选链操作符),极大简化了判空代码。if...else, switch, for, while, for...of (遍历可迭代对象), for...in (遍历对象属性)。JS 中函数是一等公民,可以赋值给变量、作为参数传递、作为返回值。
function add(a, b) { return a + b; }const add = function(a, b) { ... };const add = (a, b) => a + b;
this,它继承外层作用域的 this,这在回调函数中非常有用。map, filter, reduce。JS 是基于原型的面向对象语言,而非基于类(尽管 ES6 引入了 class 语法糖)。
{ name: "Alice", age: 25 }null。这是 JS 继承的基础机制。constructor, extends, super, static 等,但底层仍然是原型链。JS 是单线程语言,通过事件循环处理并发。理解异步是掌握 JS 的关键。
.then().catch()。代表一个异步操作的最终完成或失败。window, location, history, localStorage 等)。💡 提示: JavaScript 是一门“易学难精”的语言。入门很简单,但要写出健壮、高性能、可维护的代码,需要深入理解其底层机制和设计哲学。保持好奇心,多读源码,多写代码,是进阶的不二法门。
这是 JS 代码运行的基石,不理解它就无法理解闭包和变量提升。
var 声明和函数声明。let/const 声明、形参、arguments。var:声明提升到当前作用域顶部,初始化为 undefined。let/const:声明也提升,但进入暂时性死区,在赋值前访问会报错 ReferenceError。function:整体提升(严格模式下块级作用域内除外)。this 永远不指向函数本身,也不一定指向定义时的对象。它的值完全取决于调用方式。
| 调用方式 | this 指向 | 示例 |
|---|---|---|
| 默认绑定 | 非严格模式: window/global; 严格模式: undefined |
foo() |
| 隐式绑定 | 调用该函数的直接对象 | obj.foo() → obj |
| 显式绑定 | call/apply/bind 指定的对象 |
foo.call(obj) → obj |
| new 绑定 | 新创建的实例对象 | new Foo() → 新对象 |
| 箭头函数 | 无自己的 this,继承外层词法作用域的 this | (a) => this.x |
⚠️ 经典陷阱: 隐式绑定丢失。当把对象方法赋值给变量或作为回调传递时,
this会退化为默认绑定。解决方案:使用bind或箭头函数包裹。
ES6 的 class 只是语法糖,底层依然是原型链。
Constructor.prototype → 构造函数的原型对象Object.__proto__ → 实例的原型指针(指向 Constructor.prototype)Constructor.prototype.constructor → 指回构造函数自身obj.prop 时,先在自身找;没有则沿 __proto__ 向上找;直到 null。obj.hasOwnProperty('x'): 仅检查自身。'x' in obj: 检查自身 + 整个原型链。prototype.__proto__ 指向父类的 prototype。这就是为什么子类实例能调用父类方法。JS 单线程却能处理高并发,全靠 Event Loop。
setTimeout, setInterval, I/O, UI rendering, script 标签。Promise.then/catch/finally, MutationObserver, queueMicrotask。💡 关键结论: 微任务优先级高于宏任务。
Promise.then的回调总是在下一个setTimeout之前执行。
闭包 = 函数 + 其词法环境的引用。
JS 是弱类型语言,隐式转换是 bug 的重灾区。
[Symbol.toPrimitive],然后 valueOf(),最后 toString()。日期对象例外,优先 toString()。null == undefined → true(特例)。true→1, false→0)。===。Number(), String(), Boolean()。NaN !== NaN,用 Number.isNaN() 判断。typeof null === 'object'(历史遗留 bug)。如果你能清晰解释以下问题,说明基础已经扎实:
var a = {n: 1}; var b = a; a.x = a = {n: 2}; console.log(a.x, b.x); 输出什么?为什么?for(var i=0; i<5; i++) setTimeout(()=>console.log(i), 0) 输出什么?如何用三种方式修复?new 操作符具体做了哪几步?手写一个 myNew 实现。浏览器开发者工具(DevTools)的 Console 不仅仅是 console.log 的输出窗口,它本身就是一个强大的交互式调试 REPL 环境。掌握以下命令和技巧,可以大幅提升调试效率。
告别满屏的 console.log,使用更语义化的方法:
| 方法 | 用途 | 示例 |
|---|---|---|
console.table() |
以表格形式展示数组/对象 | console.table(users) |
console.group() / groupEnd() |
将日志分组折叠 | 嵌套逻辑调试 |
console.time() / timeEnd() |
测量代码执行耗时 | console.time('fetch'); ...; console.timeEnd('fetch') |
console.count() |
统计调用次数 | 循环/回调触发频率 |
console.trace() |
打印完整调用栈 | 追踪函数是谁调用的 |
console.assert() |
条件为 false 时才输出 | assert(user.id, 'User must have id') |
console.dir() |
以可交互树形显示对象属性 | 查看 DOM 节点原始属性 |
💡 高级格式化:
console.log支持占位符:%s(字符串),%d(数字),%o(对象),%c(CSS样式)。 例如:console.log('%c Error ', 'background:red;color:white', errorMsg)
这些是 DevTools 专属的全局函数,仅在控制台可用,不会污染你的业务代码:
$(selector):等价于 document.querySelector(selector),返回第一个匹配元素。$$(selector):等价于 document.querySelectorAll(selector),返回数组(可直接 .map/.filter)。$0 ~ $4:引用你在 Elements 面板中最近选中的 5 个 DOM 节点。$0 是当前选中项。copy(value):将任意值序列化后复制到剪贴板。调试时提取数据的神器。
copy(document.querySelectorAll('a[href]')) // 复制所有链接
copy({name: 'test', data: [1,2,3]}) // 复制JSON
inspect(object):在 Elements/Network 等面板中定位并高亮该对象。getEventListeners(element):获取绑定在元素上的所有事件监听器(含来源文件和行号)。排查事件冲突必备。monitorEvents(element, eventType?) / unmonitorEvents():实时监控元素上触发的事件并打印到控制台。
monitorEvents($0, ['click', 'input']) // 监控当前选中元素的点击和输入
queryObjects(Constructor):查找内存中由指定构造函数创建的所有存活实例。用于排查内存泄漏。
queryObjects(Promise) // 找出所有未GC的Promise实例
fetch 直接调试: Console 中可直接发请求测试 API:
const res = await fetch('/api/user', {headers: {'X-Token': 'xxx'}});
const data = await res.json();
console.table(data);localStorage / sessionStorage:直接当作对象读写。cookieStore.get() / .set() / .delete():现代异步 Cookie API(比 document.cookie 好用得多)。localStorage.clear()。performance.mark(name) / measure(name, start, end):在代码中打点,Performance 面板可视化查看。profile() / profileEnd():编程式启动/停止 CPU Profiling(等同于点击 Performance 面板的录制按钮)。debug(fn):当指定函数被调用时自动断点。比手动找源码打断点快得多。
debug(app.render) // render被调用时自动暂停
undebug(app.render) // 取消
monitor(fn):函数被调用时打印参数和返回值(不中断执行)。user.id === 123),仅条件为真时暂停。避免在循环中疯狂按继续。debug()、monitor()、monitorEvents() 等注入的钩子。选元素用
$0,拷数据用copy; 查事件getEventListeners,测耗时time/timeEnd; 自动断点debug(fn),表格展示table; 条件断点省时间,DOM 断点抓篡改。
建议打开任意网站,在 Console 中逐一实操以上命令,形成肌肉记忆。熟练后调试效率可提升数倍。