Skip to content

202403

INFO

能熬到现在 说明运气不错,如果没有熬到,那就只需要努力即可 20240105

算法题犹如一座横亘在我面前的一座大山,什么时候才能翻过去?翻过去就能海阔天空?

0301

  • 996 天, 95
  • 偏函数的定义和应用场景?
  • react18 自动批处理?
  • 在 v18 之前,只有事件回调、生命周期回调中的更新会批处理,比如上例中的 onClick。而在 promise、setTimeout 等异步回调中不会批处理。
js
state = {
  a: 0
}
onClick() {
  this.setState({a: 1});
  console.log('a is:', this.state.a);
  this.setState({a: 2});
}
render() {
  const {a} = this.state;
  return <p onClick={this.onClick}>{a}</p>;
}
  • 在 React 并发模式中,引入了两个主要概念:任务调度和优先级。如何理解任务调度和优先级
Details

任务调度器负责决定哪些任务执行、何时执行以及中断和恢复任务。优先级允许 React 根据任务的紧迫性来安排任务的执行顺序,确保响应度更高的任务能够优先执行。

利用并发模式,React 可以将渲染过程分解为多个小任务,并根据优先级来动态调整任务执行的顺序。这样,在浏览器空闲时间或网络请求等异步操作期间,React 可以暂停当前任务,执行其他具有更高优先级的任务,以实现更爽快的用户交互体验。

总而言之,React 并发模式通过任务调度和优先级机制,提供了更好的用户体验和性能,使得 React 应用程序能够更加平滑地响应用户操作。

0302

  • 997,94
  • 面试次数还是太少,没有积累足够多的经验,没有什么信心不信心,干就是了
  • 每一次面对算法题都是历史与现在的交汇,历史我忘记得太快了,这就是时间的惩罚,解决办法就是不停重发默写,默写,直到记到骨子里,然后融入到脑子里

0303

0304

  • 999,92,这数字不错,吉祥如意
  • 如果能成功进入到下一家,半年之内我会跟面试说拜拜,但是算法题永远不会说拜拜,天天记这些枯燥的术语感觉没啥大用
  • 这几天,多多背诵核心知识点,巩固记忆(网络和浏览器相关),即使休息在家,天天看这些知识点,依然不能很好的记住,需要强化记忆,反复背诵
  • 算法题核心算法,多练习几遍
  • navigator.sendBeacon 优势:有机会异步地向服务器发送数据,同时不会延迟页面的卸载或影响下一个导航的载入性能

0305

  • 1000,91

  • 前端系统复习

  • react17Vsreact18

  • 缺少架构经验? 如何结合项目,怎么补充

  • 了解使用 rollup/vite/webpack 等打包工具以及前端性能优化? 这点如何结合项目经验,使得在面试的时候有话说?

  • application/json: 表示请求体是 JSON 格式的数据。 application/x-www-form-urlencoded: 表示请求体采用 URL 编码的表单数据。

0306

  • 1001,90
  • 果然什么时候,都不会准备好面试的?everyTime,接雨水我写了将近十遍还是遗忘,二叉树的最近公共祖先也是写了近十遍,递归还是写不出来,要命了
js
function publicAn(root, p, q) {
  if (root == null || p == root || q == root) return root;
  let left = publicAn(root.left, p, q);
  let right = publicAn(root.right, p, q);
  if (left != null && right != null) return root;
  if (left == null && right != null) return right;
  if (left == null && right != null) return left;
  return null;
}
  • 说说 Tree shaking(树摇)
Details

Tree shaking(树摇)是一种代码优化技术,它依赖于 ES6 模块(ES6 modules)的静态结构。Tree shaking 的工作原理是通过消除未使用的代码,从而减小最终的 bundle 大小。这个过程主要涉及到两个步骤:静态分析代码生成。Tree shaking 的主要优点是它可以减小 bundle 的大小,从而提高加载速度和运行效率

  • vite 打包工具涉及到的性能优化

