第一章: JavaScript 核心语法:构建坚实基础
第一章: JavaScript 核心语法:构建坚实基础
Prorise第一章: JavaScript 核心语法:构建坚实基础
摘要: 本章将是您 JavaScript 学习之旅的坚实起点。我们不会重复您已熟知的编程常识,而是直击 JavaScript 的核心特性与差异点,如果是完全从零基础,或是如果您对第一章还有看不懂的知识,请您去稍微的补充您的编程基础,但相信我这并不是很难的事情!您将了解到现代 JS 的语言构成与技术生态,深入探讨 let
与 const
为何能取代 var
,并揭示 JS 独有的数据类型与“臭名昭著”的隐式类型转换机制。学完本章,您将对 JavaScript 的底层行为有更深刻的理解,为后续学习打下坚不可摧的基础。
注意: 阅读本笔记的重要前提是对于 JS 的最基础的语法要有一定的认知,包括运算符、函数、基本数据类型,只需要对于最基础的内容有所认知即可
在本章中,我们将聚焦于 JavaScript 的独特之处:
- 首先,我们将快速了解 JavaScript 的构成与标准,明确学习的重点。
- 接着,我们将深入
var
的历史遗留问题——变量提升,并理解为何let
和const
是现代 JS 的必然选择。 - 然后,我们将辨析 JS 特有的 数据类型,并剖析最关键的“陷阱”——隐式类型转换。
- 最后,我们将跳过基础语法,仅探讨 JS 中 运算符与流程控制的特殊行为,例如
==
与===
的本质区别,以及for...in
与for...of
的正确用法。
1.1. 初识 JavaScript:语言构成与现代标准
技术背景: JavaScript(简称 JS)诞生于 1995 年,它与 Java 并无直接的血缘关系,是网景公司为了让浏览器处理动态交互而设计的脚本语言。发展至今,它已成为构建现代 Web 应用不可或缺的核心技术。
一份完整的 JavaScript 实现由三个不同部分组成:
- 核心 (ECMAScript): 由
ECMA-262
规范定义,提供核心语言功能。我们通常所说的 ES5, ES6 (ECMAScript 2015), ES2025 等版本,就是指这个核心语法的标准。在 2025 年,ES6+ 已是行业开发标准。 - 文档对象模型 (DOM): 提供与网页内容(HTML 文档)交互的接口。
- 浏览器对象模型 (BOM): 提供与浏览器窗口交互的接口。
解决方案: 在现代 Web 开发中,我们推荐将 JavaScript 代码分离到独立的 .js
文件中,并通过 <script>
标签引入,这是维护代码整洁和可复用性的最佳实践。
场景
任何规模项目,行业标准。
优势
- 关注点分离:HTML、CSS、JS 互不干扰
- 可维护:逻辑集中,易改易调
- 性能好:浏览器可缓存
.js
scripts/main.js
1 | console.log('Hello from an external file!'); |
index.html
1 | <script src="scripts/main.js"></script> |
场景
一次性、与页面高度耦合的临时脚本。
劣势
- 代码混杂:破坏结构清晰度
- 无法复用:其他页面无法共享
1 | <script> |
注意:带 src
的 <script>
标签内部若再写代码会被忽略。
1.2. 变量与常量:let
、const
的时代与 var
的历史包袱
在上一节,我们了解了 JS 的基本构成。现在,我们来看编程的第一步:变量。您可能熟悉其他语言的变量声明,但在 JS 中,这是一个有“历史”的话题,也是理解其底层行为的关键。
痛点背景: 在 ES6 (2015) 之前,JavaScript 只有 var
一种声明变量的方式。var
存在一个与其他主流语言(如 Java, Python)截然不同的特性——变量提升 (Hoisting)。这会导致代码行为违反直觉,是许多早期 JS bug 的根源。
看下面的代码,在 Java 或 Python 中,这会直接抛出“变量未定义”的错误。但在 JavaScript 中…
1 | function hoistingTest() { |
1
2
undefined
Hello, Prorise!
解决方案: 为了解决 变量提升 以及 var
带来的其他作用域问题,ES6 引入了 let
和 const
。它们使用 块级作用域 (Block Scope),行为更符合预期,并且 let
声明的变量在声明前访问会直接报错,这被称为 暂时性死区 (Temporal Dead Zone, TDZ),从根本上杜绝了变量提升带来的问题。
1 | function blockScopeTest() { |
1
2
Cannot access 'myLet' before initialization
Hello, Modern JS!
2025 年最佳实践:
- 停止使用
var
。 - 默认使用
const
声明变量,这能确保变量不被重新赋值,增强代码的稳定性和可预测性。 - 只在确定变量需要被重新赋值时,才使用
let
。
1.3. 数据类型:掌握程序的基石
JavaScript 的数据类型分为两大类:原始类型和引用类型。这个划分对其内存分配和变量赋值行为有着深远影响,本小节我们仅作为了解,在后续的章节我们会对于每一个数据类型进行深入剖析
类型:原始类型
特点:不可变文本序列
1 | const str = 'Hello'; |
类型:原始类型
特点:所有数字(含整数、浮点、NaN、Infinity)
1 | const n = 42; |
类型:原始类型
特点:true
或 false
1 | const b = true; |
类型:原始类型
特点:表示“空对象引用”,历史原因导致 typeof null === 'object'
1 | const val = null; |
类型:原始类型
特点:声明但未赋值的默认结果
1 | let u; |
类型:原始类型 (ES6)
特点:唯一、不可变标识符
1 | const sym = Symbol('id'); |
类型:原始类型 (ES2020)
特点:任意精度整数
1 | const big = 9007199254740993n; |
类型:引用类型
特点:键值对集合,属性可变
1 | const obj = { name: 'Prorise' }; |
类型:引用类型(特殊 Object)
特点:有序数据集合
1 | const arr = [1, 2, 3]; |
类型:引用类型(特殊 Object,可调用)
特点:可执行代码块,一等公民
1 | const fn = () => console.log('hi'); |
类型:引用类型
特点:Date、RegExp(正则表达式)、Map、Set 等
1 | const date = new Date(); |
1.4. 深度解析:类型转换与隐式强制的“陷阱”
这是 JavaScript 与 Java、Python 等语言最大的区别之一,也是面试中的高频考点。JavaScript 是一门 弱类型 语言,在运算时会自动进行类型转换,这个过程被称为 隐式强制类型转换 。虽然这提供了灵活性,但也埋下了很多“陷阱”。
痛点背景: 观察以下代码,其结果在强类型语言中是不可想象的,但在 JS 中却真实发生。
1 | console.log(`'5' - 1 = ${'5' - 1}`); |
1
2
3
4
5
'5' - 1 = 4
'5' + 1 = 51
true + 1 = 2
' ' == 0 is true
null == undefined is true
一、==
vs ===
:核心区别
===
严格相等:不做任何类型转换,只要类型或值不同就返回false
。==
宽松相等:先按隐式规则把两边转成同一类型,再比较值。规则复杂、结果难预测,99 % 的场景请用===
。
1 | '1' === 1 // false (类型不同) |
二、算术 / 拼接运算符的隐式转换
- 加法
+
:只要有一个操作数是字符串,就执行 字符串拼接。 - 其余
-
、*
、/
、%
:两边都尽量 转成数字 再运算。
1 | '10' + 5 // "105" |
三、实战建议
- 比较时始终 优先使用
===
。 - 运算或比较前 主动显式转换,避免依赖隐式规则。
- 判断“空”时,用
value == null
可一次性覆盖null
与undefined
,这是少数==
比===
更简洁且不易出错的场景。
1.5. 运算符与流程控制中的 JS 特性
您已经熟悉了大多数运算符和流程控制结构。这里我们仅聚焦于 JavaScript 中行为独特且常用的部分。在 Java 或 Python 中,逻辑运算符 &&
和 ||
通常返回布尔值。但在 JavaScript 中,它们返回的是决定了整个表达式结果的那个 操作数的值,这种特性被称为 短路求值
expr1 && expr2
: 如果expr1
能被转换为false
值,则返回expr1
的值,否则返回expr2
的值。expr1 || expr2
: 如果expr1
能被转换为true
值,则返回expr1
的值,否则返回expr2
的值。
实战场景: 这种行为常被用于设置函数参数的默认值或执行条件代码。
1 | // 场景 1: 设置默认值 |
1
2
3
Hello, Prorise!
Hello, Guest!
Admin panel functions loaded.
JavaScript 提供了两种独特的 for
循环变体来遍历数据结构,它们的用途完全不同。
for...in
: 遍历对象的可枚举属性名 (key)。它主要用于遍历普通对象。不推荐用它来遍历数组,因为它会遍历到数组原型链上的属性,且顺序无法保证。for...of
(ES6 新增): 遍历可迭代 (Iterable) 对象的值 (value)。这是遍历数组、字符串、Map、Set 等数据结构的 推荐方式。
1 | const user = { |
1
2
3
4
5
6
7
8
--- for...in (Object) ---
name: Prorise
role: Admin
--- for...of (Array) ---
read
write
execute
1.6. 本章核心速查与高频面试题
核心速查总结
分类 | 关键项 | 核心描述 |
---|---|---|
变量声明 | let , const | (推荐) 块级作用域,无变量提升,存在暂时性死区。 |
var | (废弃) 函数作用域,存在变量提升,易导致意外行为。 | |
核心区别 | 原始类型 vs 引用类型 | 赋值时,前者复制值,后者复制引用(内存地址)。 |
相等比较 | === (严格相等) | (推荐) 不进行类型转换,同时比较类型和值。 |
== (宽松相等) | (慎用) 会进行隐式类型转换,规则复杂,易出错。 | |
类型转换 | Falsy 值 | false , 0 , "" , null , undefined , NaN 。这 6 个值转为布尔为 false 。 |
循环遍历 | for...of | (推荐) 用于遍历数组、字符串等可迭代对象的值。 |
for...in | 用于遍历对象的键(属性名)。 |