谈谈那些你逃不掉的js面试题

209 阅读3分钟

大家好,我是鱼樱!!!

关注公众号【鱼樱AI实验室】

回复【Vue3】免费获取徒手思考的:Vue3完整学习大纲!!!!不让你错过任何一个经典的知识点 回复【Vue3源码】免费获取徒手思考的:Vue3完整源码架构学习脑图!!!!不让你错过任何一个源码核心的知识点


工作的前提是有招聘,约面的前提是做好充足的准备!!!知己知彼百战百胜!!!大概率会问到的js面试题幸运的你也终究逃不掉,接下来我们讨论一下常见的概率大的js面试题灵魂拷问一波~

一、基础核心概念

1. 变量提升与暂时性死区

console.log(a); // undefined
var a = 1;
let b = 2;

答案
var存在变量提升,let/const存在暂时性死区。解析时var变量被初始化为undefined,而let变量在声明前访问会报错。


2. 闭包与内存泄漏

function createCounter() {
  let count = 0;
  return function() {
    count++;
    return count;
  };
}

答案
内部函数访问外部变量形成闭包。需注意不及时释放闭包引用会导致内存泄漏,可通过置空引用或WeakMap解决。


二、异步编程

3. 事件循环执行顺序

console.log(1);
setTimeout(() => console.log(2), 0);
Promise.resolve().then(() => console.log(3));
console.log(4);

答案
输出顺序:1 → 4 → 3 → 2
原理:同步代码 > 微任务 > 宏任务。Promise属于微任务,setTimeout属于宏任务(专栏有基于事件循环专词最合适的解释)。


4. Promise链式调用

Promise.resolve(1)
  .then(x => x + 1)
  .then(x => { throw x })
  .catch(x => x + 1)
  .then(console.log);

答案
输出3。执行流程:1→2→抛出错误→catch捕获2→3→输出。


三、面向对象

5. 原型链继承

function Parent() { this.name = 'parent'; }
Parent.prototype.getName = () => this.name;

function Child() {}
Child.prototype = new Parent();

const child = new Child();
console.log(child.getName());

答案
输出'parent'。通过原型链继承,但存在共享引用类型的问题。更优解:使用组合继承或ES6 class。


6. this指向问题

const obj = {
  name: 'obj',
  print: () => console.log(this.name),
  print2() {
    setTimeout(() => console.log(this.name));
  }
}
obj.print(); // undefined(箭头函数无自己的this)
obj.print2(); // 'obj'

四、ES6+ 特性

7. let vs var

for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 0);
}
// 输出3次3

解决方案:使用let创建块级作用域,或使用闭包。


8. 解构赋值技巧

const { a: x, b: y } = { a: 1, b: 2 };
// x=1, y=2(重命名语法)

五、手写实现

9. 防抖与节流

// 防抖实现
function debounce(fn, delay) {
  let timer;
  return (...args) => {
    clearTimeout(timer);
    timer = setTimeout(() => fn.apply(this, args), delay);
  };
}

10. 深拷贝实现

function deepClone(obj, map = new WeakMap()) {
  if (obj instanceof Date) return new Date(obj);
  if (obj instanceof RegExp) return new RegExp(obj);
  if (map.has(obj)) return map.get(obj);
  
  let clone = Array.isArray(obj) ? [] : {};
  map.set(obj, clone);
  
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      clone[key] = typeof obj[key] === 'object' ? 
        deepClone(obj[key], map) : obj[key];
    }
  }
  return clone;
}

六、进阶问题

11. EventLoop综合题

async function async1() {
  console.log(1);
  await async2();
  console.log(2);
}
async function async2() {
  console.log(3);
}
// 输出顺序:1 → 3 → 2(await后的代码相当于微任务)

12. 柯里化实现

function curry(fn) {
  return function curried(...args) {
    return args.length >= fn.length ?
      fn.apply(this, args) :
      (...newArgs) => curried.apply(this, args.concat(newArgs));
  };
}

嗯,这里的不会???没事后续还有不断惊喜的~好好准备一下准没错。