202403
INFO
能熬到现在 说明运气不错,如果没有熬到,那就只需要努力即可 20240105
算法题犹如一座横亘在我面前的一座大山,什么时候才能翻过去?翻过去就能海阔天空?
0301
- 996 天, 95
- 偏函数的定义和应用场景?
- react18 自动批处理?
- 在 v18 之前,只有事件回调、生命周期回调中的更新会批处理,比如上例中的 onClick。而在 promise、setTimeout 等异步回调中不会批处理。
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
- 998,93
- 每次面试准备,都无从下手,如何化繁为简?只要回忆 60%核心内容,加强核心内容背诵
- 2023 行情不好,大龄员工如何跳槽
0304
- 999,92,这数字不错,吉祥如意
- 如果能成功进入到下一家,半年之内我会跟面试说拜拜,但是算法题永远不会说拜拜,天天记这些枯燥的术语感觉没啥大用
- 这几天,多多背诵核心知识点,巩固记忆(网络和浏览器相关),即使休息在家,天天看这些知识点,依然不能很好的记住,需要强化记忆,反复背诵
- 算法题核心算法,多练习几遍
- navigator.sendBeacon 优势:有机会异步地向服务器发送数据,同时不会延迟页面的卸载或影响下一个导航的载入性能
0305
1000,91
缺少架构经验? 如何结合项目,怎么补充
了解使用 rollup/vite/webpack 等打包工具以及前端性能优化? 这点如何结合项目经验,使得在面试的时候有话说?
application/json: 表示请求体是 JSON 格式的数据。 application/x-www-form-urlencoded: 表示请求体采用 URL 编码的表单数据。
0306
- 1001,90
- 果然什么时候,都不会准备好面试的?everyTime,接雨水我写了将近十遍还是遗忘,二叉树的最近公共祖先也是写了近十遍,递归还是写不出来,要命了
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
Navigator.sendBeacon 是一个现代的、轻量级的方法,它允许在不阻塞页面卸载的情况下发送数据。
navigator.sendBeacon("/api/data", JSON.stringify(data));
- 通过 HTTP POST 请求方式 异步 发送数据,同时不会延迟页面的卸载或影响下一导航的载入性能;
- 支持跨域,但不支持自定义 headers 请求头,这意味着:如果用户信息 Access-Token 是作为请求头信息传递,需要后台接口支持 url querystring 参数传递解析。需要考虑其兼容性。
0307
- 1002,89
总结 SEO 相关的知识?
区分 seo 产品和用户产品
不想分摊权重的链接加上 nofollow:告诉搜索引擎不要收录这个链接的网页
robots.txt:文件规定了搜索引擎抓取工具可以访问你网站上的哪些网址
404 页面做好引导
Details
前端之所有需要 类似于 Webpack 这样的构建工具,是为了提高项目的开发效率,Webpack 通过分析 js 中的 require 语句,分析出当前 js 文件所有的依赖文件,通过递归的方式层层分析后,得到整个项目的依赖关系图,对不同的文件执行不同的 loader,比如使用 css-loader 解析 css 代码,最后基于这个依赖关系图读取到整个项目中的所有文件代码,进行打包处理之后交给浏览器执行。
useCallback useMemo, 为什么会减少 render?
本质上,useMemo 和 useCallback 都是用来帮助我们优化 重新渲染 的工具 Hook。它们通过以下两种方式实现优化的效果。
- 减少在一次渲染中需要完成的工作量。
- 减少一个组件需要重新渲染的次数。
const [count, setCount] = useState(0);
// one
const handler = React.memo(() => {
return function () {
setCount((val) => val++);
};
}, []);
const handler = React.useCallback(() => {
setCount((val) => val++);
}, []);
换句话说就是以下的两种实现方式的效果是相同的:
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 的字符串(前缀和)
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
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 深度知识点还是容易被问倒,需要重塑以及温故。有些话你讲不出来的
Details
ES5 比较两个值是否相等 相等运算符() 和严格相等运算符(=)。它们都有缺点,前者会自动转换数据类型,后者 的 NaN 不等于自身,以及+0 等于-0。JavaScript 缺乏一种运算,在所有环境中,只要两个值 是一样的,它们就应该相等。
+0 === -0 //true
NaN === NaN // false
0bject.is(+0,-0) // false
0bject.is(NaN,NaN) //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 相关知识点和业务相关的复习
- 手写题计算质数的个数
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,其他的都是过眼云烟,一切向前看。坚持自己,坚持背书,坚持手写,坚持编程
- 生成数组?
// 当你需要要生成一个0-99的数组
const createArr = (n) => new Array(n).fill().map((index, v) => v);
createArr(100);
- 去除多余空格?
// 'hello, jack' => 'hello,jack'
var space = (str) => str.replace(/\s\s+/g, "");
space("hello, jack");
- 异步函数判断?
var isAsyncFunction = (fn) =>
Object.prototype.toString.call(fn) == "[object AsyncFunction]";
isAsyncFunction(async function () {});
0317
- 1012 79
- 保持健康,保存体力,准备开干
0318
- 1013 78
- 我就像一只拉磨的牛,天天拉,天天拉,天天拉,没有什么充实感可言。时间久了,顿感乏味,但弃之可惜,如何破局?
- 如何让 var [a, b] = {a: 1, b: 2} 解构赋值成功?
Object.prototype[Symbol.iterator] = function () {
// 使用 Object.values(this) 方法获取对象的所有值,并返回这些值的迭代器对象
return Object.values(this)[Symbol.iterator]();
};
- 如何让一个对象通过 forof 遍历
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 不能异步捕获代码错误
try {
setTimeout(() => {
throw new Error("err");
}, 200);
} catch (err) {
console.log(err, "error"); // 这里能否捕捉到错误?
}
在 JavaScript 中,setTimeout 是一个异步函数(宏任务),它的回调函数会在指定的延时后被放入事件队列,等待当前执行栈清空后才执行。因此,当 setTimeout 的回调函数执行并抛出错误时,try...catch 已经执行完毕,无法捕捉到异步回调中的错误
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
- 归并排序
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。
// 原型链继承
function mockExtends(Child, Parent, staticProps) {
const proto = Object.create(Parent.prototype);
proto.constructor = Child;
Child.prototype = proto;
// 继承静态方法和属性
Parent && Object.setPrototypeOf(Child, Parent);
}
// 构造函数继承
0327
- 1022,69,目标还是不能改变,就算躺平,躺平前。100 道手写题+100hot 算法题必须要掌握
- Node12+ 下 axios 包使用报错引发的对 package.json's exports 等属性以及 esm 的学习
- dp 太难了,还没开始做就发现都混淆了,
// 最长公共子串
// 最长重复子串
0328
- 1023,68
- includes 和 indexOf 的最大的区别? indexOf 是 === ,includes 是 ==
indexOf 要求严格,无法正确判断数组中是否有 NaN,但是 includes 可以
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 代码。
// 重载签名
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() 或展开运算符 ... 将类数组转换为数组。例如:
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 是什么意思? 如果要过滤数组中的空字符串,可以用简易写法:
[0, "0", " ", true, false, "", undefined, null].filter(Boolean);
// [' ', true, '0']
这句话的意思就是,把数组的元素,都用 Boolean 类进行包装,结果为 false 的自然被过滤出去了:
Boolean(0); // false
Boolean(true); // true
Boolean(3); // true
Boolean(""); // false
Boolean("false"); // true