恋の歌的logo
Auto
归档 标签

记录广州申迪的前端面试

发表于2024-11-28 22:18
更新于2024-11-28 22:18
分类于笔试
总字数1.2K
阅读时长 ≈5 分钟

前言 🔗

记录广州申迪的前端面试。

找了一个月工作了,投了简历很多都是没回复的,一个月只面试了 4 家。

感觉要回家送外卖了。

正文 🔗

这个公司需要先笔试,所以在那里填了差不多 1 个小时题目。

基本数据类型和复杂数据类型 🔗

这个没什么好说的,看给的多少个空,一定要填的为 numberstringbooleanundefinednull ,空多的话再协商 symbolbigint

复杂数据类型就是 object 对象。

盒子 margin-top 坍塌 🔗

给定两个块级盒子,上方盒子设置 margin-bottom: 10px 下方盒子设置 margin-top: 5px ,问两者的差距是多少。

这题主要考相邻盒子的 margin 坍塌(也称为外边距折叠)以及 BFC ,即 Block Formatting Context ,中文名为区块格式化上下文。

相邻盒子在默认情况下会发生 margin 坍塌,即会取 margin 大的一方作为两者的间距。所以该题答案为 10px

为了解决这种情况,需要让其中的一个盒子创建 BFC ,这样即可解决该问题,最简单地解决方法就是加上 overflow: hidden 使其创建 BFC 。

失焦的事件名 🔗

聚焦是 focus ,失焦是 blur

原型链 🔗

输出以下代码的结果

javascript
function o(name) {
  this.name = name;
}

o.protoType.print = function() {
  console.log(this.name);
}

const i = new o("dd");
i.name = "ee";
i.__proto__.name = "dd"
i.__proto__.print();
i.print();

问输出结果,这里需要对原型链有一些认识,o.protoTypei.__proto__ 为相同的对象,每个实例化的对象的 __proto__ 都指向它构造器的 protoType

接着我们需要知道,非箭头函数的调用的 this 取决于谁调用的它。

  • 对于 i.__proto__.print() 此时 thisi.__proto__
  • 对于 i.print() 此时 thisi

这里需要注意 i.printi.__proto__.print 为同一个函数, i.printi 上没有找到 print 方法后一直往原型链上面查找。

所以这道题的答案为 ddee

数组中插入元素的方法 🔗

这里给了三个空,应该是填 pushunshiftsplice

PS:这里弄混了 shiftunshift ,写成 shift 了, shift 为弹出头元素,给自己菜麻了😅。

  • push 在尾部插入一个元素。
  • unshift 在头部插入一个元素。
  • splice 可以指定某个位置删除并插入元素,只需把第二个参数设置为 0 ,那么就不会删除元素了,再指定第三个以后的参数就可以往该位置插值了。

地址栏输入地址到显示页面的过程 🔗

纯八股文,这种直接百度。

深拷贝与浅拷贝 🔗

浅拷贝可以用很多内置的方法实现,比如字面对象的展开,数组的展开:

javascript
const o = { a: 1, b: 2 };
const copy = { ...o };
javascript
const o = [1, 2, 3];
const copy = [...o];

或者使用 Object.assign 来进行浅拷贝:

javascript
const o = { a: 1, b: 2 };
const copy = Object({}, o);

深拷贝其实就是递归浅拷贝,当然也有一些方便的方法来进行快速的深拷贝。

如果对象不包含无法序列化的类型(比如 Function , Symbol , DOM 对象等),且没有循环引用,则可以使用 JSON.parse(JSON.stringify(obj))

javascript
const o = { a: 1, b: 2 };
const copy = JSON.parse(JSON.stringify(o));

如果你的执行环境够现代,你还可以使用 structuredClone 原生接口,它很好地处理了循环引用的情况,而且支持所有支持结构化克隆的类型,当然对于其他类型也是无法克隆的。

除此之外,还可以使用三方库,比如 lodash 的 clone ,不过它也是实现了结构化克隆的类型,如果还要支持其他不支持的类型,那就得手写克隆函数来处理对应的情况了。

手写一个节流(throttle)函数 🔗

可以基于时间戳或者 setTimeout 来实现。

setTimeout 的版本我们可以参考 radash 的实现:

javascript
const throttle = ({ interval }, func) => {
  let ready = true;
  let timer = void 0;
  const throttled = (...args) => {
    if (!ready)
      return;
    func(...args);
    ready = false;
    timer = setTimeout(() => {
      ready = true;
      timer = void 0;
    }, interval);
  };
  throttled.isThrottled = () => {
    return timer !== void 0;
  };
  return throttled;
};

基于 Date.now 实现:

javascript
function throttle(func, delay) {
  let lastCallTime = 0;

  const throttled = (...args) => {
    const now = Date.now();
    if (now - lastCallTime < delay) {
      return;
    }
    func(...args);
    lastCallTime = now;
  };

  return throttled;
}

手写一个解析地址栏参数的函数 🔗

写一个函数 ,要求根据当前 href 来解析 query 参数,即,如果访问 http://example.com?a=1&b=2 ,那么函数 fn("a") 返回 1fn("b") 返回 2

这道题直接使用 URL 对象来搞定,手写实现是不可能,只能调调 api 这个样子:

javascript
function fn(key) {
  const url = new URL(location.href);
  return url.searchParams.get(key);
}

当然如果要手写实现的话,其实就是那几个步骤:

  • 通过 location.search 拿到查询字符串。
  • 去掉 ? ,然后通过 & 分割。
  • 接着每一项通过 = 分割,索引 0 为键,索引 1 为值。
  • 返回对应值。
javascript
function fn(searchKey) {
  const queryString = location.search;
  const queryList = queryString.substring(1).split("&");

  for(let i = 0; i < queryList.length; i++) {
    const [key, value] = queryList[i].split("=");
    if (key === searchKey) {
      return decodeURIComponent(value);
    }
  }

  return null;
}
#JavaScript
#前端笔试题
哦呐该,如果没有评论的话,瓦达西...