面试题

开场题

let [a, b = 2, c = 3] = [1, undefined, null]
console.log(a, b, c)
setTimeout(() => {
    console.log(1)
}, 0)
let p = new Promise((resolve, reject) => {
    console.log(2)
    reject()
    resolve()
})
p.then(() => {
    console.log(3)
}, () => {
    console.log(4)
})
console.log(5)
function main() {
  try {
    setTimeout(() => {
      throw new Error("async error");
    }, 1000);
  } catch (e) {
    console.log(e, "err");
  }
  console.log("continue...");
}
main();

CSS

  • 盒模型,标准盒模型和怪异盒模型,如何设置盒模型box-sizing: content-box | border-box
  • CSS 实现自适应正方形
    • padding 撑高,padding 的百分比是相对于父元素宽度
    • vw 和 vh
    • 微元素margin-top: 100%:margin 的百分比值参照其包含块的宽度进行计算
  • 浮动和定位,文档流,脱离文档流,z-index 使用注意事项
  • BFC 概念理解、使用
  • CSS 样式优先级、伪类伪元素的区别
  • rem 布局
  • 居中实现方案
    • vertical-align 对齐,baseline 不同类型元素位置,数值百分比
  • 横向滑动实现,flex-wrap
  • 页面水印实现方案:pointer-events: none;

三栏布局实现方案

  1. 弹性布局
  2. 定位或浮动
  3. grid 布局
<!-- 三栏布局:整体宽度占满屏幕,left 宽度 100px, right 宽度100px, middle宽度自适应 -->
<div id="left"></div>
<div id="middle"></div>
<div id="right"></div>

开放综合问题

前端动画实现

  • CSS 动画、过渡,CSS 动画为什么性能更好
  • JS 动画
  • requestAnimationFrame
  • 为什么定时器会卡顿、requestAnimationFrame 不会,任务队列执行机制问题
  • 使用定时器做动画间隔时间多少合适,为什么
  • 如何获取屏幕的刷新频率
  • 浏览器渲染流程

Long Task 导致主线程被长期占用如何优化

  • 性能分析工具使用
  • 方案一:使用 web worker
  • 方案二:任务分割,requestIdleCallback

工具&基础

  • git 分支集成方式
  • 代理抓包工具使用
  • typescript
    • 如何约束对象的属性名,联合类型
    • any、never、unknown 区别和使用场景
  • 跨域理解
  • HTTP 缓存机制及使用
  • 如何正确的使用图片,有哪些替代方案,可以从性能优化聊起
  • webpack 的使用,loader plugin 区别,webpack 构建优化
  • cookie localStorage sessionStorage 区别和使用场景
  • 前端安全

JS

  • 数据类型判断:null object
  • promise 三种状态,微任务宏任务,event loop
  • 数组和对象属性遍历方法,for in 和 for of 区别
  • 数组原生方法,数值去重
  • call,bind,apply,this

性能优化

  • 加载优化
    • 图片、懒加载
    • 缓存
  • 渲染优化
    • 重绘重排

框架使用

React

以下代码有问题吗

// React Hook实现一个计数器,每秒+1
function Counter() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    const id = setInterval(() => {
      setCount(count + 1);
    }, 1000);
    return () => clearInterval(id);
  }, []);

  return <h1>{count}</h1>;
}

Vue

  • vue 有哪些生命周期,对应的钩子和执行顺序
    • 哪个时机适合做数据请求,哪个时机可以访问到 DOM
  • vue 业务代码复用,函数式编程的优缺点
  • 如何正确的做组件封装:UI 组件和业务组件
  • 自定义表单组件,如何实现双向数据绑定
  • computed 和 watch 区别,以及使用场景
  • keep-alive 的理解
  • vue2 和 vue3 的区别
    • 为什么要使用 proxy

H5&小程序

  • H5 页面如何吊起 APP
    • URL Schema
    • Universal Link
    • 微信 wx-open-launch-app

编程题

数组元素求和尽量多方法&实现 Array.prototype.reduce polyfill

  • 遍历
  • 递归
  • reduce

删除数组指定位置元素