Navigator.sendBeacon 是一个现代的、轻量级的方法,它允许在不阻塞页面卸载的情况下发送数据。

js
navigator.sendBeacon("/api/data", JSON.stringify(data));
  • 通过 HTTP POST 请求方式 异步 发送数据,同时不会延迟页面的卸载或影响下一导航的载入性能;
  • 支持跨域,但不支持自定义 headers 请求头,这意味着:如果用户信息 Access-Token 是作为请求头信息传递,需要后台接口支持 url querystring 参数传递解析。需要考虑其兼容性。

0307

  • 1002,89

总结 SEO 相关的知识?

  • 区分 seo 产品和用户产品

  • 不想分摊权重的链接加上 nofollow:告诉搜索引擎不要收录这个链接的网页

  • robots.txt:文件规定了搜索引擎抓取工具可以访问你网站上的哪些网址

  • 404 页面做好引导

  • 一句话解释 Webpack 的构建原理?

Details

前端之所有需要 类似于 Webpack 这样的构建工具,是为了提高项目的开发效率,Webpack 通过分析 js 中的 require 语句,分析出当前 js 文件所有的依赖文件,通过递归的方式层层分析后,得到整个项目的依赖关系图,对不同的文件执行不同的 loader,比如使用 css-loader 解析 css 代码,最后基于这个依赖关系图读取到整个项目中的所有文件代码,进行打包处理之后交给浏览器执行。

useCallback useMemo, 为什么会减少 render?

本质上,useMemo 和 useCallback 都是用来帮助我们优化 重新渲染 的工具 Hook。它们通过以下两种方式实现优化的效果。

  • 减少在一次渲染中需要完成的工作量。
  • 减少一个组件需要重新渲染的次数。
js
const [count, setCount] = useState(0);
// one
const handler = React.memo(() => {
  return function () {
    setCount((val) => val++);
  };
}, []);
const handler = React.useCallback(() => {
  setCount((val) => val++);
}, []);

换句话说就是以下的两种实现方式的效果是相同的:

js
React.useCallback(function helloWorld() {}, []);

// ...功能相当于:
React.useMemo(() => function helloWorld() {}, []);

0308

  • 1002, 88
  • 还有 2 天就面试了,从容心态面对,紧张没有用,面过这么多次,有啥好囧怕的。如果后面因为算法题没过,自己认命,如果不是因为算法题,那确实有点遗憾
  • nextjs 中的 ssr 和 ssg 中的怎么说
Details
  • SSR: getServerSideProps?
  • SSG: 静态渲染
  • ISG: 增量静态渲染

0309

  • 1003 87

next13 改动

  • Next 13 另一个比较大的改动是基于文件的路由系统,增加了一个 app 目录,每一层路由必须建一个文件夹,在该文件夹中建立 page.tsx 作为该路由主页面
  • 而在 Next.js 12(以及以下)对应的路由系统,是所有路由文件都写在 pages 目录下,每个文件都会生成一个路由,很明显是这种方式更加简洁。

那么,Next.js 为什么要改基于文件的路由系统呢? 主要有以下 3 点原因:

  • 实现嵌套路由和持久化缓存
  • 支持 React 18 中的 React server Component,实现 Streaming(流渲染)
  • 实现代码目录分组,将当前路由下的测试文件、组件、样式文件友好地放在一起,避免全局查找

0310

  • 1004 86
  • 前端知识看久了,也不知道自己哪一块掌握哪一块没掌握,反正就是一个字乱,不知道从哪里开始复习和准备。在职准备比不在职准备还要痛苦,要命了,今天最后一次冲刺,只要自己努力就行,其他的随缘

rust 正在全面入侵前端

Turbopack 同样是一款基于 rust 构建的前端项目构建工具。Turbopack 建立在新的增量架构上,在打包时只关注开发所需的最小资源,因此不管是启动速度还是 hmr 速度,都有远超 vite 的性能。

