你是不是也遇到过这样的场景?面试官抛出一个闭包问题,你支支吾吾答不上来;团队代码review时,看到同事用的Promise链一脸懵逼;明明功能实现了,性能却总是差那么一点...
别慌!今天我整理了12个JavaScript核心概念,这些都是2024年各大厂面试的高频考点,也是日常开发中真正实用的硬核知识。搞懂它们,不仅能轻松应对面试,更能让你的代码质量提升一个档次!
变量与作用域
先来看个最常见的面试题:
1// 经典面试题:猜猜输出什么? 2for (var i = 0; i < 3; i++) { 3 setTimeout(() => { 4 console.log(i); // 输出:3 3 3 5 }, 100); 6} 7
为什么会这样?因为var声明的变量存在变量提升,而且没有块级作用域。换成let就正常了:
1// 使用let的正确写法 2for (let i = 0; i < 3; i++) { 3 setTimeout(() => { 4 console.log(i); // 输出:0 1 2 5 }, 100); 6} 7
这里涉及到两个关键概念:变量提升和块级作用域。let和const是ES6引入的,它们有块级作用域,不会出现var的那些奇怪问题。
闭包与内存管理
闭包可能是最让人头疼的概念了,但其实理解起来并不难:
1// 闭包的实际应用:计数器 2function createCounter() { 3 let count = 0; // 这个变量被"封闭"在函数内部 4 5 return { 6 increment: () => ++count, 7 decrement: () => --count, 8 getValue: () => count 9 }; 10} 11 12const counter = createCounter(); 13console.log(counter.increment()); // 1 14console.log(counter.increment()); // 2 15
闭包就是函数能够记住并访问其词法作用域中的变量,即使函数在其作用域外执行。但要注意内存泄漏问题:
1// 潜在的内存泄漏 2function createHeavyObject() { 3 const largeObject = new Array(1000000); // 大对象 4 5 return () => { 6 // 即使外部不再需要,largeObject仍然被引用 7 console.log('对象还在内存中'); 8 }; 9} 10
原型与继承
JavaScript的继承是基于原型的,这和传统的类继承很不一样:
1// 原型链示例 2function Animal(name) { 3 this.name = name; 4} 5 6Animal.prototype.speak = function() { 7 console.log([`${this.name} makes a noise.`](https://xplanc.org/primers/document/zh/03.HTML/EX.HTML%20%E5%85%83%E7%B4%A0/EX.a.md)); 8}; 9 10function Dog(name) { 11 Animal.call(this, name); // 调用父类构造函数 12} 13 14// 设置原型链 15Dog.prototype = Object.create(Animal.prototype); 16Dog.prototype.constructor = Dog; 17 18Dog.prototype.speak = function() { 19 console.log(`${this.name} barks.`); 20}; 21 22const dog = new Dog('Rex'); 23dog.speak(); // Rex barks. 24
ES6的class语法让这变得更简单:
1class Animal { 2 constructor(name) { 3 this.name = name; 4 } 5 6 speak() { 7 console.log([`${this.name} makes a noise.`](https://xplanc.org/primers/document/zh/03.HTML/EX.HTML%20%E5%85%83%E7%B4%A0/EX.a.md)); 8 } 9} 10 11class Dog extends Animal { 12 speak() { 13 console.log(`${this.name} barks.`); 14 } 15} 16
异步编程演进
从回调地狱到async/await,异步编程经历了很大变化:
1// 1. 回调地狱 2function oldWay(callback) { 3 readFile('file1.txt', (err, data1) => { 4 if (err) return callback(err); 5 processData(data1, (err, result1) => { 6 if (err) return callback(err); 7 // 更多嵌套... 8 }); 9 }); 10} 11 12// 2. Promise链 13function promiseWay() { 14 return readFilePromise('file1.txt') 15 .then(processDataPromise) 16 .then(data => { 17 // 更清晰的流程 18 }) 19 .catch(error => { 20 // 统一错误处理 21 }); 22} 23 24// 3. async/await(推荐) 25async function modernWay() { 26 try { 27 const data = await readFilePromise('file1.txt'); 28 const result = await processDataPromise(data); 29 return result; 30 } catch (error) { 31 console.error('处理失败:', error); 32 } 33} 34
Promise深度解析
Promise是现代JavaScript异步编程的基石:
1// 手写一个简易Promise 2class MyPromise { 3 constructor(executor) { 4 this.state = 'pending'; 5 this.value = undefined; 6 this.onFulfilledCallbacks = []; 7 8 const resolve = (value) => { 9 if (this.state === 'pending') { 10 this.state = 'fulfilled'; 11 this.value = value; 12 this.onFulfilledCallbacks.forEach(cb => cb(value)); 13 } 14 }; 15 16 executor(resolve); 17 } 18 19 then(onFulfilled) { 20 return new MyPromise((resolve) => { 21 if (this.state === 'fulfilled') { 22 const result = onFulfilled(this.value); 23 resolve(result); 24 } else { 25 this.onFulfilledCallbacks.push((value) => { 26 const result = onFulfilled(value); 27 resolve(result); 28 }); 29 } 30 }); 31 } 32} 33
事件循环机制
这是JavaScript并发模型的核心:
1// 理解事件循环的执行顺序 2console.log('1. 同步任务开始'); 3 4setTimeout(() => { 5 console.log('6. 宏任务执行'); 6}, 0); 7 8Promise.resolve().then(() => { 9 console.log('4. 微任务执行'); 10}); 11 12console.log('2. 同步任务继续'); 13 14Promise.resolve().then(() => { 15 console.log('5. 另一个微任务'); 16}); 17 18console.log('3. 同步任务结束'); 19 20// 输出顺序:1 2 3 4 5 6 21
ES6+新特性实战
现代JavaScript提供了很多好用特性:
1// 解构赋值 2const user = { name: '小明', age: 25, city: '北京' }; 3const { name, age } = user; 4 5// 扩展运算符 6const arr1 = [1, 2, 3]; 7const arr2 = [...arr1, 4, 5]; // [1, 2, 3, 4, 5] 8 9// 可选链操作符 10const street = user?.address?.street; // 不会报错 11 12// 空值合并 13const displayName = user.nickname ?? '匿名用户'; // 只有null/undefined时使用默认值 14
函数式编程概念
JavaScript很适合函数式编程风格:
1// 高阶函数 2const users = [ 3 { name: '小明', age: 25 }, 4 { name: '小红', age: 30 }, 5 { name: '小刚', age: 28 } 6]; 7 8// 函数组合 9const getAdultNames = users 10 .filter(user => user.age >= 18) 11 .map(user => user.name) 12 .sort(); 13 14// 柯里化 15const multiply = a => b => a * b; 16const double = multiply(2); 17console.log(double(5)); // 10 18
模块化系统
从IIFE到ES Modules的演进:
1// 现代ES Modules 2// math.js 3export const add = (a, b) => a + b; 4export const PI = 3.14159; 5 6// app.js 7import { add, PI } from './math.js'; 8console.log(add(PI, 2)); // 5.14159 9 10// 动态导入 11const loadModule = async () => { 12 const module = await import('./math.js'); 13 console.log(module.add(1, 2)); 14}; 15
类型系统与TypeScript
虽然JavaScript是动态类型,但类型检查很重要:
1// 类型检查工具函数 2const typeCheck = { 3 isString: value => typeof value === 'string', 4 isFunction: value => typeof value === 'function', 5 isObject: value => value !== null && typeof value === 'object' 6}; 7 8// TypeScript带来的类型安全 9interface User { 10 name: string; 11 age: number; 12 email?: string; 13} 14 15function createUser(user: User): User { 16 // TypeScript会在编译时检查类型 17 return { ...user }; 18} 19
性能优化技巧
写出高性能的JavaScript代码:
1// 防抖函数:避免频繁调用 2function debounce(func, wait) { 3 let timeout; 4 return function executedFunction(...args) { 5 const later = () => { 6 clearTimeout(timeout); 7 func(...args); 8 }; 9 clearTimeout(timeout); 10 timeout = setTimeout(later, wait); 11 }; 12} 13 14// 使用Web Worker处理密集型任务 15const worker = new Worker('heavy-task.js'); 16worker.postMessage({ data: largeData }); 17worker.onmessage = (event) => { 18 console.log('计算结果:', event.data); 19}; 20
现代开发工具链
2024年的前端开发离不开这些工具:
1// Vite配置示例 2// vite.config.js 3export default { 4 plugins: [vue(), eslint()], 5 build: { 6 rollupOptions: { 7 output: { 8 manualChunks: { 9 vendor: ['vue', 'vue-router'] 10 } 11 } 12 } 13 } 14}; 15 16// 现代测试工具 17import { describe, it, expect } from 'vitest'; 18 19describe('工具函数测试', () => { 20 it('应该正确计算加法', () => { 21 expect(add(1, 2)).toBe(3); 22 }); 23}); 24
这12个核心概念就像JavaScript的基石,理解它们不仅能让你在面试中游刃有余,更能写出更健壮、更易维护的代码。
《90%前端面试必问的12个JS核心,搞懂这些直接起飞!》 是转载文章,点击查看原文。