CSS、JS面试题

CSS:

1.页面渲染时,dom 元素所采用的 布局模型。
可通过box-sizing进行设置。根据计算宽高的区域可分为:
content-box (W3C 标准盒模型)
border-box (IE 盒模型)
padding-box
margin-box (浏览器未实现)

BFC

块级格式化上下文,是一个独立的渲染区域,让处于 BFC 内部的元素与外部的元素相互隔离,使内外元素的定位不会相互影响。

IE下为 Layout,可通过 zoom:1 触发

触发条件:
position: absolute/fixed
display: inline-block / table
float 元素
ovevflow !== visible
规则:
属于同一个 BFC 的两个相邻 Box 垂直排列
属于同一个 BFC 的两个相邻 Box 的 margin 会发生重叠
BFC 中子元素的 margin box 的左边, 与包含块 (BFC) border box的左边相接触 (子元素 absolute 除外)
BFC 的区域不会与 float 的元素区域重叠
计算 BFC 的高度时,浮动子元素也参与计算
文字层不会被浮动层覆盖,环绕于周围.
应用:
阻止margin重叠
可以包含浮动元素 —— 清除内部浮动(清除浮动的原理是两个div都位于同一个 BFC 区域之中)
自适应两栏布局
可以阻止元素被浮动元素覆盖.

层叠上下文

元素提升为一个比较特殊的图层,在三维空间中 (z轴) 高出普通元素一等。
触发条件
根层叠上下文(html)
position
css3属性
flex
transform
opacity
filter
will-change
-webkit-overflow-scrolling
层叠等级:层叠上下文在z轴上的排序
在同一层叠上下文中,层叠等级才有意义
z-index的优先级最高

选择器优先级:

!important > 行内样式 > #id > .class > tag > * > 继承 > 默认

CSS动画

transition: 过渡动画
transition-property: 属性
transition-duration: 间隔
transition-timing-function: 曲线
transition-delay: 延迟
常用钩子: transitionend
animation / keyframes
animation-name: 动画名称,对应@keyframes
animation-duration: 间隔
animation-timing-function: 曲线
animation-delay: 延迟
animation-iteration-count: 次数
infinite: 循环动画
animation-direction: 方向
alternate: 反向播放
animation-fill-mode: 静止模式
forwards: 停止时,保留最后一帧
backwards: 停止时,回到第一帧
both: 同时运用 forwards / backwards
常用钩子: animationend

flex布局

常用属性
加分项: flex计算规则

JavaScript

原型/ 构造函数 / 实例

原型(prototype): 一个简单的对象,用于实现对象的 属性继承。可以简单的理解成对象的爹。在 Firefox 和 Chrome 中,每个JavaScript对象中都包含一个__proto__ (非标准)的属性指向它爹(该对象的原型),可obj.__proto__进行访问。
构造函数: 可以通过new来 新建一个对象 的函数。
实例: 通过构造函数和new创建出来的对象,便是实例。 实例通过__proto__指向原型,通过constructor指向构造函数。

原型链

原型链是由原型对象组成,每个对象都有 proto 属性,指向了创建该对象的构造函数的原型,proto 将对象连接起来组成了原型链。是一个用来实现继承和共享属性的有限的对象链。
属性查找机制: 当查找对象的属性时,如果实例对象自身不存在该属性,则沿着原型链往上一级查找,找到时则输出,不存在时,则继续沿着原型链往上一级查找,直至最顶级的原型对象Object.prototype,如还是没找到,则输出undefined;
属性修改机制: 只会修改实例对象本身的属性,如果不存在,则进行添加该属性,如果需要修改原型的属性时,则可以用: b.prototype.x = 2;但是这样会造成所有继承于该对象的实例的属性发生改变。

执行上下文

执行上下文可以简单理解为一个对象:
它包含三个部分:
变量对象(VO)
作用域链(词法作用域)
this指向
它的类型:
全局执行上下文
函数执行上下文
eval执行上下文
代码执行过程:
创建 全局上下文 (global EC)
全局执行上下文 (caller) 逐行 自上而下 执行。遇到函数时,函数执行上下文 (callee) 被push到执行栈顶层
函数执行上下文被激活,成为 active EC, 开始执行函数中的代码,caller 被挂起
函数执行完后,callee 被pop移除出执行栈,控制权交还全局上下文 (caller),继续执行.

变量对象

变量对象,是执行上下文中的一部分,可以抽象为一种 数据作用域,其实也可以理解为就是一个简单的对象,它存储着该执行上下文中的所有 变量和函数声明(不包含函数表达式)。
活动对象 (AO): 当变量对象所处的上下文为 active EC 时,称为活动对象。

作用域