Vue 团队正式开源 Rolldown:基于 Rust 的超快 JavaScrip 打包工具!

  • Vue 团队正式开源了其对外公布已久的打包工具:Rolldown,它是使用 Rust 开发的 Rollup 替代品,提供了与 Rollup 兼容的 API 和插件接口,但在功能范围上将更接近 Esbuild 目前,Vite 的底层使用了两个打包工具:

  • Esbuild:Esbuild 是一款高性能的 JavaScript 打包器,专注于实现极速的构建过程。它支持多种模块类型、语法转换和插件扩展,且无需缓存即可迅速完成打包任务。在 Vite 中,Esbuild 被用于依赖预打包、TypeScript 和 JSX 转换、目标降级以及代码压缩

  • Rollup:Rollup 是一个 JavaScript 模块打包器,能够编译小块代码成复杂的大型代码块,特别支持 ES6 模块。它支持 Tree Shaking,有效去除未使用的代码,减少最终文件大小。在 Vite 中,Rollup 被用于生产构建,并支持一个与 Rollup 兼容的插件接口。 vite 之所以采用两者原因是, esbuild 速度快且功能丰富,但不适合代码拆分,rollup 虽在打包方面成熟,但性能却不及原生编译工具

0311

  • 1005 85
  • 不到三个月,4 月 10 号/5 月 10 号/6 月 10 号,应该在 5 月的时候,会告知你滚蛋,所以,接下来的三个月,比较关键,不能懈怠,相信自己的算法还是有进步的
  • 从去年 8 月开始默写,8/9/11/12/1/2 半年的时间手写,应该问题不大,自信一点,大概能写出基本的。后序还要归纳总结,不能服输。
  • 面试前,还是会特别紧张,而且脑子里老是胡思乱想,很难做到专注
  • 和为 k 的字符串(前缀和)
js
function perfixSum(nums, k) {
  let m = new Map([[0, 1]]);
  let sum = 0,
    count = 0;
  for (let num of nums) {
    sum += num;
    if (m.has(sum - k)) {
      count += m.get(sum - k);
    }
    if (m.has(sum)) {
      m.set(sum, m.get(sum) + 1);
    } else {
      m.set(sum, 1);
    }
  }
  return count;
}
  • 手写 useTimeout/useEvent/useToggle
js
const useTimeout = (fn, delay) => {
  const fnRef = useRef(fn);
  useEffect(() => {
    fnRef.current = fn;
  }, []);
  useEffect(() => {
    if (delay < 0 || !delay) return;
    let timer = setTimeout(() => {
      fnRef.current();
    }, delay);
    return () => {
      clearTimeout(timer);
    };
  }, [delay]);
};
// 在组件多次 render 时保持引用一致
const useEvent = (fn) => {
  const fnRef = useRef(fn);
  useEffect(() => {
    fnRef.current = fn;
  }, []);
  return useCallback((...arg) => {
    fnRef.current(...arg);
  }, []);
};
const useToggle = (init) => {
  const [toggle, setToggle] = useState(init);
  const changeToggle = useCallback(() => {
    setToggle((val) => !val);
  }, []);
  return [toggle, changeToggle];
};

0312

  • 1006 84

  • 昨晚还是没有休息好,还是在想昨天面试的事,手写题依然要不断巩固,同时多刷几次面试,特别是哪些不想去的,多争取几次机会

  • react 深度知识点还是容易被问倒,需要重塑以及温故。有些话你讲不出来的

  • Object.is

Details

ES5 比较两个值是否相等 相等运算符() 和严格相等运算符(=)。它们都有缺点,前者会自动转换数据类型,后者 的 NaN 不等于自身,以及+0 等于-0。JavaScript 缺乏一种运算,在所有环境中,只要两个值 是一样的,它们就应该相等。

js
+0 === -0 //true
NaN === NaN // false

