JavaScript 基础语法系统学习笔记
前言:为什么JavaScript基础如此重要
JavaScript作为现代Web开发的三大基石之一,其重要性不言而喻。根据2023年Stack Overflow开发者调查,JavaScript连续10年成为最常用的编程语言。但很多开发者在学习框架时遇到瓶颈,究其原因,往往是基础不够牢固。
扎实的JavaScript基础能让你:
- 更容易理解各种框架的设计思想
- 快速定位和解决复杂问题
- 编写更高效、更健壮的代码
- 在技术面试中脱颖而出
“框架会过时,但基础永远重要。” —— 某大厂技术总监
一、变量声明:程序的记忆单元
三种声明方式对比
特性 | var | let | const |
---|---|---|---|
作用域 | 函数作用域 | 块级作用域 | 块级作用域 |
变量提升 | ✅ | ❌ | ❌ |
重复声明 | ✅ | ❌ | ❌ |
重新赋值 | ✅ | ✅ | ❌ |
关键概念解析
变量提升(Hoisting)
console.log(a); // undefined var a = 1; console.log(b); // ReferenceError let b = 2;
暂时性死区(TDZ)
// TDZ开始 console.log(value); // ReferenceError let value = "hello"; // TDZ结束
块级作用域实践
// 问题示例 for (var i = 0; i < 3; i++) { setTimeout(() => console.log(i), 100); // 输出3个3 } // 解决方案 for (let j = 0; j < 3; j++) { setTimeout(() => console.log(j), 100); // 输出0,1,2 }
声明规范建议
- 默认使用
const
- 需要重新赋值的变量用
let
- 避免使用
var
- 常量命名全大写:
const MAX_SIZE = 100
二、数据类型:程序的构建基石
类型系统全景图
graph TD
A[数据类型] --> B[原始类型]
A --> C[引用类型]
B --> D[Number]
B --> E[String]
B --> F[Boolean]
B --> G[Undefined]
B --> H[Null]
B --> I[Symbol]
B --> J[BigInt]
C --> K[Object]
C --> L[Array]
C --> M[Function]
类型判断方法对比
typeof 42; // "number"
typeof "text"; // "string"
typeof true; // "boolean"
typeof undefined; // "undefined"
typeof null; // "object" (历史遗留问题)
typeof {}; // "object"
typeof []; // "object"
typeof Symbol(); // "symbol"
typeof 10n; // "bigint"
// 更准确的数组判断
Array.isArray([]); // true
特殊值注意点
NaN(Not a Number)
NaN === NaN; // false isNaN(NaN); // true Number.isNaN(NaN); // true (更安全)
null vs undefined
undefined
:变量已声明但未赋值null
:开发者主动设置的空值
三、运算符:程序的逻辑工具
运算符优先级表(部分)
优先级 | 运算符 | 描述 |
---|---|---|
1 | () | 分组 |
2 | !, ++ | 逻辑非, 自增 |
3 | *, /, % | 乘除取余 |
4 | +, - | 加减 |
5 | <, <= | 比较 |
6 | == , === | 相等 |
7 | && | 逻辑与 |
8 | || | 逻辑或 |
常见陷阱示例
宽松相等(==)的隐式转换
'' == '0'; // false 0 == ''; // true 0 == '0'; // true false == 'false'; // false false == '0'; // true
短路求值应用
// 设置默认值 const name = user.name || 'Anonymous'; // 条件执行 isLogin && showDashboard();
四、流程控制:程序的执行路径
现代循环优化
数组遍历最佳实践
const arr = [1, 2, 3]; // for...of循环 for (const item of arr) { console.log(item); } // 函数式编程 arr.forEach(item => console.log(item));
标签语句(高级用法)
outerLoop: for (let i = 0; i < 3; i++) { for (let j = 0; j < 3; j++) { if (i === 1 && j === 1) break outerLoop; console.log(i, j); } }
五、类型转换:数据的变形
显式转换最佳实践
// 转字符串
String(123); // "123"
(123).toString(); // "123"
'' + 123; // "123" (隐式)
// 转数字
Number("123"); // 123
parseInt("123px", 10); // 123 (始终指定进制)
parseFloat("3.14.15"); // 3.14
+'42'; // 42
// 转布尔
Boolean(1); // true
!!"text"; // true (双非技巧)
隐式转换规则表
操作符 | 转换规则 |
---|---|
+ | 优先字符串拼接 |
- * / | 优先数字运算 |
== | 复杂类型转换 |
六、最佳实践与常见陷阱
代码规范建议
命名约定
- 变量/函数:驼峰式
calculateTotal
- 类名:帕斯卡式
UserModel
- 常量:全大写
API_KEY
- 变量/函数:驼峰式
防御性编程
// 不好的写法 function printName(user) { console.log(user.name); } // 好的写法 function printName(user) { console.log(user?.name ?? 'Anonymous'); }
常见面试问题
0.1 + 0.2 !== 0.3
如何解决?// 解决方案 (0.1 * 10 + 0.2 * 10) / 10 === 0.3; // true
如何实现深拷贝?
const deepCopy = JSON.parse(JSON.stringify(obj)); // 注意:会丢失函数和Symbol等特殊类型
七、实战应用与练习
购物车计算器
function calculateCart(cartItems) {
return cartItems.reduce(
(total, item) => {
total.subtotal += item.price * item.quantity;
total.items += item.quantity;
return total;
},
{ subtotal: 0, items: 0 }
);
}
// 使用示例
const cart = [
{ name: "iPhone", price: 6999, quantity: 1 },
{ name: "Case", price: 99, quantity: 2 }
];
console.log(calculateCart(cart));
// 输出: { subtotal: 7197, items: 3 }
练习题
实现一个类型判断函数
getType()
,能准确区分数组、null等类型function getType(obj) { if (obj === null) return 'null'; if (Array.isArray(obj)) return 'array'; return typeof obj; }
写一个安全的加法函数,处理各种边界情况
function safeAdd(a, b) { // 你的实现 }
总结与学习建议
学习路线图
- 基础语法 → 2. DOM操作 → 3. 异步编程 → 4. ES6+特性 → 5. 设计模式