【前端】字节商业化面经
7月初面的,当时面完去上号了,具体内容记不太清了,只记得三道手写题。
一面
时长:1 hour +
面试内容
常规八股
当时没记录呜呜,就是一些普通的八股文😭。
手写题
实现 lodash.get ✅
lodash.get 是一个常用的 JavaScript 库 Lodash 提供的一个函数,它用于安全地获取对象中的属性值,避免了在对象结构中可能出现的空引用错误。下面是一个简单的实现:
function get(object, path, defaultValue) {
// 将路径字符串转换成数组,以便逐层访问对象属性
const pathArray = Array.isArray(path) ? path : path.split('.');
// 逐层访问对象属性
for (let i = 0; i < pathArray.length; i++) {
// 如果当前层属性为 undefined 或 null,则返回默认值
if (object == null) {
return defaultValue;
}
// 访问下一层属性
object = object[pathArray[i]];
}
// 如果遍历完路径后对象仍不为 undefined 或 null,则返回该属性值
return object;
}
// 示例用法
const obj = {
a: {
b: {
c: 123
}
}
};
console.log(get(obj, 'a.b.c')); // 输出: 123
console.log(get(obj, 'a.b.d', 'default')); // 输出: 'default',因为路径 'a.b.d' 不存在
这个实现基本上模仿了 lodash.get 的行为,接受一个对象 object,一个路径 path,并提供一个可选的默认值 defaultValue。函数会根据给定的路径从对象中逐层获取属性值,如果获取失败则返回默认值。
第一次被问到,写出来了,但是比较暴力。
实现深拷贝 ✅
实现深拷贝需要考虑对象的所有属性,包括嵌套对象和数组,确保每个属性都被复制到一个新的对象中,而不是简单地复制引用。下面是一个简单的深拷贝实现:
function deepClone(obj) {
// 如果传入的是基本类型数据或null,则直接返回
if (obj === null || typeof obj !== 'object') {
return obj;
}
// 根据原始对象的类型创建一个新的空对象或数组
const newObj = Array.isArray(obj) ? [] : {};
// 遍历原始对象的属性
for (let key in obj) {
// 递归调用deepClone函数进行深拷贝,并将拷贝后的值赋给新对象的对应属性
newObj[key] = deepClone(obj[key]);
}
return newObj;
}
// 示例用法
const obj = {
a: 1,
b: [1, 2, 3],
c: {
d: 4,
e: [5, 6, 7]
}
};
const clonedObj = deepClone(obj);
console.log(clonedObj); // 输出深拷贝后的对象
这个实现会递归地遍历原始对象的属性,并使用相同的结构创建一个新的对象,从而实现深度复制。需要注意的是,这个简单的实现可能会在处理一些特殊情况时出现问题,例如循环引用或原型链上的属性,所以在实际使用中可能需要对其进行改进。
常规手写题。
-
LC改编算法题,中等难度,类似于:岛屿数量,最大岛屿面积 ✅
- 面试官还备注了说不用去LC搜了,改过的😂。改成了根据坐标获取岛屿面积,写过这两个题的解决这个还是没问题的。
二面
个人原因婉拒。
作者:LonelySnowman
链接:www.nowcoder.com/discuss/509…
来源:牛客网
字节data前端二面面经
二面跟一面完全不是一个级别啊!太难了!
二面面试官会深挖。你说不会,他会提示你,好尴尬啊,提示我我也不会啊,难受
体验不太好,也可能是我太菜
面到一半不到我就知道我凉了
菜鸡不适合字节😭
就在昨天字节给我打电话问我是否可以调剂,好吧可以,又要一面了
描述一下某个项目
手写
- 函数柯里化
难点
1. webpack的钩子函数
Webpack 是一个现代 JavaScript 应用程序的静态模块打包工具。Webpack 提供了一组钩子函数(Hooks),用于在构建流程中插入自定义逻辑,实现更灵活的构建流程和插件扩展。下面是一些常用的 Webpack 钩子函数:
-
entryOption:在解析入口文件之前调用,允许修改入口选项。
-
beforeRun:在运行编译之前调用,异步地触发构建流程。
-
run:开始运行编译时调用。
-
compile:在创建编译器实例时调用,返回 Compiler 对象。
-
compilation:在创建新的编译实例时调用,返回 Compilation 对象。
-
emit:在生成资源并将资源输出到目录之前调用。
-
afterEmit:在资源生成并输出到目录之后调用。
-
done:编译完成时调用,不论编译是成功还是失败。
-
failed:编译失败时调用。
-
beforeCompile:在编译器开始编译之前调用。
-
afterCompile:在编译器完成编译之后调用。
这些是一些常用的 Webpack 钩子函数,您可以根据需要选择合适的钩子函数来实现您的自定义逻辑。通过注册钩子函数并在适当的时机执行自定义代码,您可以实现诸如添加额外的功能、修改编译配置、优化输出结果等操作。
3. webpack的生命周期函数
Webpack 的生命周期函数是指在 Webpack 构建过程中,不同阶段触发的一系列事件。通过这些生命周期函数,可以方便地在构建过程中执行自定义逻辑,以实现各种定制化的需求。以下是 Webpack 构建过程中常用的生命周期函数:
-
初始化阶段(Initialization):
webpackOptionsValidationError:Webpack 配置验证错误时触发。environment:在初始化 Webpack 环境变量之前调用。afterEnvironment:在初始化 Webpack 环境变量之后调用。beforeRun:在开始执行构建前调用。
-
编译阶段(Compilation):
compile:在创建编译实例时调用。make:在编译器开始编译时调用。compilation:在创建新的编译实例时调用。emit:在生成资源并将资源输出到目录之前调用。
-
构建阶段(Building):
afterCompile:在编译器完成编译之后调用。thisCompilation:在创建新的编译实例时调用。normalModuleFactory:在模块工厂被创建时调用。contextModuleFactory:在上下文模块工厂被创建时调用。
-
生成阶段(Generation):
beforeCompile:在编译器开始编译之前调用。beforeRun:在开始执行构建前调用。
-
完成阶段(Completion):
done:编译完成时调用,不论编译是成功还是失败。failed:编译失败时调用。
这些生命周期函数允许开发者在构建的不同阶段插入自定义逻辑,例如添加额外的功能、修改编译配置、优化输出结果等。通过注册这些生命周期函数,并在适当的时机执行自定义代码,可以更灵活地控制 Webpack 构建流程,满足各种定制化的需求。
5. vue-loader是干啥的
vue-loader 是一个用于 Webpack 的 loader,用于解析和转换 Vue 单文件组件(.vue 文件)。它的主要作用是将 Vue 单文件组件中的模板、脚本和样式等内容解析成 JavaScript 模块,以便于在 Webpack 构建过程中进行打包处理。
vue-loader 的主要功能包括:
-
解析模板:将 Vue 单文件组件中的模板代码解析成 JavaScript 函数,以便在运行时渲染到 DOM 中。
-
解析脚本:将 Vue 单文件组件中的脚本代码解析成 JavaScript 模块,可以处理 ES6+ 语法、TypeScript 等,并且可以通过 Babel 等工具进行转译和优化。
-
解析样式:将 Vue 单文件组件中的样式代码解析成 JavaScript 模块,支持处理 CSS、Sass、Less 等样式语言,并且可以通过 PostCSS 等工具进行预处理和后处理。
-
提取静态资源:可以从 Vue 单文件组件中提取静态资源(如图片、字体等),并将其作为模块引入到 JavaScript 中,以便于 Webpack 进行处理和管理。
-
支持热重载:
vue-loader与 Vue CLI 等工具集成良好,可以实现开发环境下的热重载,即当 Vue 单文件组件发生变化时,页面可以实时更新而无需手动刷新。
总之,vue-loader 是 Vue.js 生态系统中的重要组成部分,它能够让开发者更加便捷地使用 Vue 单文件组件,并且与 Webpack 配合使用,实现高效的模块化开发和打包构建。
7. vue模板指令解析的原理和步骤,如v-model
Vue 模板指令(Directives)是 Vue.js 模板语法的一部分,用于在 DOM 中添加特殊的行为。例如,v-model 指令用于在表单元素和 Vue 实例的数据之间建立双向绑定。下面是解析 Vue 模板指令的原理和步骤:
-
编译阶段:
- Vue 在编译模板时,会将模板字符串解析成抽象语法树(AST)。
- 在解析过程中,Vue 会识别模板中的指令,并将其转换成相应的操作指令。
-
创建指令对象:
- 当 Vue 检测到模板中的指令时,会创建对应的指令对象。
- 指令对象包含指令名称、表达式、元素节点等信息。
-
指令解析:
- Vue 会根据指令名称和参数来执行相应的解析逻辑。
- 对于
v-model指令,Vue 会解析指令中的表达式,并确定其绑定的数据属性和事件监听。
-
数据绑定:
- 一旦指令解析完成,Vue 将在 Vue 实例的数据对象中创建对应的属性,并将其初始化为元素的初始值。
- 对于
v-model指令,Vue 会将表单元素的值与指定的数据属性建立双向绑定关系。
-
事件监听:
- Vue 会为指令所在的元素添加相应的事件监听器。
- 对于
v-model指令,Vue 会监听表单元素的输入事件,并在输入发生变化时更新绑定的数据属性的值。
-
响应式更新:
- 当绑定的数据属性发生变化时,Vue 会自动更新视图中相关的 DOM 元素。
- 对于
v-model指令,当表单元素的值发生变化时,绑定的数据属性也会相应地更新,从而实现双向绑定的效果。
总的来说,Vue 模板指令的解析过程是在编译阶段进行的,Vue 会将模板解析成抽象语法树,并根据指令名称和参数执行相应的解析逻辑,从而实现模板和数据的绑定以及特定行为的实现。
9. 屏幕刷新,一帧一帧的,浏览器每一帧都干些啥
在屏幕刷新过程中,浏览器会执行一系列的操作,以确保页面能够流畅地渲染在用户的屏幕上。这些操作通常包括以下步骤:
-
样式计算(Style Calculation):
- 浏览器需要计算出每个元素在页面上的最终样式。这包括从元素的 CSS 规则中继承样式,以及应用在元素上的各种样式规则。
-
布局计算(Layout):
- 浏览器需要确定每个元素在页面上的确切位置和大小。这个过程称为布局计算,也称为回流(reflow)。
-
绘制(Paint):
- 一旦浏览器确定了每个元素的样式和布局,它就会开始将页面上的元素绘制成像素。这个过程称为绘制。
-
合成(Composite):
- 最后,浏览器会将页面上的所有绘制操作合成为一个或多个图层,并将这些图层组合在一起形成最终的页面。这个过程称为合成。
这些步骤通常会在屏幕刷新的每一帧中重复执行,以确保页面的内容能够及时地显示在用户的屏幕上,并保持流畅的动画和交互效果。在现代浏览器中,这些步骤通常会由浏览器的渲染引擎(例如WebKit、Blink)负责执行,以确保页面能够以最佳的性能进行渲染。
11. 数据劫持的方法有哪些?除了defineproperty和proxy还有啥
除了 Object.defineProperty 和 Proxy,还有一些其他方法可以实现数据劫持,例如:
-
劫持原型链:可以通过修改对象的原型链来劫持属性访问。这种方法通常涉及到创建一个新的原型对象,并将其设置为目标对象的原型,从而在原型链中添加新的属性或方法。
-
重写原型方法:可以通过重写对象的原型方法来劫持属性访问。例如,可以重写对象的
toString方法来控制对象的字符串表示形式。 -
重写构造函数:可以通过重写对象的构造函数来劫持属性访问。这种方法通常涉及到创建一个新的构造函数,并在其中添加自定义逻辑,然后将其设置为目标对象的构造函数。
-
Object.observe:
Object.observe是一种原生的数据劫持方法,它可以用于监视对象的属性变化,并在属性变化时触发回调函数。不过需要注意的是,Object.observe已经被废弃,并且在现代浏览器中已经不再支持。
这些方法都可以用于实现数据劫持,但它们各自有不同的适用场景和实现方式。在选择数据劫持的方法时,需要根据具体的需求和场景来进行选择,并考虑其性能、兼容性等因素。
作者:牛客398208178号
链接:www.nowcoder.com/discuss/353…
来源:牛客网