0bject.is(+0-0) // false
0bject.is(NaNNaN) //true

0313

  • 1008 83
  • tree-shaking 的操作是文件级别还是函数级别的?
  • 终其一生,我的追求是什么?我自己也不知道,只感觉世界对每个人都是不公平的,尽管你非常努力,非常努力,但是依然没啥用?说明还没有努力到头?

react 渲染流程

在 16 之后,为了优化性能,会先把 vdom 转换成 fiber,也就是从树转换成链表,然后再渲染。整体渲染流程分成了两个阶段:

  • render 阶段:从 vdom 转换成 fiber,并且对需要 dom 操作的节点打上 effectTag 的标记
  • commit 阶段:对有 effectTag 标记的 fiber 节点进行 dom 操作,并执行所有的 effect 副作用函数。

从 vdom 转成 fiber 的过程叫做 reconcile(调和),这个过程是可以打断的,由 scheduler 调度执行。 diff 算法作用在 reconcile 阶段: 1.第一次渲染不需要 diff,直接 vdom 转 fiber。 2.再次渲染的时候,会产生新的 vdom,这时候要和之前的 fiber 做下对比,决定怎么产生新的 fiber,对可复用的节点打上修改的标记,剩余的旧节点打上删除标记,新节点打上新增标记

0314

  • 1009 82
  • 项目深度,还是需要在挖挖深度,准备好

0315

  • 10010 81
  • 距离跑路的时间渐近,自己多需要点耐心和毅力? > 可惜事与愿违,已经没有机会了
  • 等了好久也没等到通知,但我是打不死的小强,题目继续卷起来,每天都要练习手写编程题,练习的时候也要动一动自己精贵的脑袋,不能写了几十遍还会忘记
  • 重点背诵 react 相关知识点和业务相关的复习
  • 手写题计算质数的个数
js
function getPrime(n) {
  let count = 0;
  for (let i = 2; i <= n; i++) {
    if (isPrime(i)) {
      count++;
    }
  }
  return count;
}
function isPrime(n) {
  for (let i = 2; i * i <= n; i++) {
    if (n % i === 0) return false;
  }
  return n > 1;
}
getPrime(10);

0316

  • 1011 80
  • 每个人都有自己的使命,而我的使命就是成为更好的自己,拿下心仪公司的 offer,其他的都是过眼云烟,一切向前看。坚持自己,坚持背书,坚持手写,坚持编程
  • 生成数组?
js
// 当你需要要生成一个0-99的数组
const createArr = (n) => new Array(n).fill().map((index, v) => v);
createArr(100);
  • 去除多余空格?
js
// 'hello,   jack' => 'hello,jack'
var space = (str) => str.replace(/\s\s+/g, "");
space("hello,   jack");
  • 异步函数判断?
js
var isAsyncFunction = (fn) =>
  Object.prototype.toString.call(fn) == "[object AsyncFunction]";
isAsyncFunction(async function () {});

0317

  • 1012 79
  • 保持健康,保存体力,准备开干

0318

js
Object.prototype[Symbol.iterator] = function () {
  // 使用 Object.values(this) 方法获取对象的所有值,并返回这些值的迭代器对象
  return Object.values(this)[Symbol.iterator]();
};
  • 如何让一个对象通过 forof 遍历
js
class MockIterator {
  constructor(obj) {
    this.obj = obj;
    this.len = Object.keys(obj).length;
    this.index = 0;
  }
  [Symbol.iterator]() {
    return this;
  }
  next() {
    return this.index < this.len
      ? { value: this.obj[this.index++], done: false }
      : {
          value: undefined,
          done: true,
        };
  }
}

ssr 项目痛点?

  • Serverless 云函数: 云计算发展过程中出现的一种计算资源的抽象,它以云计算平台为基础,为开发者提供业务程序的运行环境,开发者无需关注底层资源分配、扩容部署,代码执行所必要的全部服务由平台提供。
  • 做 Serveless SSR 服务,免去运维部署烦恼,减少直出接入成本!