执行上下文中还包含作用域链。理解作用域之前,先介绍下作用域。作用域其实可理解为该上下文中声明的 变量和声明的作用范围。可分为 块级作用域 和 函数作用域。
加分:总结es5之前的作用域和es6之后的作用域,以及ES6 let和const的区别,以及babel编译为es5后的具体实现。

作用域链

我们知道,我们可以在执行上下文中访问到父级甚至全局的变量,这便是作用域链的功劳。作用域链可以理解为一组对象列表,包含 父级和自身的变量对象,因此我们便能通过作用域链访问到父级里声明的变量或者函数。
由两部分组成:
[[scope]]属性: 指向父级变量对象和作用域链,也就是包含了父级的[[scope]]和AO
AO: 自身活动对象
如此 [[scopr]]包含[[scope]],便自上而下形成一条 链式作用域。

闭包

闭包属于一种特殊的作用域,称为 静态作用域。它的定义可以理解为: 父函数被销毁 的情况下,返回出的子函数的[[scope]]中仍然保留着父级的单变量对象和作用域链,因此可以继续访问到父级的变量对象,这样的函数称为闭包。
闭包会产生一个很经典的问题:
多个子函数的[[scope]]都是同时指向父级,是完全共享的。因此当父级的变量对象被修改时,所有子函数都受到影响。
解决:
变量可以通过 函数参数的形式 传入,避免使用默认的[[scope]]向上查找
使用setTimeout包裹,通过第三个参数传入
使用 块级作用域,让变量成为自己上下文的属性,避免共享.

对象的拷贝

浅拷贝: 以赋值的形式拷贝引用对象,仍指向同一个地址,修改时原对象也会受到影响
Object.assign
展开运算符(…)
深拷贝: 完全拷贝一个新对象,修改时原对象不再受到任何影响
JSON.parse(JSON.stringify(obj)): 性能最快
具有循环引用的对象时,报错
当值为函数、undefined、或symbol时,无法拷贝
递归进行逐一赋值

模块化

分类:
es6: import / export
commonjs: require / module.exports / exports
amd: require / defined
加分:require与import的区别
require支持 动态导入,import不支持,正在提案 (babel 下可支持)
require是 同步 导入,import属于 异步 导入
require是 值拷贝,导出值变化不会影响导入值;import指向 内存地址,导入值会随导出值而变化

防抖与节流

防抖 (debounce): 将多次高频操作优化为只在最后一次执行,通常使用的场景是:用户输入,只需再输入完成后做一次输入校验即可。

每次进入都打开一个一次定时器并赋值到timer变量, 如果定时器存在就清除定时器,不存在就再打开一个定时器

节流(throttle): 每隔一段时间后执行一次,也就是降低频率,将高频操作优化成低频操作,通常使用场景: 滚动条事件 或者 resize 事件,通常每隔 100~500 ms执行一次即可。

每次进入都打开一个一次定时器并赋值到timer变量, 如果定时器存在就忽略,定时器结束重置变量,下次就能进入

加分项:具体实现细节

ES6和ES7语法

声明
let / const: 块级作用域、不存在变量提升、暂时性死区、不允许重复声明
const: 声明常量,无法修改
解构赋值
class / extend: 类声明与继承
Set / Map: 新的数据结构
异步解决方案:
Promise的使用与实现
generator:
yield: 暂停代码
next(): 继续执行代码

包含声明,解构赋值和异步解决方案,装饰器语法

AST

抽象语法树 (Abstract Syntax Tree),是将代码逐字母解析成 树状对象 的形式。这是语言之间的转换、代码语法检查,代码风格检查,代码格式化,代码高亮,代码错误提示,代码自动补全等等的基础。

babel编译原理

babylon 将 ES6/ES7 代码解析成 AST
babel-traverse 对 AST 进行遍历转译,得到新的 AST
新 AST 通过 babel-generator 转换成 ES5

浏览器

跨标签页通讯

不同标签页间的通讯,本质原理就是去运用一些可以 共享的中间介质,因此比较常用的有以下方法:
通过父页面window.open()和子页面postMessage
异步下,通过 window.open(‘about: blank’) 和 tab.location.href = ‘*’
设置同域下共享的localStorage与监听window.onstorage
重复写入相同的值无法触发
会受到浏览器隐身模式等的限制
设置共享cookie与不断轮询脏检查(setInterval)
借助服务端或者中间层实现

浏览器下事件循环(Event Loop)

事件循环是指: 执行一个宏任务,然后执行清空微任务列表,循环再执行宏任务,再清微任务列表
微任务 microtask(jobs): promise / ajax / Object.observe(该方法已废弃)
宏任务 macrotask(task): setTimout / script / IO / UI Rendering

从输入url到展示的过程

