前端基础知识
前端基础知识体系(结构化的知识范围)
css基础知识 js基础语法 JS-Web-API 开发环境 运行环境 HTTP协议
HTML CSS
1、如何理解HTML语义化?
答:让人更容易读懂,增加代码可读性。
让搜索引擎更容易读懂(SEO)
2、默认情况下,哪些HTML 标签是块级元素,哪些是内联元素?
**** 答:display:block/table 有 div h1 h2 table ul ol p 等
display:inline/inline-block 有 span img input button 等
3、盒子模型的宽度如何计算
**** 要点:offsetWidth = (内容宽度 + 内边距 + 边框),无外边框
设置 box-sizing:border-box 之后,width 为到边框盒子模型的宽度
4、margin纵向重叠的问题
**** 要点:相邻元素的 margin-top 和 margin-bottom 会发生重叠
空白内容的标签也会重叠
5、margin负值的问题
**** 要点:margin-top 和 margin-left 负值,元素向上、向左移动
margin-right 负值,右侧元素左移,自身不受影响
margin-bottom 负值,下方元素上移,自身不受影响
6、BFC理解和应用
**** 要点:一个独立的渲染区域,内部元素的渲染不会影响边界以外的元素
形成BFC的条件
1、float 不是 none
2、position 是 absolute 或 fixed
3、overflow 不是 visible
4、display 是 flex inline-block
BFC常见应用
清除浮动
7、如何实现圣杯布局和双飞翼布局
**** 要点:三栏布局,中间一栏最先加载和渲染(内容最重要)
两侧内容固定,中间内容随着宽度自适应
一般用于 pc 网页
技术总结:采用浮点布局;在两侧设置负值的margin以实现与中间内容横向重叠的效果;通过分别采用padding和margin两种方式进行处理来避免中间内容被两侧遮挡或覆盖
// 圣杯布局
.container {
float: left;
padding-left: 200px;
padding-right: 150px;
}
.content {
width: 100%;
}
.left {
position: relative;
width: 200px;
margin-left: -100%;
right: 200px;
}
.right {
width: 150px;
margin-right: -150px;
}
//双飞翼布局
.container {
float: left;
margin: 0 150px 0 200px;
}
.left {
width: 200px;
margin-left: -100%;
}
.right {
width: 150px;
margin-left: -150px;
}
8、 手写 clearfix
.clearfix:after {
content: '';
display: table;
clear: both;
}
9、 flex画骰子
**** 要点:flex-direction justify-content align-items flex-wrap align-self
.box {
display: flex;
justify-content: space-between;
}
.item {
/* 背景色 大小 边框 */
}
.item:nth-child(2) {
align-self: center;
}
.item:nth-child(3) {
align-self: flex-end;
}
10、absolute和relative 分别依据什么定位?
**** 答:relative 依据自身定位;absolute 依据最近一层的定位元素定位
11、居中对齐有哪些实现方式?
水平居中:inline 元素采用水平居中的布局方式(text-align: center),block 元素采用自动调整间距(margin: auto),absolute 元素左侧居中并添加左边负值偏移量(left: 50% + margin-left 负值)
inline 类型的元素采用相同的线高设置;abs类元素的顶部位置设置为50%并附加负值的margin-top;abs类元素应用平移变换(-50%,-50%);abs类元素的顶部、左侧、底部和右侧设置为无边距
12、line-height的继承问题
关键点包括以下几种情况:当使用具体数值(如30px)时,则沿用该数值;当采用比例(如2或1.5)时,则沿用该比例;当采用百分比(如200%)时,则根据计算得出的结果来设置。
12、 rem是什么?
要点:px被视为绝对长度单位;而em被视为相对长度单位,默认基于父元素;rem同样作为相对长度单位,默认基于根元素,在响应式设计中常用作基准。
13、如何实现响应式?
核心要点:media-query机制通过根据不同屏幕宽度自动调节根元素的字体大小;作为基于根元素的相对长度单位
js基础知识
值类型和引用类型
知识点:
- primitives与objects之间的差异主要体现在数据存储方式上。在stack model下进行deep copy时需特别注意内存分配策略。
- typeof运算符的作用在于区分数据的存储方式及其行为模式。
- 类型转换过程涉及将变量从一种数据形式转换为另一种形式。truly变量用于精确标识对象实例;而falsely变量则用于临时标识以避免混淆。
1、typeof 能判断哪些类型
要点:识别所有值类型,识别函数,判断是否是引用类型(不可再细分)
2、何时使用 === 何时使用 ==
**** 答:使用 == 会进行默认的类型转化,除了 == null 之外,其他一律用 ===
3、值类型和引用类型的区别
在C++中,默认情况下数值类型采用栈存储方式,在执行赋值操作时会直接影响原有的数据;而引用类型的变量则采用堆内存进行管理,在执行赋值操作时其对应的内存地址不会被修改
4、手写深拷贝
function deepClone(target) {
if(typeof target !== 'Object' || target == null) {
return target
}
let result
if(target insatnceof Array) {
result = []
} else {
result = {}
}
for(let i in target) {
if(target.hasOwnProperty(i)) {
result[i] = deepClone(target[i])
}
}
return result
}
原型和原型链
知识点:
- 类及其继承关系可以通过手写的jQuery 示例来理解。
- 基于实例的编程概念是通过* instanceof 来体现的。
- 在对象模型中,原型与原型链是两个关键概念。它们可以通过图解的方式进行展示,并遵循特定的执行规则。
5、如何准确判断一个变量是不是数组?
**** 答:使用 instanceof 来进行判断
6、 手写一个简易的jQuery,考虑插件和扩展性
class jQuery {
connstructor(selector) {
const result = document.querySelectorAll(selector)
const length = result.length
for(let i = 0; i < length; i++) {
this[i] = result[i]
}
this.length = length
}
get(index) {
return this[index]
}
each(fn) {
for(let i = 0; i< this.length; i++) {
const elem = this[i]
fn(elem)
}
}
on(type,fn) {
return this.each(elem => {
elem.addEventListener(type,fn,false)
})
}
}
7、class 的原型本质怎么理解?
**