0319

  • 1014 77,离开的日子越来越近,可惜还没有找到合适对口的公司,该何去何从呢!
  • 好的公司竞争力太大,没有高学历,专业又不对口,简历都过不了!要命,感觉又回到 7 年前,7 年前,刚开始接入编程,投啥公司都没人理,最后感谢南京厚建接纳了我,让我入门了前端开发,感谢老东家,如果有可能,回老东家养老还是非常好的。
  • 彻底放弃幻想,开始另寻出路,我还是想做出点内容,不然成为程序员碌碌无为,没有给后代留下什么。

0320

  • 1015,76
  • 我还比人家多一年经验,什么都没有留下,大佬,真的是强,佩服五体投地,强烈推荐大佬的文章2023 前端年度技术总结
  • 没有一个领域进行深耕,随着年纪增大,早晚有一天会被时代淘汰的。一想到这个就睡不着,神经绷紧了
  • 真没算法的头脑,天天逼自己刷题有意义吗?刷题也比不过应届生,真的失败
  • 学一学得物如何进行性能优化

0321

  • 1016,75
  • 身体出现亚健康信号,再次上火,打开调试:iting://xmdebugger?index=main
  • try...catch 不能异步捕获代码错误
js
try {
  setTimeout(() => {
    throw new Error("err");
  }, 200);
} catch (err) {
  console.log(err, "error"); // 这里能否捕捉到错误?
}

在 JavaScript 中,setTimeout 是一个异步函数(宏任务),它的回调函数会在指定的延时后被放入事件队列,等待当前执行栈清空后才执行。因此,当 setTimeout 的回调函数执行并抛出错误时,try...catch 已经执行完毕,无法捕捉到异步回调中的错误

js
function isSimilar(a, b) {
  if (a.length != b.length) return false;
  let m = new Map();
  for (let item of a) {
    m.set(item, m.get(item) + 1 || 1);
  }
  for (let item of b) {
    let val = m.get(item);
    if (val == undefined || val <= 0) return false;
    m.set(item, val - 1);
  }
  return true;
}
const array1 = ["apple", "banana", "cherry", "banana"];
const array2 = ["banana", "apple", "banana", "cherry"];

isSimilar(array1, array2);

0322

  • 1017,74
  • 在努力挣扎最后一次,能不能好一点就看最近这半个月了

0323/24

  • 1018, 73/72

0325

  • 1020, 71
  • 归并排序
js
function mergeSort(arr) {
  let merge = (l, r) => {
    let i = 0,
      j = 0;
    let res = [];
    while (i < l.length && j < r.length) {
      if (l[i] < r[j]) {
        res.push(l[i++]);
      } else {
        res.push(r[j++]);
      }
    }
    while (i < l.length) {
      res.push(l[i++]);
    }
    while (j < r.length) {
      res.push(r[j++]);
    }
    return res;
  };
  let sort = (arr) => {
    if (arr.length == 1) return arr;
    let mid = Math.floor(arr.length / 2);
    let l = arr.slice(0, mid);
    let r = arr.slice(mid);
    return merge(mergeSort(l), mergeSort(r));
  };
  return sort(arr);
}
mergeSort([11, 22, 1, 24, 3, 4]);

0326

  • 1021,70
  • 天天手写,不带脑子思考,写几百遍都没有用,总有一天你会心累的。你自己就是个面试机器人,毫无情感
  • 我挺羡慕那些主动辞职的人,只有没有啥奔头的人才继续留在这里。
  • 手写题 hot 100 + 算法题 hot100,搞完就躺平,多会几道题也无济于事,把这些天搞懂,基本没啥问题
  • sse 和 websocket 区别

SSE(Server-Sent Events)和 WebSocket 都是用于实现服务器与客户端之间实时双向通信的技术。虽然它们都可以用于实时更新数据,但它们在实现方式、特点和适用场景上有着明显的区别。