DNS 解析
TCP 三次握手
发送请求,分析 url,设置请求报文(头,主体)
服务器返回请求的文件 (html)
浏览器渲染
HTML parser --> DOM Tree
标记化算法,进行元素状态的标记
dom 树构建
CSS parser --> Style Tree
解析 css 代码,生成样式树
attachment --> Render Tree
结合 dom树 与 style树,生成渲染树
layout: 布局
GPU painting: 像素绘制页面

重绘与回流

当元素的样式发生变化时,浏览器需要触发更新,重新绘制元素。这个过程中,有两种类型的操作,即重绘与回流。
重绘(repaint): 当元素样式的改变不影响布局时,浏览器将使用重绘对元素进行更新,此时由于只需要UI层面的重新像素绘制,因此 损耗较少
回流(reflow): 当元素的尺寸、结构或触发某些属性时,浏览器会重新渲染页面,称为回流。此时,浏览器需要重新经过计算,计算后还需要重新页面布局,因此是较重的操作。会触发回流的操作:
页面初次渲染
浏览器窗口大小改变
元素尺寸、位置、内容发生改变
元素字体大小变化
添加或者删除可见的 dom 元素
激活 CSS 伪类(例如::hover)
查询某些属性或调用某些方法
clientWidth、clientHeight、clientTop、clientLeft
offsetWidth、offsetHeight、offsetTop、offsetLeft
scrollWidth、scrollHeight、scrollTop、scrollLeft
getComputedStyle()
getBoundingClientRect()
scrollTo()

回流必定触发重绘,重绘不一定触发回流。重绘的开销较小,回流的代价较高。
最佳实践:
css
避免使用table布局
将动画效果应用到position属性为absolute或fixed的元素上
javascript
避免频繁操作样式,可汇总后统一 一次修改
尽量使用class进行样式修改
减少dom的增删次数,可使用 字符串 或者 documentFragment 一次性插入
极限优化时,修改样式可将其display: none后修改
避免多次触发上面提到的那些会触发回流的方法,可以的话尽量用 变量存住

服务器与网络

http/https 协议
1.0 协议缺陷:
无法复用链接,完成即断开,重新慢启动和 TCP 3次握手
head of line blocking: 线头阻塞,导致请求之间互相影响
1.1 改进:
长连接(默认 keep-alive),复用
host 字段指定对应的虚拟站点
新增功能:
断点续传
身份认证
状态管理
cache 缓存
Cache-Control
Expires
Last-Modified
Etag
2.0:
多路复用
二进制分帧层: 应用层和传输层之间
首部压缩
服务端推送
https: 较为安全的网络传输协议
证书(公钥)
SSL 加密
端口 443
TCP:
三次握手
四次挥手
滑动窗口: 流量控制
拥塞处理
慢开始
拥塞避免
快速重传
快速恢复
缓存策略: 可分为 强缓存 和 协商缓存
Cache-Control/Expires: 浏览器判断缓存是否过期,未过期时,直接使用强缓存,Cache-Control的 max-age 优先级高于 Expires
当缓存已经过期时,使用协商缓存
唯一标识方案: Etag(response 携带) & If-None-Match(request携带,上一次返回的 Etag): 服务器判断资源是否被修改,
最后一次修改时间: Last-Modified(response) & If-Modified-Since (request,上一次返回的Last-Modified)
如果一致,则直接返回 304 通知浏览器使用缓存
如不一致,则服务端返回新的资源
Last-Modified 缺点:
周期性修改,但内容未变时,会导致缓存失效
最小粒度只到 s, s 以内的改动无法检测到
Etag 的优先级高于 Last-Modified
常见状态码
1xx: 接受,继续处理
200: 成功,并返回数据
201: 已创建
202: 已接受
203: 成为,但未授权
204: 成功,无内容
205: 成功,重置内容
206: 成功,部分内容
301: 永久移动,重定向
302: 临时移动,可使用原有URI
304: 资源未修改,可使用缓存
305: 需代理访问
400: 请求语法错误
401: 要求身份认证
403: 拒绝请求
404: 资源不存在
500: 服务器错误

算法

1 . 五大算法

贪心算法: 局部最优解法
分治算法: 分成多个小模块,与原问题性质相同
动态规划: 每个状态都是过去历史的一个总结
回溯法: 发现原先选择不优时,退回重新选择
分支限界法

2. 基础排序算法

冒泡排序: 两两比较
选择排序: 遍历自身以后的元素,最小的元素跟自己调换位置
插入排序: 将元素插入到已排序好的数组中

3. 高级排序算法

快速排序
选择基准值(base),原数组长度减一(基准值),使用 splice
循环原数组,小的放左边(left数组),大的放右边(right数组);
concat(left, base, right)
递归继续排序 left 与 right
希尔排序:不定步数的插入排序,插入排序 口诀: 插冒归基稳定,快选堆希不稳定

