最近在结合自己整理一些面试会考的题目(猜测),也算是对自己知识的一个总结和整理,想起来某些方面会更新进来~
CSS相关
选择器
css目前有标签选择器、类选择器、id选择器、伪类选择器等等 css3还增加了子代选择器、兄弟选择器等等。
参考MDN伪类列表
:link、:active、:hover、:focus、:first-child、:nth-child、:nth-last-child、:nth-of-type、:first-of-type、:last-of-type、:target、:checked、:enabled、:disabled
伪类和伪元素的区别
伪类是一个以冒号:作为前缀,被添加到一个选择器末尾的关键字,当你希望样式在特定状态下才被呈现到指定的元素时,可以往元素的选择器后面加上对应的伪类。
伪元素用于创建一些不在文档中的元素,并为其添加样式。比如说,可以通过::before来在一个元素前添加一些文本,并为这些文本添加样式。虽然用户可以看到这些文本,但是这些文本实际上不在文档树中。
选择器权重
css选择器的优先级是:内联 > ID选择器 > 类选择器 > 标签选择器
ID选择器权重可以看为1000
类选择器权重可以看为100
标签选择器权重可以看为10
盒模型
盒模型由content(内容)、padding(内边距)、border(边框)、margin(外边距)组成。
标准盒模型和怪异盒模型的区别?
在W3C标准下,我们定义元素的width值即为盒模型中的content的宽度值,height值即为盒模型中的content的高度值。
因此,标准盒模型:
元素的宽度 = margin-left + border-left + padding-left + width + padding-right + border-right + margin-right
怪异盒模型(IE盒模型)width的宽度并不是content的宽度,而是border-left + padding-left + content的宽度值 +padding-right + border-right之和,height同理。
因此,怪异盒模型:
元素占据的宽度 = margin-left + width + margin-right
虽然现代浏览器默认使用W3C的标准盒模型,但是不少情况下怪异盒模型更好用,于是W3C在css3中加入box-sizing
box-sizing: content-box // 标准盒模型
box-sizing: border-box // 怪异盒模型
box-sizing: padding-box // 火狐的私有模型,没人用
水平垂直居中
- 定位
- flex布局
- grid
详情参考我的另一篇整理 juejin.cn/post/693565…
有哪些方式可以隐藏页面元素?
- opacity:0。本质上是将元素的透明度为0,视觉上看起来隐藏了,但是依然在文档流中且可以互相交互。
- visibility:hidden。与上一个方法类似的效果,依然占据空间,但是不可以交互了。
- overflow:hidden。这个只隐藏元素溢出来的部分,跟visibility一样。占据空间,但是不可以交互。
- display:none。这个是彻底隐藏了元素,元素从文档流中消失,既不占据空间也不可以交互,对布局也没有影响。
- z-index:-9999。原理是将层级放到了底部,这样就被覆盖了,看起来隐藏了。
- transform:scale(0,0):平面变换。将元素缩放为0,但是依然占据空间,但是不可以交互。
还有一些靠绝对定位把元素移动到可视区外。
BFC
书面解释:BFC(Block Formatting Context)
一块独立的区域,让处于BFC内部的元素与外部的元素互相隔离。
如何生成?
BFC触发条件:
- 根元素
- position:fixed/absolute
- float不为none
- overflow不为visible
- display为inline-block、table-cell、table-caption
作用?
- 防止margin重叠
- 防止元素塌陷
- 两栏布局,防止文字环绕
em/px/rem区别?
- px:绝对单位,页面按精确像素展示。
- em:相对单位,基准点为父节点字体的大小,如果自身定义了font-size按自身来计算(浏览器默认字体是16px)整个页面内1rem不是一个固定的值。
- rem:相对单位,可理解为“root em”,相对根节点html的字体大小来计算,CSS3新加属性。
flex(自我认为这个可以解决所有)
web应用有不同设备尺寸和分辨率,这时需要响应式界面设计来满足复杂的布局需求,Flex弹性盒模型的优势在于开发人员只是声明布局应该具有的行为,而不需要给出具体的实现方式,浏览器负责完成实际布局,当布局涉及到不定宽度,分布对⻬的场景时,就要优先考虑弹性盒布局。
动画、过渡等
animation、transition
css有几种定位方式?
- static:正常文档流定位,此时top、right、bottom、left和z-index无效,块级元素从上往下纵向排布,行级元素从左向右排列。
- relative:相对定位,此时的「相对」是相对于正常文档流的位置。
- absolute:相对于最近的非static定位祖先元素的偏移,比如一个绝对定位元素它的父级、和祖父级都为relative,它会相对他的父级产生偏移。
- fixed:指定元素相对于屏幕视口的位置来指定元素位置。元素的位置在屏幕滚动时不会改变,比如那种回到顶部的按钮一般都是采用这种定位方式。
- sticky:粘性定位,特性近似于relative和fixed的合体,其在实际应用中的近似效果就是ios通讯录滚动的时候的「顶屁股」。
如何理解z-index
css中的z-index属性控制重叠元素的垂直叠加顺序,默认元素的z-index为0,可以修改z-index来控制元素的图层位置,而且z-index只能影响设置来position的元素。
JS相关
变量提升
JavaScript引擎的工作方式是,先解析代码,获取所有被声明的变量,然后再一行一行地运行。这造成的结果,就是所有的变量声明语句,都会被提升到代码头部,这就叫做变量提升。函数的提升优于变量的提升。
console.log(a); // undefined
var a = 33;
function b() {
console.log(a);
}
b(); // 1
数据类型
分为原始数据类型和引用数据类型。
原始数据类型按值存储,引用数据类型按地址存储。前者存在栈内,后者存在堆内。
原始数据类型:null、undefined、string、boolean、number、symbol、bigInt
引用数据类型:object
判断类型
typeof
typeof 可以判断基本数据类型,null除外
null严格意义上来说是一个空对象指针,判断为object。
Array.isArray
判断数组可以用isArray来判断是否是一个数组
let testArr = [1,2,3,4];
Array.isArray(testArr); // true
toString.call()
也可以用Object.prototype.toString.call() 来进行判断。每一个继承 Object 的对象都有 toString 方法,如果 toString 方法没有重写的话,会返回 [Object type],其中 type 为对象的类型。
instanceof
instanceof 运算符也可以用来判断某个构造函数的 prototype 属性所指向的對象是否存在于另外一个要检测对象的原型链上。因为数组的构造函数是 Array,所以可以通过以下判断。注意:因为数组也是对象,所以 数组 instanceof Object 也为 true
ES2020新增??和?.
可以参考我的这篇文章
为什么会有BigInt?
WHAT
BigInt是一种内置对象,它提供了一种方法来表示大于2的53次方-1的整数。这个原本是JavaScript中可以用Number表示的最大数字。BigInt可以表示任意大的整数。
WHY
在JS中,所有的数字都以双精度64位浮点格式表示,这导致JS中的Number无法精确表示非常大的整数,它会将非常大的整数四舍五入,确切地说,JS中的Number类型只能安全地表示-9007199254740991(-(2^53-1))和9007199254740991((2^53-1)),任何超出此范围的整数值都可能失去精度。
HOW
要创建BigInt,只需要在数字末尾追加n即可。另一种方式是BigInt()构造函数。BigInt和number不是严格相等的,是宽松相等。
this指向相关
this的指向不是在编写的时候确定的,而是在执行的时候确定的,同时,this不同的指向在于遵循来一定的规则。在哪里调用,this指向哪里。
-
首先,在默认情况下,this是指向全局对象的,比如在浏览器就是指向window。
-
其次,如果函数被调用的位置存在上下文对象时,那么函数是被隐式绑定的。
-
当new一个实例,this会指向new出来的新对象。
-
对于箭头函数,箭头函数本身是没有this指向的,所以箭头函数也不能改变this指向,详情看下一题。
箭头函数this指向
箭头函数不同于传统JavaScript中的函数,箭头函数没有属于自己的this,是继承父级函数的this指向,也就是说箭头函数所谓的this是捕获其所在上下文的this值,作为自己的this值,并且由于没有属于自己的this,所以箭头函数的this是不可改变的。
call、apply、bind区别
call、apply、bind都是改变this指向。
call
当前实例通过原型链查找机制,找到function.prototype上的call方法。
把找到的call方法执行,当call方法执行的时候,内部处理了一些事情。
- 首先把要操作的函数中的this关键字变为call方法一个传递的实参。
- 把call方法第二个及之后的实参获取到。
- 把要操作的函数执行,并且把第二个以后传递进来的实参传递给函数。
fn.call([this],[param]...)
apply
和call基本一致,唯一区别在于传参方式。apply把需要传递给fn的参数放到一个数组(或者类数组)中传递进去,虽然写的是一个数组,但是也相当于给fn一个个的传递。
fn.call(obj, 1, 2);
fn.apply(obj, [1, 2]);
bind
bind,语法跟call一样,但是bind不是立即执行,bind需要手动执行。
fn.call(obj, 1, 2); // 改变fn中的this,并且把fn立即执行
fn.bind(obj, 1, 2); // 改变fn中的this,fn并不执行
总结:都是改变this指向,call是一个个传参、apply是以数组的形式传参,bind也是一个个传参,但是bind不会立即执行,需要手动触发。
如何实现上面三个?
原型、原型链
原型对象
绝大部分的函数(少数内建函数除外)都有一个prototype属性,这个属性是原型对象用来创建新对象实例,而所有被创建的对象都会共享原型对象,因此这些对象便可以访问原型对象的属性。
原型链
原因是每个对象都有 proto 属性,此属性指向该对象的构造函数的原型。
对象可以通过 proto 与上游的构造函数的原型对象连接起来,而上游的原型对象也有一个 proto ,这样就形成来原型链。
作用域
闭包
闭包其实就是一个可以访问外部函数变量的函数,简单理解为就是一个函数嵌套着另一个函数,内部函数可以访问外部函数的变量和值,避免垃圾回收机制。其实闭包就两个作用,一个是保护,一个是保存。比如jquery就是利用闭包的保护机制,避免jquery自己的方法因为和外面使用者定义的函数名相同而造成全局污染。而保存机制就是,执行一个函数会形成一个私有栈内存,一般来说当函数执行完毕,私有栈内存就会被释放和销毁,但是一旦当前私有栈内存里面的东西被其他的函数所占用了,那么当前私有栈内存就不会被释放和销毁掉。
Promise
防抖和节流
继承
可以参考我这篇文章
0.1+0.2 !== 0.3,为什么
JS的number类型遵循的是IEEE 754标准,使用的是64位固定长度来表示。IEEE 754浮点数由三个域组成,分别为sign bit(符号位)、exponent bias(指数偏移值)和fraction(分数值)。64位中,sign bit占1位,exponent bias占11位,fraction占52位。
当一个数为正书,sign bit为0;当为负数时,sign bit为1。
怎么解决0.1+0.2 !== 0.3
面向对象编程(在我实习面试的时候,总会考到)
浏览器相关
浏览器的主要组成部分是什么?
- 用户界面
- 浏览器引擎
- 呈现引擎
- 网络
- 用户界面后端
- JavaScript解释器
- 数据存储
简述浏览器是如何渲染UI的?
- 浏览器获取HTML文件,然后对文件进行解析,形成DOM Tree。
- 与此同时,进行css解析,生成style rules。
- 接着将DOM Tree与style rules合成为render tree。
- 接着进入布局(layout)阶段,也就是为每一个节点分配一个应出现在屏幕上的确切坐标。
- 随后调用GPU进行绘制,遍历render tree的节点,将元素呈现出来
缓存
重绘和重排
- 重排:部分渲染树需要重新分析并且节点尺寸需要重新计算,表现为重新生成布局,重新排列元素。
- 重绘:由于节点的几何属性发生改变或者由于样式发生改变,例如元素背景色改变,屏幕上的部分内容需要更新,表现为某些元素的外观被改变。
两者相比,重排的性能影响更大。
「重绘」不一定会出现「重排」,「重排」一定会出现「重绘」。
事件循环机制
JavaScript是一个单线程。单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。为了解决等待问题,JS的任务分为同步任务、异步任务。
所有的同步任务都在主线程执行,形成了一个执行栈。异步任务不进入主线程,而是进入一个「任务队列」。同步任务顺序执行,只有执行栈中的同步任务执行完了,系统才会读取任务中异步任务,才会把异步任务从事件队列中放入执行栈中执行,如此循环,直至所有任务执行完毕。
一般执行顺序如下:
执行同步、异步放到队列中,同步执行完再执行异步。
- 执行script代码
- 当有宏任务,放到事件队列的宏任务中
- 当有微任务,放到事件队列的微任务中
- 执行完所有的微任务,再去执行所有的宏任务
PS:promise=>这里的函数在当前队列直接执行.then=>放到微任务队列中执行。
常见的微任务:promise、process.nextTick 常见的宏任务:setTimeout、I/O、setInterval
- 微任务队列优先于宏任务队列执行。
- 微任务队列上创建的宏任务会被添加到当前宏任务队列的尾端,微任务队列中创建的微任务会被添加到微任务队列的尾端。
- 只要微任务中还有任务,宏任务就要等待。
// 宏任务队列 1
setTimeout(() => {
// 宏任务队列 2.1
console.log('timer_1');
setTimeout(() => {
// 宏任务队列 3
console.log('timer_3')
}, 0)
new Promise(resolve => {
resolve()
console.log('new promise')
}).then(() => {
// 微任务队列 1
console.log('promise then')
})
}, 0)
setTimeout(() => {
// 宏任务队列 2.2
console.log('timer_2')
}, 0)
console.log('========== Sync queue ==========')
输入URL到浏览器发生了什么?
简单答:浏览器根据请求的URL交给DNS域名解析,找到真实IP,向服务器发起请求。服务器交给后台处理完成后返回数据,浏览器接收文件(HTML、JS、CSS、图像等)。浏览器对加载到的资源进行语法解析,建立相应的内部数据解构(如HTML的DOM)。载入解析到的资源文件,渲染页面,完成。
PS:其实这里考察的点还是很深入的,有时间的话,大家可以在掘金或者各种博客上搜搜,会有很详细的解说,大家最好理解深入一些。
微信小程序相关
双线程
生命周期
常用API
wx:if和wxml中hidden的区别
vue相关
生命周期
v-if和v-show区别
双向数据绑定
typescript相关
与JavaScript区别
类型
前端工程化
webpack
gulp
Babel的原理是什么?
babel的转译过程也分为三个阶段
- 解析Parse:将代码解析生成抽象语法树(即AST),即词法分析与语法分析的过程。
- 转换Transform:对于AST进行变换一系列的操作,babel接受得到AST并通过babel-traverse对其进行遍历,在此过程中进行添加、更新及移除等操作。
- 生成Generate:将变换后的AST再转换为JS代码,使用到的模块是babel-generator