**
作用域和闭包
知识点:
- 作用域和自由变量
- 闭包:两种常见方式 & 自由变量查找规则
- this
...:特殊的函数作用域应用情况,在编程逻辑设计中通常会遇到的主要情形有两类:一种是在参数列表中将函数传递进去;另一种是在执行完成后将该函数返回给调用者
8、this 的不同应用场景,如何取值?
**** 要点:this 取值是在函数执行时确认的,不是在函数定义时确认的
答:当做普通函数被调用 ------- window
使用 call apply bind ------- 传入参数
作为对象方法调用 ------- 对象本身
在 class 的方法中调用 ------- 实例
箭头函数 ------ 上级作用域的函数
9、 手写 bind 函数
Function.prototype.bind1 = function() {
// 将参数拆解为数组
const args = Array.prototype.slice.call(arguments)
// 获取 this (数组第一项)
const t = args.shift()
// fn1.bind() 中的 fn1
const self = this
// 返回一个函数
return function() {
return self.apply(t,args)
}
}
10、 实际开发中闭包的应用场景,举例说明
// 闭包隐藏数据,只提供 API
function createCache() {
const data = {} // 闭包中的数据被隐藏,不被外界访问
return {
set: function(key,val) {
data[key] = val
},
get: function(key) {
return data[key]
}
}
}
11、 创建10个 a 标签,点击时弹出对应的序号
let a
for(let i = 0; i < 10; i++) {
a = document.createElement('a')
a.innerHTML = i + '<br>'
a.addEventListener('click',function(e) {
e.preventDefault()
alert(i)
})
document.body.appendChild(a)
}
异步和单线程
12、同步和异步的区别是什么?
**** 答:JS 是单线程语言,异步不会阻塞代码执行,同步会阻塞代码执行
13、 手写 Promise 加载一张图片
function loadImg(src) {
return new Promise(
(resolve,reject) => {
const img = document.createElement('img')
img.onload = () => {
resolve(img)
}
img.onerror = () => {
reject('加载失败')
}
img.src = src
}
)
}
14、前端使用异步的场景有哪些?
**** 答:网络请求,如 Ajax 图片加载,定时任务,如 setTimeout
js异步(进阶)
15、 请描述 event loop (事件循环/事件轮询)的机制,可画图
**** 执行过程:
- 将同步代码依次放入Call Stack中进行处理;
- 遇到异步任务时会先记录下来并等待相应的时机(例如定时任务或网络请求等);
- 当时机到来时,则被移至Callback队列中;
- 当Call Stack为空时(意味着所有同步代码已经完成),Event Loop启动工作流程;
- 持续检查Callback队列,在发现存在时,则被转移回Call Stack进行处理;
- 然后继续进行检查。
16、什么是宏任务和微任务,两者有什么区别?
要点:事件循环(Event Loop)与DOM渲染之间存在密切关联。每当Call Stack被清空后(即完成同步任务后),都会提供一次DOM再渲染的机会;若DOM结构发生变化,则会进行重绘;随后再次触发下一个Event Loop的处理流程。
答:主要功能块包括 setTimeout、setInterval、Ajax 和 DOM 事件处理;基础操作包括 Promise 和 async/await 机制
微任务执行时机比宏任务要早
区别:宏任务: DOM 渲染后触发,浏览器规定; 微任务: DOM 渲染前触发,ES6规定
17、Promise 有哪三种变化?如何变化
**** 要点:async await 解决了异步回调
async 与 await 与 promise 的关联: async 等同于 Promise.then() 会被调用; await 等同于 Promise.catch() 会被用来捕获。
for....of 单个进行遍历,依次执行,不会一次性执行所有循环项
答: pending resolved rejected
pending -- > resolved 或 pending --- > rejected 变化不可逆
JS Web API
18、DOM 是哪种数据结构
**** 答:树形结构
19、DOM 操作的常用 API
// 新建节点
const newP = document.createElement('p')
newp.innerHTML = 'this is new p'
// 插入节点
div1.appendChild(newP)
// 移动节点
const p1 = document.getElementById('p1') // 此时p1 节点在div1 中
div2.appendChild(p1)
20、attr 和 property 的区别
prototype 用于修改对象属性,并不会体现在 html 结构体中;而 attribute 可以用于修改 html 属性,在这种情况下会导 致 html 树发生变化。无论是哪种情况都有可能出现 DOM 重 render 操作。
21、一次性插入多个 DOM 节点,考虑性能
**** 要点: DOM 性能:将 DOM 做缓存;将频繁操作改为一次性操作
const listNode = document.getElementById('list')
// 创建一个文档片段,此时还没有插入到 DOM 树中
const frag = document.createDocumentFragment()
// 执行插入
for(let x = 0; x < 10; x++) {
const li = document.createElement('li')
li.innerHTML = 'list item' + x
frag.appendChild(li)
}
// 都完成后,再插入到 DOM 树中
listNode.appendChild(frag)
事件
22、 编写一个通用的事件监听函数
function bindEvennt(elem,type,selector,fn) {
if(fn == null) {
fn = selector
selector = null
}
elem.addEventListener((type,event) => {
const target = event.target
if(selector) {
// 代理绑定
if(target.maches(selector)) {
fn.call(target,event)
}
} else {
// 普通绑定
fn.call(event,target)
}
}
}
23、描述事件冒泡的流程
**** 答:基于 DOM 树形结构,事件会顺着触发元素往上冒泡,应用场景:代理
24、 无限下拉的图片列表,如何监听每个图片的点击?
答:利用事件代理机制,在代码中使用e.target属性获取对应的触发元素实例;然后通过matches属性判断是否有对应的触发元素存在
ajax
25、 手写一个简易得到 Ajax
要点:xhr.readyState
0:(未初始化) 还没有调用send() 方法
1:(载入)已调用 send() 方法,正常发送请求
2:(载入完成) send() 方法执行完成,已经接收到全部响应内容
3:(交互)正在解析响应内容
4:(完成)响应内容解析完成,可以在客户端调用
xhr.status
2xx:表示成功处理请求
3xx:需要重定向,浏览器直接跳转,如301 302 304
4xx:客户端请求错误,如 404 403
5xx:服务端错误
function ajax(url) {
const p = new Promise((resolve,reject) => {
const xhr = new XMLHttpRequest()
xhr.open('GET',url,true)
xhr.onreadystatechange = function() {
if(xhr.readyState === 4) {
if(xhr.status === 200 ) {
resolve(JSON.parse(xhr.responseText)
}
}
}
xhr.send()
})
return p
}
26、跨域的常用实现方式
要点:同源方法:当发起Ajax请求时,客户端与服务器之间必须采用相同的协议(HTTP)、使用相同的域名以及配置相同的端口才能实现通信;同源性要求三个要素——协议、域名和端口——必须保持一致
答:JSONP CORS
存储
27、 描述 cookie localStorage sessionStorage 区别
答:localStorage能够实现长久保存功能,在浏览器退出时也不会丢失内容;session data则会在退出时自行消失;网站通过cookie机制将用户的访问信息与身份信息绑定并存储于本地终端设备上(通常采用加密技术保护)。该机制会不断往返于客户端与服务器端之间以便完成验证流程;而session storage以及local storage的数据仅限于本地设备内部处理
http
28、 http 常见的状态码有哪些?
要点:状态码分类如下:
1xx 表示服务器接收到客户端的请求;
2xx 表示客户端所作请求获得成功响应;
3xx 表示执行的是重定向指令;
4xx 表示客户端发生了技术问题;
5xx 表示服务端出现了故障
常见状态码: 200 返回成功响应; 301 发布永久重定向响应; 302 发布临时重定向响应;304 资源的状态未发生变化;404 资源未找到响应;403 权限不足响应;500 服务器错误响应;504 网关超时响应
29、http 常见的 header 有哪些?
**** 答:常见的 Request Headers
Accept 浏览器可接收的数据格式
Accept-Encoding 浏览器可接收的压缩算法,如 gzip
Accept-Languange 浏览器可接收的语言,如 zh-CN
Connection:keep-alive 一次 TCP 连接重复使用
cookie
Host
User-Agent(简称 UA) 浏览器信息
Content-type 发送数据的格式,如 application/json
常见的 Response Headers
Content-type 返回数据的格式,如 application/json
Content-length 返回数据的大小,多少字节
Content-Encoding 返回数据的压缩算法,如 gzip
Set-Cookie
30、什么是 Restful API
当前采用的方法:发布、提交请求(发布新内容)、删除现有记录(删除现有记录)、更新部分字段记录(通过patch或put方法实现更新),重置资源(通过put重新发布整个资源)、检索现有信息(通过get获取信息)
答:此方案提供了一种新的API设计方法;传统API设计采用将每一个URL视为独立的功能这一策略;而RestfulAPI设计则采用将每一个URL视为独立且独特的资源这一策略。
31、 描述一下 http 的缓存机制
**** 强制缓存
**

**
协商缓存
服务器端缓存策略
服务器端判断客户端资源,是否和服务端资源一样
一致则返回 304,否则返回 200 和最新的资源

综述

三种刷新操作:正常刷新、手动刷新、强制刷新(ctrl + F5)
正常操作:强制缓存有效,协商缓存有效
手动刷新:强制缓存失效,协商缓存有效
强制刷新:强制缓存失效,协商缓存失效
开发环境
git:最常用的代码版本管理工具
**** 常用git命令:
git add . 添加所有的文件
git checkout . 撤销所有文件
git commit -m "xxx" 提交单个文件
git push origin master 推送分支
git pull origin master 拉取分支
git branch 查看分支
git checkout -b xxx / git checkout xxx 切换分支
git merge xxx 合并分支
git status 查看更新文件
git diff 查看修改内容
Chrome 调试工具
抓包(windows:fiddler Mac OS:charles)
webpack 和 babel
linux 命令
运行环境
****知识点:
**** 加载资源的形式:html 代码、 媒体文件、 js css
加载过程如下:DNS解析将域名映射到对应的IP地址;当浏览器收到该IP地址时会发送HTTP请求;服务器接收并处理该HTTP请求后返回响应内容
32、从输入 url 到渲染出页面的整个过程
**** 渲染过程:
- 解析HTML内容以构建DOM树,并基于CSS代码生成cssOM对象。
- 渲染基于Render Tree的页面时,在遇到JavaScript脚本时临时停止渲染流程,并优先加载并运行相关JavaScript代码块;待所有脚本执行完毕后立即恢复流程。
33、window.onload 和 DOMContentLoaded 的区别
onload会在所有网页元素全部成功加载完毕后才会被执行的操作包括但不限于图片处理与视频播放等操作 DOMContentLoaded则是在DOM解析树构建并完成初始渲染之后才允许JavaScript脚本在网页上运行 当前阶段网页中的图片与视频文件可能尚未完全加载完毕
性能优化
性能优化原则:主要依赖内存和缓存资源进行操作,在算法设计中尽量避免过于复杂的计算逻辑以降低计算资源的消耗,在网络层面上采取相应的优化措施以降低网络加载时间,并通过占用更多存储空间来换取处理速度
让加载更快
**** 减少资源体积:压缩代码
减少访问次数:合并代码,SSR 服务器端渲染,缓存
使用更快的网络: cdn
让渲染更快
**** css 放在 head ,js 放在 body 最下面
尽早开始执行 js ,用 DOMContentLoaded 触发
懒加载(图片懒加载,上划加载更多)
对 DOM 查询进行缓存
频繁 DOM 操作,合并到一起插入 DOM 结构
节流 throttle 防抖 debounce
// 防抖
function debounce(fn,delay = 500) {
let timer = null
return function() {
if(timer) {
clearTimeout(timer)
}
timer = setTimeout(() => {
fn.apply(this,argumennts)
timer = null
}, delay)
}
// 节流
function throttle(fn,delay = 100) {
let timer = null
return function() {
if(timer) return
timer = setTimeout(() => {
fn.apply(this,arguments)
timer = null
},delay)
}
}
34、常见的 web 前端攻击方式有哪些?
**** 答:XSS 跨站请求攻击, XSRF 跨站请求伪造
面试真题
1、var 和 let const 的区别
答:var 是 ES5 语法,let const 是 ES6 语法; var 有变量提升
var 和 let 是变量,可修改;const 是常量,不可修改
let const 有块级作用域,var 没有
2、typeof 返回哪些类型
**** 答:undefined string number Boolean symbol
object(注意,typeof null === 'object')
function
3、 列举强制类型转换和隐式类型转换
**** 答:强制:parseInt parseFloat toString 等
隐式: if、逻辑运算、==、 + 拼接字符串
4、 手写深度比较,模拟 lodash isEqual
function isObject(obj) {
return typeof obj === 'object' && obj !== null
}
function isEqual(obj1,obj2) {
if(!isObject(obj1) || !isObject(obj2)) {
return obj1 === obj2
}
if(obj1 === obj2) {
return true
}
// 两个都是对象 而且不相等
// 1、先取出 obj1 和 obj2 的keys, 比较个数
const obj1keys = Object.key(obj1)
const obj2keys = Object.key(obj2)
if(obj1keys.length !== obj2keys.length) {
return false
}
//2、以 obj1 为基准 和 obj2 依次进行递归比较
for(let key in obj1) {
const res = isEqual(obj1[key],obj2[key])
}
if(!res) {
return false
}
return true
}
5、split() 和 join() 的区别
答:split 拆分为数组,join 合并为字符串
6、数组的 pop push unshift shift 分别做什么
答: pop 将数组栈顶元素删除,返回删除值
push 在数组尾部追加新的元素,返回数组长度
unshift 在数组头部追加新的元素,返回追加值
shift 在数组头部删除元素,返回删除值
纯函数(不改变原数组,返回数组):concat、map、filter、slice
7、数组 slice 和 splice 的区别
Slice作为纯函数式编程语言中的切片操作符:slice(a,b)获取数组中下标从a至b的元素;slice(a)获取从索引a开始的所有元素;slice(-a)获取最后a个元素。
spice 是一种非纯过程:spice(a,b,c) 在数组中以索引a的位置开始选取长度b的元素并将其替换为c
8、[10,20,30].map(parseInt) 返回结果是什么
[10,20,30].map((num,index) => {
return parseInt(num,index)
})
// [10,NaN,NaN]
** 9、ajax 请求 get 和 post 的区别**
**** 答:get 一般用于查询操作,post 一般用于提交操作
get 参数拼接在 url 上,post 放在请求体内(数据体积更大)
安全性:post 易于防止 CSRF
10、函数 call 和 apply 的区别
不同的是,在这种调用模式下(call),每个参数都会被独立地传输;而使用apply方法时,则要求输入参数必须是数组或类数组。
11、事件代理是什么?
答:给父元素绑定事件,通过事件冒泡完成代理
12、 闭包是什么,有什么特性?有什么负面影响
在编程中,函数会被传递作为参数,并在其执行过程中被返回;在查找自由变量时,请确保其搜索位置位于函数定义处而非其运行位置
影响:变量会常驻内存,得不到释放,闭包不要乱用
13、如何阻止事件冒泡和默认行为
答:event.stopPropagation() event.preventDefault()
14、查找、添加、删除、移动 DOM 节点的方法
createElement 创建 appendChild 插入 removeChild 删除
15、如何减少 DOM 操作?
答:缓存 DOM 查询结果;多个DOM 操作合并为一次插入
16、 解释 jsonp 的原理,为何它不是真正的 ajax
答:解答:创建并调用一段JavaScript代码;该代码返回执行结果;未使用XMLHttpRequest API库;因此属于非Ajax请求。
17、 document load 和 ready 的区别
答:load 页面的全部资源加载完才会执行;ready 渲染完即可完成
18、=== 和== 的区别
答: == 会隐式转换, === 是严格相等
19、 函数声明和函数表达式的区别
答:函数声明 function fn() {}
函数表达式 const fn = function() {}
函数声明会在代码执行前预加载,而函数表达式不会
20、 new Object() 和 object.create() 的区别
答:{} 等于 new Object(),原型 Object.prototype
Object.create(null) 没有原型
Object.create({...}) 可指定原型
21、关于this 场景题
22、 判断字符串以字母开头,后面字母数字下划线,长度6-30
**** const reg = /^[a-zA-Z]\w{5,29}$/
23、 手写字符串 trim 方法,保证浏览器兼容性
String.prottotype.trim = function() {
return this.replace(/^\s+/,'').replace(/\s+$/,'')
}
24、如何获取多个数字中的最大值
答:Math.max()
25、 如何用 js 实现继承
26、如何捕获 js 程序中的异常
try {
// todo
} catch(ex) {
console.error(ex)
} finally {
// todo
}
// 自动捕获
window.onerror = function(message,source,lineNum,colNum,error) {
// 第一,对跨域的 js, 如 CDN 的,不会有详细的报错信息
// 第二,对于压缩的 js,还要配合 sourceMap 反查到未压缩代码的行、列
}
27、 什么是 JSON
json 是一种数据结构,本质是一段字符串
json 格式和 JS 对象结构一致,对 JS 语言更友好
window.JSON 是一个全局对象: JSON.stringify JSON.parse
28、 获取当前页面 url 参数
传统方式,查找 location.search
function query(name) {
const search = location.search.substr(1)
// search: 'a=10&b=20&c=30'
const reg = new RegExp(`(^|&)${name}=([^&]*)(&|$)`,'i')
const res = search.match(reg)
if(res === null) {
return null
}
return res[2]
}
新 API ,URLSearchParams
function query(name) {
const search = location.search
const p = new URLSearchParams(search)
return p.get(name)
}
29、 将 url 参数解析为 js 对象
function queryToObj() {
const res = {}
const search = location.search.substr(1) // 去掉前面的 ?
search.split('&').forEach(paramStr => {
const arr = paramStr.split('=')
const key = arr[0]
const val = arr[1]
res[key] = val
})
return res
}
// 使用 URLSearchParams
function queryToObj() {
const res = {}
const pList = new URLSearchParams(location.search)
pList.forEach((val,key) => {
res[key] = val
})
return res
}
30、 手写数组 flatern(拍平),考虑多层级
function flat(arr) {
const isDeep = arr.some(item => item instanceof Array)
if(!isDeep) {
return arr
}
const res = Array.prototype.concat.apply([],arr)
return flat(res)
}
31、 数组去重
// 传统方式
function unique(arr) {
const res = []
arr.forEach(item => {
if(res.indexOf(item) < 0) {
res.push(item)
}
})
return res
}
// 使用 set
function unique(arr) {
const set = new Set(arr)
return [...set]
}
32、手写深拷贝
function deepClone(target) {
if(typeof target !== 'object' || target == null) {
return target
}
let result
if(target instanceof Array) {
result = []
} else {
result = {}
}
for(let i in target) {
if(target.hasOwnProperty(i)) {
result[i] = deepClone(target[i])
}
}
return result
}
33、前端性能如何优化,一般从几方面考虑
原则:多使用内存、缓存,减少计算、减少网络请求
方向:加载页面,页面渲染,页面操作流畅度