ES5 的继承和 ES6 的继承有什么区别?

  • ES5 的继承时通过 prototype(构造函数机制) 来实现。ES5 的继承实质上是先创建子类的实例对象,然后再将父类的方法添加到 this 上(Parent.call(this))

  • ES6 的继承机制完全不同,实质上是先创建父类的实例对象 this(所以必须先调用父类的 super()方法),然后再用子类的构造函数修改 this。

js
// 原型链继承
function mockExtends(Child, Parent, staticProps) {
  const proto = Object.create(Parent.prototype);
  proto.constructor = Child;
  Child.prototype = proto;
  // 继承静态方法和属性
  Parent && Object.setPrototypeOf(Child, Parent);
}
// 构造函数继承

0327

js
// 最长公共子串

// 最长重复子串

0328

  • 1023,68
  • includes 和 indexOf 的最大的区别? indexOf 是 === ,includes 是 ==

indexOf 要求严格,无法正确判断数组中是否有 NaN,但是 includes 可以

js
let arr = [NaN, 1, undefined];
console.log(arr.includes(NaN)); // true
console.log(arr.indexOf(NaN)); // -1
// undefined不受影响
console.log(arr.includes(undefined)); // true
console.log(arr.indexOf(undefined)); // 2
  • import 和 require 的区别?

0329

  • 1024,67
  • react keep-alive 是怎么做的?
  • ts 的函数重载怎么做的? 在 TypeScript 中,函数重载是一种类型定义的特性,它允许你为同一个函数提供多个类型签名。这样做的目的是为了在 API 文档中提供更清晰的指导,同时也能在一定程度上帮助 IDE 进行类型检查和自动补全。需要注意的是,TypeScript 编译器只在编译阶段使用函数重载签名进行参数类型检查,并不会影响最终生成的 JavaScript 代码。
ts
// 重载签名
function addq(a: string, b: string): string;
function addq(a: number, b: number): number;

// 函数实现
function add(a: any, b: any): any {
  return a + b;
}

console.log(add("hello", "world")); // hello world
console.log(add(1, 2)); // 3
  • new String('123')和 String('123')有什么区别,new String('123')==String('123')吗,typeof 判断这两个是什么

0330

  • 1025,66
  • 数组和类数组区别
Details
  • 定义 数组是使用数组字面量 [] 或者 new Array() 显式定义的。 类数组通常是一个对象,它具有数字索引属性和 length 属性,但没有数组的内置方法。常见的类数组包括函数的 arguments 对象、NodeList 对象、HTMLCollection 对象等。
  • 原型链:

数组的原型链指向 Array.prototype。 类数组的原型链指向 Object.prototype。

  • 属性和方法: 数组继承了 Array.prototype 上的所有属性和方法,如 push、pop、slice 等。 类数组没有继承任何数组方法,需要使用函数方法或 ES6 新增的数组方法才能操作类数组。

虽然类数组和数组有区别,但是可以使用 ES6 新增的 Array.from() 或展开运算符 ... 将类数组转换为数组。例如:

js
let arrayLike = { 0: "a", 1: "b", 2: "c", length: 3 };
let arr = Array.from(arrayLike); // ['a', 'b', 'c']
let arr2 = [...arrayLike]; // ['a', 'b', 'c']

0331

  • 1026 65
  • Array.filter(Boolean)中的 Boolean 是什么意思? 如果要过滤数组中的空字符串,可以用简易写法:
js
[0, "0", " ", true, false, "", undefined, null].filter(Boolean);
// [' ', true, '0']

这句话的意思就是,把数组的元素,都用 Boolean 类进行包装,结果为 false 的自然被过滤出去了:

js
Boolean(0); // false
Boolean(true); // true
Boolean(3); // true
Boolean(""); // false
Boolean("false"); // true