JavaScript 核心概念面试指南
1. 数据类型与类型检测
1.1 基本数据类型
JavaScript 有 8 种基本数据类型:
- number
- string
- boolean
- undefined
- null
- symbol (ES6)
- bigint (ES2020)
- object
// 类型检测方法
console.log(typeof 42); // 'number'
console.log(typeof '42'); // 'string'
console.log(typeof true); // 'boolean'
console.log(typeof undefined); // 'undefined'
console.log(typeof null); // 'object' (这是一个历史遗留bug)
console.log(typeof Symbol()); // 'symbol'
console.log(typeof 42n); // 'bigint'
console.log(typeof {}); // 'object'
1.2 类型转换
// 隐式转换
console.log(1 + '2'); // '12'
console.log('1' + 2); // '12'
console.log(1 - '2'); // -1
console.log('1' - 2); // -1
console.log(Boolean([])); // true
console.log(!![]); // true
console.log([] == false); // true
// 显式转换
console.log(Number('42')); // 42
console.log(String(42)); // '42'
console.log(Boolean(0)); // false
console.log(Object(42)); // Number {42}
2. 原型与继承
2.1 原型链
function Person(name) {
this.name = name;
}
Person.prototype.sayHello = function() {
return `Hello, I'm ${this.name}`;
};
const alice = new Person('Alice');
console.log(alice.sayHello()); // "Hello, I'm Alice"
// 原型链查找过程
console.log(alice.__proto__ === Person.prototype); // true
console.log(Person.prototype.__proto__ === Object.prototype); // true
console.log(Object.prototype.__proto__ === null); // true
2.2 继承实现
// ES6 之前的继承
function Animal(name) {
this.name = name;
}
Animal.prototype.speak = function() {
return `${this.name} makes a sound`;
};
function Dog(name) {
Animal.call(this, name); // 调用父类构造函数
}
// 设置原型链
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
// ES6 的 class 继承
class Animal {
constructor(name) {
this.name = name;
}
speak() {
return `${this.name} makes a sound`;
}
}
class Dog extends Animal {
constructor(name) {
super(name);
}
bark() {
return `${this.name} barks`;
}
}
3. 作用域与闭包
3.1 作用域
var globalVar = 'global';
let blockVar = 'block';
function scopeTest() {
var functionVar = 'function';
if (true) {
let blockVar = 'inner block';
var functionVar2 = 'function 2';
console.log(blockVar); // 'inner block'
}
console.log(functionVar); // 'function'
console.log(functionVar2); // 'function 2'
// console.log(blockVar); // ReferenceError
}
3.2 闭包实例
function createCounter() {
let count = 0;
return {
increment() {
return ++count;
},
decrement() {
return --count;
},
getCount() {
return count;
}
};
}
const counter = createCounter();
console.log(counter.increment()); // 1
console.log(counter.increment()); // 2
console.log(counter.decrement()); // 1
4. 异步编程
4.1 Promise
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
const random = Math.random();
if (random > 0.5) {
resolve(random);
} else {
reject(new Error('Number too small!'));
}
}, 1000);
});
promise
.then(result => console.log('Success:', result))
.catch(error => console.error('Error:', error));
// Promise.all 示例
const promises = [
Promise.resolve(1),
Promise.resolve(2),
Promise.resolve(3)
];
Promise.all(promises)
.then(results => console.log(results)) // [1, 2, 3]
.catch(error => console.error(error));
4.2 Async/Await
async function fetchUserData(userId) {
try {
const response = await fetch(`/api/users/${userId}`);
const data = await response.json();
return data;
} catch (error) {
console.error('Error fetching user:', error);
throw error;
}
}
// 错误处理最佳实践
async function handleUserData() {
try {
const user = await fetchUserData(123);
console.log(user);
} catch (error) {
// 处理错误
}
}
5. 事件循环
5.1 宏任务与微任务
console.log('1'); // 同步任务
setTimeout(() => {
console.log('2'); // 宏任务
}, 0);
Promise.resolve()
.then(() => {
console.log('3'); // 微任务
});
console.log('4'); // 同步任务
// 输出顺序:1, 4, 3, 2
5.2 实际应用
async function loadData() {
console.log('开始加载'); // 1
setTimeout(() => {
console.log('定时器执行'); // 4
}, 0);
await Promise.resolve();
console.log('Promise 已完成'); // 3
console.log('加载完成'); // 2
}
loadData();
6. 常见面试题解析
6.1 this 指向问题
const obj = {
name: 'object',
sayName() {
console.log(this.name);
},
sayNameArrow: () => {
console.log(this.name);
}
};
obj.sayName(); // 'object'
obj.sayNameArrow(); // undefined
const fn = obj.sayName;
fn(); // undefined (在全局环境调用)
6.2 防抖与节流
// 防抖
function debounce(fn, delay) {
let timer = null;
return function(...args) {
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, args);
}, delay);
};
}
// 节流
function throttle(fn, interval) {
let last = 0;
return function(...args) {
const now = Date.now();
if (now - last >= interval) {
last = now;
fn.apply(this, args);
}
};
}
6.3 深拷贝实现
function deepClone(obj, hash = new WeakMap()) {
if (obj === null || typeof obj !== 'object') return obj;
if (obj instanceof Date) return new Date(obj);
if (obj instanceof RegExp) return new RegExp(obj);
// 防止循环引用
if (hash.has(obj)) return hash.get(obj);
const cloneObj = Array.isArray(obj) ? [] : {};
hash.set(obj, cloneObj);
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
cloneObj[key] = deepClone(obj[key], hash);
}
}
return cloneObj;
}
7. ES6+ 重要特性
7.1 解构与展开运算符
// 数组解构
const [a, b, ...rest] = [1, 2, 3, 4, 5];
console.log(a, b, rest); // 1, 2, [3, 4, 5]
// 对象解构
const { name, age, ...other } = { name: 'John', age: 30, city: 'NY', country: 'USA' };
console.log(name, age, other); // 'John', 30, { city: 'NY', country: 'USA' }
// 展开运算符
const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5]; // [1, 2, 3, 4, 5]
const obj1 = { foo: 'bar' };
const obj2 = { ...obj1, baz: 'qux' }; // { foo: 'bar', baz: 'qux' }
7.2 Map 与 Set
// Map
const map = new Map();
map.set('key', 'value');
map.set(obj, 'value2');
// Set
const set = new Set([1, 2, 2, 3, 3]);
console.log([...set]); // [1, 2, 3]
// WeakMap 和 WeakSet
const weakMap = new WeakMap();
let obj = { foo: 'bar' };
weakMap.set(obj, 'value');
obj = null; // 对象可被垃圾回收
8. 性能优化
8.1 代码优化
// 避免频繁操作 DOM
const fragment = document.createDocumentFragment();
for (let i = 0; i < 1000; i++) {
const el = document.createElement('div');
fragment.appendChild(el);
}
document.body.appendChild(fragment);
// 使用事件委托
document.getElementById('list').addEventListener('click', (e) => {
if (e.target.tagName === 'LI') {
console.log('Clicked:', e.target.textContent);
}
});
8.2 内存管理
// 避免内存泄漏
function addHandler() {
const el = document.getElementById('element');
el.addEventListener('click', () => {
console.log('Clicked');
});
}
// 正确的做法
function addHandler() {
const el = document.getElementById('element');
const handler = () => console.log('Clicked');
el.addEventListener('click', handler);
// 清理函数
return () => {
el.removeEventListener('click', handler);
};
}
记住,这些知识点不仅是为了应对面试,更重要的是在实际开发中能够灵活运用。建议:
- 理解原理,而不是死记硬背
- 多动手实践,加深理解
- 关注最新的 JavaScript 发展动态
- 结合实际项目经验来理解这些概念