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. 原型继承

图1

实践建议

  • 优先使用 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. 微任务与事件循环

图2

实践建议

  • 微任务(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)

性能优化要点

  1. 防抖与节流实现
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));
  1. 虚拟 DOM 原理

图3

实践建议

  • 避免频繁的直接 DOM 操作
  • 使用 requestAnimationFrame 优化动画性能

总结

JavaScript 作为现代 Web 开发的核心语言,其丰富的运算符系统、灵活的函数特性以及强大的异步处理能力,为开发者提供了构建复杂应用的基础。掌握这些核心概念:

  1. 熟练使用现代语法(解构、可选链、箭头函数等)
  2. 理解原型继承与 class 语法糖的本质
  3. 合理选择异步处理方案(回调/Promise/async-await)
  4. 遵循模块化开发原则
  5. 优化 DOM 操作性能

随着 ECMAScript 标准的持续演进,建议定期关注新特性(如 2023 新增的数组分组方法),同时夯实基础概念,才能在快速变化的前端生态中保持竞争力。

评论已关闭