一、永恒的经典
const arr = [1, 8, 2, 1, 0, 6]
const N = arr.length
for (let i = 0; i < N - 1; i++) {
for (let j = 0; j < N - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]
}
}
}
for (let i = 1; i < N; i++) {
let j;
let key = arr[i]
for (j = i - 1; j >= 0 && arr[j] > key; j--) {
arr[j + 1] = arr[j]
}
arr[j + 1] = key
}
for (let i = 0; i < N - 1; i++) {
let minIndex = i
for (let j = i + 1; j < N; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j
}
}
if (minIndex != i) {
[arr[minIndex], arr[i]] = [arr[i], arr[minIndex]]
}
}
二、节流、防抖与柯里化
function throttle(fn, interval) {
let callTime = 0
return function (...args) {
const now = Date.now()
if (now - callTime >= interval) {
fn.apply(this, args)
callTime = now
}
}
}
function debounce(fn, delay) {
let timer = 0
return function (...args) {
timer && clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, args)
}, delay)
}
}
function curry(fn) {
const arity = fn.length;
function curried(...args) {
if (args.length >= arity) {
return fn(...args);
} else {
return function (...moreArgs) {
return curried(...args, ...moreArgs);
};
}
}
return curried;
}
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) {
return fn.apply(this, args);
} else {
return function(...moreArgs) {
return curried.apply(this, args.concat(moreArgs));
};
}
};
}
const add = curry((a, b, c) => a + b + c);
console.log(add(1)(2)(3));
console.log(add(1, 2)(3));
三、普通函数与箭头函数的this
function outer() {
if (true) {
const arrowFunc = () => {
console.log('箭头~', this);
};
arrowFunc();
const regularFunc = function () {
console.log('普通~', this)
}
regularFunc()
}
}
outer.call({
name: "Charlie"
});
outer()
const obj = {
name: "Bob",
regularMethod: function () {
const arrowFunc = () => {
console.log('箭头~', this);
};
arrowFunc();
const regularFunc = function () {
console.log('普通~', this)
}
regularFunc()
}
};
obj.regularMethod()
四、易混淆知识点
Array Array.of Array.from
splice slice substring substr
五、经典笔试题
1、发布订阅模式
class EventEmitter{
constructor(){
this.events=[]
}
on(event,cb){
if(this.events[event]){
this.events[event]=cb
}
this.events[evnet].push(cb)
}
emit(event,...args){
if(this.events[event]){
this.events[event].forEach(cb => {
cb(...args)
});
}
}
off(event,cb){
if(this.events[event]){
this.events[event]=this.events[event].filter(callback=>callback!==cb)
}
}
}
const emitter=new EventEmitter()
emitter.on('msg',(msg)=>{
console.log(`hi,${msg}`)
})
emitter.emit('msg','999')
2、并发控制
async function runTasks(tasks,concurrency){
const results=[]
const runningTasks=[]
for(const task of tasks){
const runningTask=task().then(res=>{
runningTasks.splice(runningTasks.indexOf(runningTask),1)
results.push(res)
})
runningTasks.push(runningTask)
if(runningTasks.length>=concurrency){
console.log('并发啦')
await Promise.race(runningTasks)
}
}
return Promise.all(runningTasks).then(()=>results)
}
async function runTasks(tasks, concurrency) {
const results = [],
runningTasks = new Set()
for (let i = 0; i < task.length; i++) {
if (runningTasks.length >= concurrency) {
await Promise.race(runningTasks)
}
const taskPromise = task[i]().then(res => {
runningTasks.delete(taskPromise)
results[i] = res
})
runningTasks.add(taskPromise)
}
await Promise.all(runningTasks)
return results
}
const tasks=[
()=>new Promise(resolve=>setTimeout(() => {
resolve("Task 1")
}, 1000)),
()=>new Promise(resolve=>setTimeout(() => {
resolve("Task 2")
}, 500)),
()=>new Promise(resolve=>setTimeout(() => {
resolve("Task 3")
}, 2000)),
]
runTasks(tasks,2).then(res=>{
console.log(res);
})
3、爬楼梯
function climbStairs(n) {
if (n <= 2) return n;
let prev1 = 1;
let prev2 = 2;
for (let i = 3; i <= n; i++) {
const current = prev1 + prev2;
prev1 = prev2;
prev2 = current;
}
return prev2;
}
function climbStairs(n){
if (n < 3) return n
let prev1 = 1,
prev2 = 2
while (n-- > 2) {
[prev1, prev2] = [prev2, prev1 + prev2]
}
return prev2
}
4、有效回文串
function canMakePalindrome(s) {
let mismatch = 0;
for(let i = 0, j = s.length - 1; i < j; i++, j--) {
if (s[i] !== s[j] && ++mismatch > 2) return false;
}
return mismatch < 3;
}
5、深度克隆
function deepClone(obj, hash = new WeakMap()) {
if (obj === null || typeof obj !== 'object') {
return obj;
}
if (hash.has(obj)) {
return hash.get(obj);
}
if (obj instanceof Date) {
const clone = new Date(obj);
hash.set(obj, clone);
return clone;
}
if (obj instanceof RegExp) {
const clone = new RegExp(obj);
hash.set(obj, clone);
return clone;
}
if (obj instanceof Map) {
const clone = new Map();
hash.set(obj, clone);
obj.forEach((value, key) => {
clone.set(deepClone(key, hash), deepClone(value, hash));
});
return clone;
}
if (obj instanceof Set) {
const clone = new Set();
hash.set(obj, clone);
obj.forEach(value => {
clone.add(deepClone(value, hash));
});
return clone;
}
if (ArrayBuffer.isView(obj)) {
const clone = new obj.constructor(obj);
hash.set(obj, clone);
return clone;
}
if (obj instanceof ArrayBuffer) {
const clone = obj.slice(0);
hash.set(obj, clone);
return clone;
}
if (typeof obj === 'function') {
return obj;
}
const clone = Object.create(Object.getPrototypeOf(obj));
hash.set(obj, clone);
const allKeys = Object.getOwnPropertyNames(obj).concat(
Object.getOwnPropertySymbols(obj)
);
for (const key of allKeys) {
const descriptor = Object.getOwnPropertyDescriptor(obj, key);
if (descriptor) {
if (typeof descriptor.value === 'object' && descriptor.value !== null) {
descriptor.value = deepClone(descriptor.value, hash);
}
Object.defineProperty(clone, key, descriptor);
}
}
return clone;
}
6、sp通配符匹配
var isMatch = function (s, p) {
const m = s.length, n = p.length
const dp=Array.from({length:m+1}).map(()=>Array.from({length:n+1}).map(()=>false))
dp[0][0] = true
for (let i = 1; i <= n; i++) {
dp[0][i] = dp[0][i - 1] && p[i - 1] == '*'
}
for (let i = 1; i <= m; i++) {
for (let j = 1; j <= n; j++) {
if (s[i - 1] == p[j - 1] || p[j - 1] == '?') {
dp[i][j] = dp[i - 1][j - 1]
} else if (p[j - 1] == '*') {
dp[i][j] = dp[i][j - 1] || dp[i - 1][j]
}
}
}
return dp[m][n]
}
六、正则经典
手机号验证(中国大陆)
/^1[3-9]\d{9}$/.test('13800138000')
邮箱验证
/^[\w-]+(.[\w-]+)*@[\w-]+(.[\w-]+)+$/.test('test@example.com')
身份证号验证(简单版)
/^\d{17}[\dXx]$/.test('11010119900307783X')
中文汉字匹配
/^[\u4e00-\u9fa5]+$/.test('中文测试')
提取域名
'https://example.com/path'.match(/https?:\/\/([^/]+)/)[1]
数字提取
'价格¥299'.match(/\d+/)[0]
日期格式验证(YYYY-MM-DD)
/^\d{4}-\d{2}-\d{2}$/.test('2025-09-28')
密码强度验证(6-12位字母数字)
/^[a-zA-Z0-9]{6,12}$/.test('Pass123')
HTML标签内容提取
'<div>content</div>'.match(/<[^>]+>([^<]+)</)[1]
空白字符替换
'多 个 空格'.replace(/\s+/g,'')
一百分、其他
面试方法论
1、慢一点&&被提问环节至少问对方至少5个问题
2、star法则 情景 目标 行动 结果
3、总分总
4、prep 观点 理由 举例子 总结
function getType(value) {
return Object.prototype.toString.call(value)
.match(/\s+(\w+)/)[1]
.toLowerCase();
}
闭包:函数能访问并记住其词法作用域,即使函数在作用域外执行。
前端性能优化
代码压缩(gzip、丑化、多目标打包)
图片懒加载(webp、雪碧图、base64)
HTTP(http2、多静态资源域)
缓存、CDN