JavaScript运算符与函数详解:从基础到高阶应用
JavaScript 运算符与函数深度解析:从基础到高阶应用
一、运算符与表达式
1. 算术、比较与逻辑运算符
JavaScript 提供了丰富的运算符用于各种计算和逻辑操作:
// 算术运算符
console.log(10 + 20); // 加法
console.log(30 - 10); // 减法
console.log(2 ** 3); // 指数运算 (ES2016)
// 比较运算符
console.log(5 == '5'); // true (宽松相等)
console.log(5 === '5'); // false (严格相等)
// 逻辑运算符
const isValid = true;
const isActive = false;
console.log(isValid && isActive); // AND
console.log(isValid || isActive); // OR
实践建议:
- 始终使用
===
代替==
以避免类型转换带来的意外行为 - 对于数学运算,注意浮点数精度问题(如
0.1 + 0.2 !== 0.3
)
2. 解构赋值(数组/对象)
解构赋值是从数组或对象中提取值的简洁语法:
// 数组解构
const [first, , third] = [1, 2, 3];
console.log(first, third); // 1, 3
// 对象解构
const { name, age } = { name: 'Alice', age: 25 };
console.log(name, age); // Alice 25
// 函数参数解构
function greet({ name, age }) {
return `Hello, ${name}! You are ${age} years old.`;
}
实践建议:
- 解构时可以为缺失值设置默认值:
const { name = 'Unknown' } = {}
- 嵌套解构时注意结构匹配,避免
undefined
错误
3. 可选链与空值合并
ES2020 引入的两个重要操作符:
// 可选链操作符 (?.)
const street = user?.address?.street; // 不会抛出错误
// 空值合并操作符 (??)
const displayName = username ?? 'Guest'; // 仅在 null/undefined 时使用默认值
实践建议:
- 替代冗长的
&&
链式检查(如a && a.b && a.b.c
) ??
与||
不同,它不会对 falsy 值(如 0、'')进行默认值替换
二、函数进阶
1. 函数声明 vs 函数表达式
// 函数声明 (会提升)
function sum(a, b) {
return a + b;
}
// 函数表达式 (不会提升)
const multiply = function(a, b) {
return a * b;
};
实践建议:
- 优先使用函数表达式以保持代码结构一致性
- 需要提升特性时(如递归调用)使用函数声明
2. 箭头函数与 this 绑定
const person = {
name: 'Bob',
traditionalGreet: function() {
console.log('Hello, ' + this.name);
},
arrowGreet: () => {
console.log('Hello, ' + this.name); // this 指向外层作用域
}
};
实践建议:
- 箭头函数适合简短的回调函数(如数组方法)
- 需要动态
this
的场景(如事件处理)使用传统函数
3. 默认参数与剩余参数
// 默认参数
function createUser(name, role = 'user') {
// ...
}
// 剩余参数
function sum(...numbers) {
return numbers.reduce((acc, num) => acc + num, 0);
}
实践建议:
- 默认参数应放在参数列表末尾
- 剩余参数替代过时的
arguments
对象
4. 高阶函数应用
// map 示例
const numbers = [1, 2, 3];
const squares = numbers.map(x => x * x);
// filter 示例
const evens = numbers.filter(x => x % 2 === 0);
// reduce 示例
const total = numbers.reduce((sum, num) => sum + num, 0);
实践建议:
- 链式调用时注意中间数组创建带来的性能影响
- 复杂操作可分解为多个步骤提高可读性
三、对象与原型
1. 属性描述符
const obj = {};
Object.defineProperty(obj, 'readOnlyProp', {
value: 42,
writable: false,
enumerable: true
});
实践建议:
- 使用
Object.freeze()
创建不可变对象 - 谨慎使用
enumerable: false
避免影响序列化
2. 原型继承
实践建议:
- 优先使用
class
语法而非直接操作原型链 Object.create(null)
创建无原型的纯净对象
3. class 语法
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a noise.`);
}
}
class Dog extends Animal {
speak() {
super.speak();
console.log(`${this.name} barks.`);
}
}
实践建议:
- 静态方法适合工具函数而非实例相关操作
- 私有字段(ES2022)使用
#
前缀:#privateField = 42
四、异步编程演进
1. 回调函数到 Promise
// 回调地狱示例
getData(function(a) {
getMoreData(a, function(b) {
getMoreData(b, function(c) {
// ...
});
});
});
// Promise 改进
getData()
.then(a => getMoreData(a))
.then(b => getMoreData(b))
.catch(error => console.error(error));
实践建议:
- 始终处理 Promise 拒绝(添加
catch
) - 使用
Promise.all
并行独立异步操作
2. async/await 最佳实践
async function fetchUserData() {
try {
const user = await fetch('/user');
const posts = await fetch('/posts');
return { user, posts };
} catch (error) {
console.error('Fetch failed:', error);
throw error;
}
}
实践建议:
- 避免不必要的顺序
await
(独立请求应并行) - 在循环中谨慎使用
await
,考虑Promise.all
3. 微任务与事件循环
实践建议:
- 微任务(Promise、MutationObserver)在当前任务结束后立即执行
- 宏任务(setTimeout、I/O)等待下一次事件循环
五、模块化实践
1. ES Modules 基础
// math.js
export const PI = 3.14159;
export function square(x) { return x * x; }
// app.js
import { PI, square } from './math.js';
console.log(square(PI));
实践建议:
- 使用命名导出提高代码可读性
- 默认导出(
export default
)适合模块主要功能
2. 动态导入
async function loadModule() {
const module = await import('./module.js');
module.doSomething();
}
实践建议:
- 按需加载提高初始加载性能
- 结合代码分割(Code Splitting)优化打包结果
六、DOM 操作核心
1. 高效元素选择
// 现代选择方法
const form = document.querySelector('#signup-form');
const inputs = form.querySelectorAll('input[type="text"]');
// 旧方法对比
const oldWay = document.getElementById('signup-form');
实践建议:
- 优先使用
querySelector
系列方法 - 缓存 DOM 查询结果避免重复查找
2. 事件委托模式
document.querySelector('#item-list').addEventListener('click', (e) => {
if (e.target.matches('li.item')) {
console.log('Item clicked:', e.target.dataset.id);
}
});
实践建议:
- 对动态内容使用事件委托而非直接绑定
- 注意事件冒泡与阻止默认行为(
e.stopPropagation()
)
七、现代浏览器 API
1. fetch 替代 XHR
async function fetchData() {
try {
const response = await fetch('/api/data');
if (!response.ok) throw new Error('Network error');
return await response.json();
} catch (error) {
console.error('Fetch failed:', error);
}
}
实践建议:
- 始终检查
response.ok
状态 - 设置合理的超时控制(使用
AbortController
)
2. Web Storage 使用
// localStorage 持久化存储
localStorage.setItem('theme', 'dark');
const theme = localStorage.getItem('theme');
// sessionStorage 会话级存储
sessionStorage.setItem('tempData', JSON.stringify({ id: 1 }));
实践建议:
- 存储前使用
JSON.stringify
序列化对象 - 注意存储大小限制(通常 5MB)
性能优化要点
- 防抖与节流实现:
function debounce(func, delay) {
let timeout;
return (...args) => {
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(this, args), delay);
};
}
window.addEventListener('resize', debounce(() => {
console.log('Resize handler');
}, 200));
- 虚拟 DOM 原理:
实践建议:
- 避免频繁的直接 DOM 操作
- 使用
requestAnimationFrame
优化动画性能
总结
JavaScript 作为现代 Web 开发的核心语言,其丰富的运算符系统、灵活的函数特性以及强大的异步处理能力,为开发者提供了构建复杂应用的基础。掌握这些核心概念:
- 熟练使用现代语法(解构、可选链、箭头函数等)
- 理解原型继承与
class
语法糖的本质 - 合理选择异步处理方案(回调/Promise/async-await)
- 遵循模块化开发原则
- 优化 DOM 操作性能
随着 ECMAScript 标准的持续演进,建议定期关注新特性(如 2023 新增的数组分组方法),同时夯实基础概念,才能在快速变化的前端生态中保持竞争力。
评论已关闭