Webpack

核心概念

JavaScript 的 模块打包工具 (module bundler)。通过分析模块之间的依赖,最终将所有模块打包成一份或者多份代码包 (bundler),供 HTML 直接引用。实质上,Webpack 仅仅提供了 打包功能 和一套 文件处理机制,然后通过生态中的各种 Loader 和 Plugin 对代码进行预编译和打包。因此 Webpack 具有高度的可拓展性,能更好的发挥社区生态的力量。
Entry: 入口文件,Webpack 会从该文件开始进行分析与编译;
Output: 出口路径,打包后创建 bundler 的文件路径以及文件名;
Module: 模块,在 Webpack 中任何文件都可以作为一个模块,会根据配置的不同的 Loader 进行加载和打包;
Chunk: 代码块,可以根据配置,将所有模块代码合并成一个或多个代码块,以便按需加载,提高性能;
Loader: 模块加载器,进行各种文件类型的加载与转换;
Plugin: 拓展插件,可以通过 Webpack 相应的事件钩子,介入到打包过程中的任意环节,从而对代码按需修改;

相关配置

如:如何配置一个sass支持等
指纹hash,chunk-hash和contenthash区别,以及js与css的hash指纹解耦方案
多入口应用配置
打包优化
无用代码消除,是许多编程语言都具有的优化手段,这个过程称为 DCE (dead code elimination),即 删除不可能执行的代码;
code-spliting: 代码分割 和 代码切片
缩小编译范围:
modules: 指定模块路径,减少递归搜索;
mainFields: 指定入口文件描述字段,减少搜索;
noParse: 避免对非模块化文件的加载;
includes/exclude: 指定搜索范围/排除不必要的搜索范围;
alias: 缓存目录,避免重复寻址;

babel-loader:

忽略node_moudles,避免编译第三方库中已经被编译过的代码;
使用cacheDirectory,可以缓存编译结果,避免多次重复编译;

多进程并发:

webpack-parallel-uglify-plugin: 可多进程并发压缩 js 文件,提高压缩速度;
HappyPack: 多进程并发文件的 Loader 解析;

第三方库模块缓存:

DLLPlugin 和 DLLReferencePlugin 可以提前进行打包并缓存,避免每次都重新编译;

项目性能优化

编码优化

编码优化,指的就是 在代码编写时的,通过一些最佳实践,提升代码的执行性能。通常这并不会带来非常大的收益,但这属于程序猿的自我修养,而且这也是面试中经常被问到的一个方面,考察自我管理与细节的处理。

数据读取:

通过作用域链 / 原型链 读取变量或方法时,需要更多的耗时,且越长越慢;对象嵌套越深,读取值也越慢;
最佳实践:
尽量在局部作用域中进行 变量缓存;
避免嵌套过深的数据结构,数据扁平化 有利于数据的读取和维护;

循环

循环通常是编码性能的关键点;
代码的性能问题会再循环中被指数倍放大;
最佳实践:
尽可能 减少循环次数;
减少遍历的数据量;
完成目的后马上结束循环;
避免在循环中执行大量的运算,避免重复计算,相同的执行结果应该使用缓存;
js 中使用 倒序循环 会略微提升性能;
尽量避免使用 for-in 循环,因为它会枚举原型对象,耗时大于普通循环;
条件流程性能: Map / Object > switch > if-else

cookie:

减少 cookie 体积: 能有效减少每次请求的体积和响应时间;
去除不必要的 cookie;
压缩 cookie 大小;
设置 domain 与 过期时间;

dom 优化:

减少访问 dom 的次数,如需多次,将 dom 缓存于变量中;
减少重绘与回流:
多次操作合并为一次;
减少对计算属性的访问;
例如 offsetTop, getComputedStyle 等
因为浏览器需要获取最新准确的值,因此必须立即进行重排,这样会破坏了浏览器的队列整合,尽量将值进行缓存使用;
大量操作时,可将 dom 脱离文档流或者隐藏,待操作完成后再重新恢复;
使用DocumentFragment / cloneNode / replaceChild进行操作;
使用事件委托,避免大量的事件绑定;

css 优化:

层级扁平,避免过于多层级的选择器嵌套;
特定的选择器 好过一层一层查找: .xxx-child-text{} 优于 .xxx .child .text{}
减少使用通配符与属性选择器;
减少不必要的多余属性;
使用 动画属性 实现动画,动画时脱离文档流,开启硬件加速,优先使用 css 动画;
使用 替代原生 @import;

html 优化:

减少 dom 数量,避免不必要的节点或嵌套;
避免空标签,能减少服务器压力,因为 src 为空时,浏览器仍然会发起请求
IE 向页面所在的目录发送请求;
Safari、Chrome、Firefox 向页面本身发送请求;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值