上一篇笔记记录了笔试内容,本篇笔记来记录一下面了两个小厂的面试问题总结吧。希望下一次面试可以成功避开这些坑,回答的更好一些。
两个面试感觉都是一上来就开始撕项目经历,根据项目来深入的问一些问题。
下面就梳理一下内容:
1、 能不能讲讲对webpack的理解以及webpack的工作原理?
webpack
是一个用于现代JavaScript应用程序的静态打包工具,webpack
在处理应用程序时,会在内部从一个或多个入口构建一个依赖图,将每个项目所需的每一个模块组合成一个或多个bundles
(均为静态资源)用于展示内容,依赖图对应映射到项目所需的每个模块,并生成一个或多个bundle
webpack
的构建流程:
- 初始化流程:从配置文件和Shell语句中读取与合并参数,并初始化需要使用的插件和配置插件等执行环境所需要的参数
- 编译构建流程:从
Entry
出发,针对每个Module
串行调用对应的Loader
去翻译文件内容,再找到该Moudel
依赖的Moudel
,递归地进行编译处理- 输出流程:对编译后的
Moudle
组合成Chunk
,把Chunk
转换成文件,输出到文件系统中。
2. 能不能讲讲vite和webpack的区别以及各自的优缺点?
首先,先讲讲
vite
的理解,作为vue团队开发的打包工具,其工作原理是根据源文件之间的依赖关系通过浏览器对ESM规范的支持来解析,将应用中的模块区分为依赖和源码两类。实现按需打包,极大的优化了打包速度。
vite
的核心理念就是借助浏览器原生ES Modules
能力,当浏览器发出请求时,为浏览器按需提供ES Module
文件,浏览器获取ES Module
文件会直接执行,即使首次启动的预构建也是使用速度惊人的esbuild
完成
优缺点分析
- 在首屏、懒加载性能方面,由于
webpack
本身经过了打包过程,得到了一个完整的模块关系依赖包,因此不存在这方面的性能问题。而对于vite
而言,由于unbundle
机制,在这方面会存在一定的问题,因此需要做额外的工作来处理。- 在服务启动速度方面,
webpack
需要将所有的模块建立依赖关系打包成一个大文件,速度相对较慢。而vite
将应用中的模块区分为依赖和源码两类,进行预构建,无需进行bundle
处理,速度会块很多。- 在热更新速度方面,
webpack
在编辑文件后将重新构建文件本身,即使使用动态模块热重载,其更新速度也会随着应用规模的增长显著下降。vite
编辑一个文件时,只需要精确地使已编辑的模块与其最近的HMR
边界之间的链失效,使HMR
更新始终快速,无论应用的大小。同时vite
利用http
头来加速整个页面的重新加载- 在pord环境打包的区别,
webpack
的构建更加成熟,bundle
整体形成完善的依赖关系,同时也有非常多的loader
plugin
可供选择。vite
在生产环境的构建目前用的是Rollup
而不是esbuild
,这是因为rollup
在应用打包方面更加成熟且灵活。- 对于生态成熟度而言,无疑
webpack
拥有一个庞大的生态系统,而vite
的生态系统目前是比不上webpack
的。总的来说,
vite
的使用体验感还是非常不错的。
3、es6篇,讲讲es6新增的特性吧
两次面试一来问的就是es6,包括梳理es6的新特性和使用。所以现在需要整理以下es6相关的内容。
1、let/const关键字
在上一篇博客中我们分析了这两个关键字的使用与var的区别:
- 一个是作用域区别,这两个关键字声明的变量都是块级作用域,
var
声明的变量是一个全局作用域的变量。 let
声明的变量不可重复声明,var
声明的变量可以重复声明,会覆盖前一次声明的值。let
和const
关键字声明的变量不存在变量提升,而var
关键字声明的变量存在变量提升。const
声明的变量是一个常数,不可修改其指针的指向。但是可以修改指针指向地址的值。因此可以修改引用数据类型的内容。const
声明的变量必须赋初值。
2、模板字符串
在es6以前,要输出字符串拼接变量的语句,通常使用占位符console.log('hello' + str);
这种方式 。而es6中新增的模板字符串,模板字符串使用反引号 ` (Tab 键上方的符号)来代替普通字符串中的用双引号和单引号。模板字符串可以包含特定语法 ${expression} 的占位符。占位符中的表达式和周围的文本会一起传递给一个默认函数,该函数负责将所有的部分连接起来。
console.log(`hello ${str}`)
输出结果与上面的语句输出结果一致。
同时,模板字符串中支持进行变量运算。
3、模块化导入和导出
默认导出:export default{默认导出成员}
每个模块中只允许默认导出一次
默认导入:import 接收名称 from '模块标识符'
按需导出:export 按需导出成员
每个模块中可以多次按需导出
按需导入:import {s1} from '模块标识符'
按需导入的成员名称必须和按需导出的名称保持一致,可以使用as
关键字进行重命名
按需导入可以和默认导入一起使用
4、变量的解构赋值
es6中允许按照一定模式从数组和对象中提取值,对变量进行赋值。
数组解构
const array = ['a','b','c','d'];
let [a,b,c,d] = array
下面括号的每一个变量都对象数组中相应位置的值。
对象的解构
const obj = {
name:'lili',
age:'18',
test: function(){
console.log('test')
}
}
let {name,age,test} = obj;
console.log(name);
console.log(age);
console.log(test);
test();
对象内的方法被解构出来后可以直接调用。
对象的简化写法
es6允许在一个大括号内直接写入对象的变量和函数,作为对象的属性和方法。
let name = 'aa';
let change = function(){
console.log('我们可以改变你');
}
const school = {
name,
change,
improve(){
console.log("bbb");
}
}
箭头函数及其特点
es6中允许使用 => 来声明一个函数。
let fn = (a,b)=>{
}
//简写形式
//形参有且只有一个时省略小括号
let fn = n => {}
//代码体只有一条语句时省略花括号
let fn = n => n*n;
箭头函数的特性:
- this是静态的,this的指向始终指向函数声明时所在作用域下的this值
- 不能作为构造实例化对象
- 不能使用arguments变量
因此,箭头函数适合与this无关的回调。
函数参数的默认值
es6中允许给函数参数赋值初始值
//1、形参初始值,具有默认值的参数,一般位置要靠后
function add(a,b,c=10){
return a+b+c;
}
//2、与解构赋值结合
function connect({host="127.0.0.1",username,password,port}){
console.log(host)
console.log(username)
console.log(password)
concole.log(port)
}
connect({
host:'localhost',
username:'root',
password:'root',
port:336
})
rest参数
ES6引入rest参数,用于获取函数的实参,用来代替arguments
//rest 参数
function date(...args){
concole.log(args);
}
date('阿娇','博智','撕毁');
//rest参数必须要放到参数的最后
function fn(a,b,...args){
concole.log(a);
concole.log(b);
console.log(args);
}
fn(1,2,3,4,5,6);
扩展运算符
…扩展运算符能将数组转换为逗号分隔的序列
//声明一个数组
const arr = ['a','b','c','d'];
//声明一个函数
function test(){
console.log(argument)
}
test(...arr)//等同于test('a','b','c')
Symbol
ES6 引入了一种新的原始数据类型Symbol,表示独一无二的值。它是JavaScript语言的第七种数据类型,是一种类似于字符串的数据类型
特点:
- Symbol的值是唯一的,用来解决命名冲突的问题
- Symbol值不能与其他数据进行运算
- Symbol定义的对象属性不能使用
for...in
循环遍历,但是可以使用Relect.ownKeys
来获取对象的所有键名
使用场景:给对象添加属性和方法,表示独一无二的值。
迭代器
迭代器是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署iterator
接口,就可以完成遍历操作
- ES6创造了一种新的遍历命令for…of循环,lterator接口主要供
for...of
消费 - 原生具备iterator接口的数据(可用for of遍历)
- Array
- Arguments
- Set
- Map
- String
- TypedArray
- NodeList
const xiyou = ['1','2','3','4'];
let iterator = xiyou[Symbol.iterator]();
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
Set和Map
ES6 引入了 Set 和 Map 作为新的数据结构。Set 是一种无重复元素的集合,Map 是一种键值对的集合。它们提供了方便的方法来处理数据集合和映射关系。以下是 Set 和 Map 的基本用法示例:
// Set的使用
const set = new Set();
set.add(1);
set.add(2);
set.add(3);
console.log(set.size); // 输出:3
console.log(set.has(2)); // 输出:true
// Map的使用
const map = new Map();
map.set('name', 'Zhangsan');
map.set('age', 20);
console.log(map.size); // 输出:2
console.log(map.get('name')); // 输出:Zhangsan
WeakMap和WeakSet
WeakMap 和 WeakSet 是弱引用版本的 Map 和 Set。它们的特点是,当对象被垃圾回收时,与之关联的键也会被自动删除。这对于避免内存泄漏非常有用。
面向对象方面的性质
es6中引入了类的概念,使得js更像一种面向对象的语言。可以用于定义一个原型类,并用于创建类的实例和类的继承。
知识点:
- class声明类
- constuctor定义构造函数初始化
- extends继承父类
- super调用父级构造方法
- static定义静态方法和属性
- 父类方法可以重写
Generator
Generator
是一种特殊的函数,可以通过 yield
语句暂停和恢复执行。它可以用于实现迭代器、异步操作和惰性求值等。
function* generator() {
yield 1;
yield 2;
yield 3;
}
const iterator = generator();
console.log(iterator.next().value); // 输出: 1
console.log(iterator.next().value); // 输出: 2
console.log(iterator.next().value); // 输出: 3
promise
ES6 引入了 Promise 对象,它提供了一种更优雅的方式来处理异步操作。Promise 可以链式调用,通过 then 和 catch 方法来处理成功和失败的情况。以下是 Promise 的基本用法示例:
function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Data fetched successfully.');
}, 1000);
});
}
fetchData()
.then(data => {
console.log(data); // 输出:Data fetched successfully.
})
.catch(error => {
console.error(error);
});
promise的出现解决了异步函数回调地狱的问题。es6梳理出来一些常用的特性就是这些了吧,没注意weakset和weakmap,面试官提起的时候知道有这个东西但是不知道区别呜呜呜呜。然后还有一些js问题,例如原型链,闭包以及this指向问题。一些vue框架的简单问题,都不是很深。今天写累了,明天继续。
讲讲什么叫BFC
BFC应该是我面了三家小厂都问了的问题。BFC(Block Formatting Content)-- 块级格式化上下文。
在JavaScript中,BFC是一种重要的布局概念,是目前最常用的清除浮动的方法,它有以下特点:
- BFC容器计算高度时包括浮动元素:一个BFC容器会将其内部的浮动元素的高度也计算在内,这有助于防止父元素塌陷并正确包裹浮动元素。
- 解决内外margin重叠的问题:当相邻元素的margin相遇时,margin合并,导致间距小于预期间距。但是在BFC容器内部,margin不会合并,可以更精确地控制元素之间的间距。
创建BFC的属性
- display:inline-block
- display:table-cell
- overflow:hidden / auto / overlay / scroll
overflow: hidden:当内容溢出容器的边界时,多余的内容将被隐藏,不可见。这意味着不会显示滚动条,也不会提供任何滚动功能。
overflow: auto:如果内容溢出容器的边界,滚动条会出现,允许用户滚动查看被隐藏的内容。如果内容未溢出,滚动条将自动隐藏。
overflow: overlay:这是一个相对较新的值,它与auto类似,但在某些情况下会显示一个轻量级的滚动条,而不是传统的滚动条。它的行为可能会因浏览器的不同而有所变化。
overflow: scroll:无论内容是否溢出,始终显示滚动条,允许用户滚动内容。即使内容未溢出,也会显示滚动条,但会被禁用。
- 弹性盒子(display:flex || inline-flex)
总结:
# BFC 容器 Block Formatting Content 块级格式化上下文
- 哪些属性可以触发BFC:
1. float: left || right
2. position: absolute || fixed
- 哪些属性可以创建BFC:
3. display: inline-block
4. display: table-cell ....
5. overflow: hidden || auto || overly || scroll
6. 弹性盒子 (display : flex || inline-flex)
- BFC的特点:
1. bfc容器在计算高度时,会将浮动元素的高度也计算在内
2. 用来解决内外margin重叠问题