🧑💻 寫在開頭
點贊 + 收藏 === 學會🤣🤣🤣
你是不是也遇到過這樣的場景?面試官拋出一個閉包問題,你支支吾吾答不上來;團隊代碼review時,看到同事用的Promise鏈一臉懵逼;明明功能實現了,性能卻總是差那麼一點...
別慌!今天我整理了12個JavaScript核心概念,這些都是2024年各大廠面試的高頻考點,也是日常開發中真正實用的硬核知識。搞懂它們,不僅能輕鬆應對面試,更能讓你的代碼質量提升一個檔次!
變量與作用域
先來看個最常見的面試題:
// 經典面試題:猜猜輸出什麼?
for (var i = 0; i < 3; i++) {
setTimeout(() => {
console.log(i); // 輸出:3 3 3
}, 100);
}
為什麼會這樣?因為var聲明的變量存在變量提升,而且沒有塊級作用域。換成let就正常了:
// 使用let的正確寫法
for (let i = 0; i < 3; i++) {
setTimeout(() => {
console.log(i); // 輸出:0 1 2
}, 100);
}
這裏涉及到兩個關鍵概念:變量提升和塊級作用域。let和const是ES6引入的,它們有塊級作用域,不會出現var的那些奇怪問題。
閉包與內存管理
閉包可能是最讓人頭疼的概念了,但其實理解起來並不難:
// 閉包的實際應用:計數器
function createCounter() {
let count = 0; // 這個變量被"封閉"在函數內部
return {
increment: () => ++count,
decrement: () => --count,
getValue: () => count
};
}
const counter = createCounter();
console.log(counter.increment()); // 1
console.log(counter.increment()); // 2
閉包就是函數能夠記住並訪問其詞法作用域中的變量,即使函數在其作用域外執行。但要注意內存泄漏問題:
// 潛在的內存泄漏
function createHeavyObject() {
const largeObject = new Array(1000000); // 大對象
return () => {
// 即使外部不再需要,largeObject仍然被引用
console.log('對象還在內存中');
};
}
原型與繼承
JavaScript的繼承是基於原型的,這和傳統的類繼承很不一樣:
// 原型鏈示例
function Animal(name) {
this.name = name;
}
Animal.prototype.speak = function() {
console.log(`${this.name} makes a noise.`);
};
function Dog(name) {
Animal.call(this, name); // 調用父類構造函數
}
// 設置原型鏈
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.speak = function() {
console.log(`${this.name} barks.`);
};
const dog = new Dog('Rex');
dog.speak(); // Rex barks.
ES6的class語法讓這變得更簡單:
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a noise.`);
}
}
class Dog extends Animal {
speak() {
console.log(`${this.name} barks.`);
}
}
異步編程演進
從回調地獄到async/await,異步編程經歷了很大變化:
// 1. 回調地獄
function oldWay(callback) {
readFile('file1.txt', (err, data1) => {
if (err) return callback(err);
processData(data1, (err, result1) => {
if (err) return callback(err);
// 更多嵌套...
});
});
}
// 2. Promise鏈
function promiseWay() {
return readFilePromise('file1.txt')
.then(processDataPromise)
.then(data => {
// 更清晰的流程
})
.catch(error => {
// 統一錯誤處理
});
}
// 3. async/await(推薦)
async function modernWay() {
try {
const data = await readFilePromise('file1.txt');
const result = await processDataPromise(data);
return result;
} catch (error) {
console.error('處理失敗:', error);
}
}
Promise深度解析
Promise是現代JavaScript異步編程的基石:
// 手寫一個簡易Promise
class MyPromise {
constructor(executor) {
this.state = 'pending';
this.value = undefined;
this.onFulfilledCallbacks = [];
const resolve = (value) => {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
this.onFulfilledCallbacks.forEach(cb => cb(value));
}
};
executor(resolve);
}
then(onFulfilled) {
return new MyPromise((resolve) => {
if (this.state === 'fulfilled') {
const result = onFulfilled(this.value);
resolve(result);
} else {
this.onFulfilledCallbacks.push((value) => {
const result = onFulfilled(value);
resolve(result);
});
}
});
}
}
事件循環機制
這是JavaScript併發模型的核心:
// 理解事件循環的執行順序
console.log('1. 同步任務開始');
setTimeout(() => {
console.log('6. 宏任務執行');
}, 0);
Promise.resolve().then(() => {
console.log('4. 微任務執行');
});
console.log('2. 同步任務繼續');
Promise.resolve().then(() => {
console.log('5. 另一個微任務');
});
console.log('3. 同步任務結束');
// 輸出順序:1 2 3 4 5 6
ES6+新特性實戰
現代JavaScript提供了很多好用特性:
// 解構賦值
const user = { name: '小明', age: 25, city: '北京' };
const { name, age } = user;
// 擴展運算符
const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5]; // [1, 2, 3, 4, 5]
// 可選鏈操作符
const street = user?.address?.street; // 不會報錯
// 空值合併
const displayName = user.nickname ?? '匿名用户'; // 只有null/undefined時使用默認值
函數式編程概念
JavaScript很適合函數式編程風格:
// 高階函數
const users = [
{ name: '小明', age: 25 },
{ name: '小紅', age: 30 },
{ name: '小剛', age: 28 }
];
// 函數組合
const getAdultNames = users
.filter(user => user.age >= 18)
.map(user => user.name)
.sort();
// 柯里化
const multiply = a => b => a * b;
const double = multiply(2);
console.log(double(5)); // 10
模塊化系統
從IIFE到ES Modules的演進:
// 現代ES Modules
// math.js
export const add = (a, b) => a + b;
export const PI = 3.14159;
// app.js
import { add, PI } from './math.js';
console.log(add(PI, 2)); // 5.14159
// 動態導入
const loadModule = async () => {
const module = await import('./math.js');
console.log(module.add(1, 2));
};
類型系統與TypeScript
雖然JavaScript是動態類型,但類型檢查很重要:
// 類型檢查工具函數
const typeCheck = {
isString: value => typeof value === 'string',
isFunction: value => typeof value === 'function',
isObject: value => value !== null && typeof value === 'object'
};
// TypeScript帶來的類型安全
interface User {
name: string;
age: number;
email?: string;
}
function createUser(user: User): User {
// TypeScript會在編譯時檢查類型
return { ...user };
}
性能優化技巧
寫出高性能的JavaScript代碼:
// 防抖函數:避免頻繁調用
function debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
// 使用Web Worker處理密集型任務
const worker = new Worker('heavy-task.js');
worker.postMessage({ data: largeData });
worker.onmessage = (event) => {
console.log('計算結果:', event.data);
};
現代開發工具鏈
2024年的前端開發離不開這些工具:
// Vite配置示例
// vite.config.js
export default {
plugins: [vue(), eslint()],
build: {
rollupOptions: {
output: {
manualChunks: {
vendor: ['vue', 'vue-router']
}
}
}
}
};
// 現代測試工具
import { describe, it, expect } from 'vitest';
describe('工具函數測試', () => {
it('應該正確計算加法', () => {
expect(add(1, 2)).toBe(3);
});
});
這12個核心概念就像JavaScript的基石,理解它們不僅能讓你在面試中游刃有餘,更能寫出更健壯、更易維護的代碼。