arr.splice(2, 1) arr.slice(0, 2).concat(arr.slice(3,))

实现 retry 方法,可以执行异步函数,失败后会重试,可以设置重试次数和重试缓冲时间,返回值是 Promise 实例

const retry = (promiseFn, times, delay) {
}

/*
 * @param {function} promiseFn 异步任务函数,返回Promise
 * @param {number} times 重试次数
 * @param {number} delay 任务失败后缓冲时间
 * @returns
 */
const retry = (promiseFn, times, delay) => {
  let time = 0;
  return new MyPromise((resolve, reject) => {
    const run = () => {
      console.log(`第${++time}次`);
      promiseFn().then(
        (value) => {
          resolve(value);
        },
        (error) => {
          if (time < times) {
            setTimeout(() => {
              run();
            }, delay || 0);
          } else {
            reject("超过次数");
          }
        }
      );
    };
    run();
  });

实现一个可以设置超时时间的异步函数的执行方法,返回值为一个 Promise 对象

const timeoutRunner = (promiseFn, timeout) => {};

const timeoutRunner = (promiseFn, timeout) => {
  // return new MyPromise((resolve, reject) => {
  //   promiseFn().then((value) => {
  //     resolve(value);
  //   }, reject);
  //   setTimeout(() => {
  //     reject("timeout");
  //   }, timeout);
  // });
  const timeoutPromise = new MyPromise((resolve, reject) => {
    setTimeout(() => {
      reject("timeout race");
    }, timeout);
  });
  return MyPromise.race([timeoutPromise, promiseFn()]);
};

发布订阅模式 & eventEmitter 实现,on off emit once

深拷贝

  • 递归实现深拷贝:适用于大多数情况,但需要注意循环引用。
  • JSON 序列化和反序列化:简单快速,但有一些限制。
  • 使用 Lodash 库的 _.cloneDeep 方法:功能强大,适用于各种复杂情况。
function deepClone(obj) {
  if (obj === null || typeof obj !== "object") {
    return obj;
  }

  if (obj instanceof Date) {
    return new Date(obj);
  }

  if (obj instanceof Array) {
    var arrCopy = [];
    obj.forEach(function (item, index) {
      arrCopy[index] = deepClone(item);
    });
    return arrCopy;
  }

  if (obj instanceof Object) {
    var objCopy = {};
    for (var key in obj) {
      if (obj.hasOwnProperty(key)) {
        objCopy[key] = deepClone(obj[key]);
      }
    }
    return objCopy;
  }

  throw new Error("Unable to copy object! Its type isn't supported.");
}

// 示例用法
var original = {
  name: "John",
  age: 30,
  date: new Date(),
  hobbies: ["reading", "travelling"],
  address: {
    city: "New York",
    zip: "10001",
  },
};

var copy = deepClone(original);
console.log(copy);

防抖节流

  • 防抖 Debounce,将多次执行变为最后一次执行,当触发事件时,会延迟一定时间去执行,如果在这段时间内再次触发事件,则重新计算延迟时间,适用于用户输入校验处理
  • 节流 Throttle,限制函数在一定时间内只能执行一次,适用于浏览器滚动处理

JS 数组去重

  • 使用 Set:最简洁和高效的方法。
  • 使用 forEach 和对象:利用对象属性名唯一性。
  • 手动遍历:最基本的方法,适合理解去重的原理。
  • 使用 filter 和 indexOf:适合理解和学习数组方法。
  • 使用 reduce 和 includes:适合理解和学习 reduce 方法。

分别使用 ES5 和 ES6 语法定义一个常量

ES5 语法:使用 Object.defineProperty 方法来定义常量,通过设置 writable 属性为 false 来确保常量不可修改。

Object.defineProperty(window, "MY_CONSTANT", {
  value: 42,
  writable: false,
  enumerable: true,
  configurable: false,
});

实现方案思路

  • Vue 命令式组件实现,注册全局弹窗
  • 多环境适配实现:策略模式和适配器模式
  • 商品列表信息卡片实现:UI 组件和业务组件分层实现

results matching ""

    No results matching ""