前端面试题
序号
|
|
|
|
1
|
|
Node.js的框架有哪些
|
express koa2
|
2
|
2
|
call 和 apply的区别
|
call 从第二个参数开始逐个传参
apply 第二个参数是一个数组
|
3
|
4
|
addEventListener最后一个参数
|
true表示捕获,false表示冒泡
|
4
|
|
状态码200什么意思
|
通讯成功
|
5
|
|
状态码404
|
客户端请求错误,没有目标网页
|
6
|
|
状态码500
|
服务器内部错误
|
7
|
|
状态码503
|
服务器暂时无法使用
|
8
|
3
|
简单说几个性能优化的方法
|
拆分请求
压缩js html
压缩合并图片 走cdn
|
9
|
|
在团队里的角色
|
一个应用的小组长
|
10
|
|
错误收集方法
|
1 window.onerror
2 逻辑错误的地方主动打点收集
3 如有复现步骤,用fiddler把线上js 映射到本地
|
11
|
|
我的经验
|
1年QA
5年Flash
2年前端
2年egret
|
12
|
|
有哪些缓存
|
cookie 在客户端和服务端传递 最大传4k 在同源的浏览器窗口cookie过期时间之前保存
sessionStorage 浏览器关闭那失效
localStorage 永远存在
|
13
|
2
|
get 和 post 的区别
|
get的参数会存到浏览器的历史中,用于获取数据,无副作用,幂等
post有副作用,幂不等
get 用于获取数据 无副作用 当然幂等
delete 用于删除数据 有副作用 多次调用效果相同 所以幂等
post 用于提交数据 有副作用 多次调用产生多条数据 所以幂不等
put 用于提交数据 有副作用 多次调用只生产或更新一条数据 所以幂等
|
14
|
|
什么是同域
|
协议 域名 端口 都相同
url = protocol + hostname + port + search + hash
host = hostname + port
origin = protocol + hostname + port
另外还有
href是全部
pathname 问号后斜杠那部分
|
15
|
2
|
Cors 跨源资源共享
|
cross origin resources sharing 跨域资源共享
若带cookie服务端也要设置
response.setHeader('Access-Control-Allow-Origin',"*");
1 cors需要客户端和服务端同时支持
2 如果浏览器发现ajax请求跨域,就会自动添加一些头信息,有时还会多发一个请求
3 cors请求有两类。简单请求和非简单请求
简单请求:类型是head get post, Content-Type只限于下面三个值 application/x-www-form-urlencoded、multipart/form-data、text/plain
4 发送cors简单请求时,浏览器会带上origin,服务器根据这个值来判断是否接受请求
4.1 如果没同意,会返回200http回应,但头信息上没有带上Access-Control-Allow-Origin,同时XMLHttpRequest的onerror会被调用
4.2 如果同意了,返回的http回应里,头信息上会带有
Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Credentials: true 表示允许带上cookie 一起发给服务器
Access-Control-Expose-Headers: FooBar
Content-Type: text/html; charset = utf-8
如果想带着cookie, 需要做两步
1 服务器端要设置 Access-Control-Allow-Credentials: true
2 xhr.withCredentials = true
5发送非简单请求时 会在正式请求前 加一次http查询请求 即options请求
除了Origin字段,"预检"请求的头信息包括两个特殊字段。
(1)Access-Control-Request-Method
该字段是必须的,用来列出浏览器的CORS请求会用到哪些HTTP方法,上例是PUT。
(2)Access-Control-Request-Headers
该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段,上例是X-Custom-Header。
5.1 服务器如果同意了这个option请求
5.2 正常的请求返回的头信息将会是这两个:
Access-Control-Allow-Origin: http://api.bob.com
Content-Type: text/html; charset=utf-8
|
|
2
|
OSI七层
|
Open System Interconnection
物理层 比特流
数据链路层 提供介质 链路管理
网络层 寻址 和 路由选择
传输层 建立主机端到端国连接
会话层 管理会话
表示层 处理数据格式,数据加密
应用层 提供应用程序间通信
|
17
|
|
tcp udp 属于哪个层
|
传输层
|
18
|
|
http 属于哪个层
|
传输层 |
19
|
|
常用排序方法
|
冒泡排序:
let test:number[] = [1,1]
let len:number = test.length
for( let i:number = 0 ; i < len ; i ++ ){
for( let j:number = 0 ; j < len - 1 - i ; j ++ ){
let temp:number = test[j+1];
test[j+1] = test[ j ];
test[j] = temp ;
}
}
时间复杂度 最差情况O(n2) 最好情况O(n)
插入排序:
for( let i:number = 1 ; i < len ; i++ ){
for( let j:number = 0 ; j < i ; j ++ ){
if( test[j] > test[i] ){
let a:number = test[i];
test[i] = test[j] ;
test[j] = a ;
}
}
}
|
20
|
3
|
webpack缩小打包体积的方法
四种方法
|
1 第三方库单独引用
2 单独打包css
3 不同环境用不同一配置文件,以去掉不必要的插件
4 选择合适的devtool, 以优化sourceMap
|
21
|
2
|
请求url到html展示的过程
七步
|
dns 解析
tcp 三次握手
浏览器设置好请求报文后发出http请求
服务器处理请求并返回http报文
浏览器解析渲染页面
a html解析器构建dom tree
b css 解析器构建 style rule
a和b共同构造出呈现树 render tree -> 布局阶段
|
22
|
2
|
html里的async和defer区别
|
async是下载完就执行
defer是渲染完再执行
|
23
|
2
|
如何减少内存泄露 |
监听用完要移除
离开场景 清除动画 停止setTimeout
|
24
|
1
|
有几个原始类型,它们有方法吗
|
null undefined boolean number string symbol
原始类型是没有方法的
|
25
|
|
原始类型 和 对象类型 有什么区别
|
原始类型 存储的是值
对象类型 存储的是地址
|
27
|
|
eval
|
可把字符串解析成js代码并运行 应避免使用eval 很耗性能
|
28
|
1
|
null和undefined有什么区别
|
null表示定义了,但值为空值
undefinded表示不存在这个值
|
29
|
|
typeof 1
typeof '1'
typeof undefined
typeof true
typeof Symbol
typeof 函数
typeof 任何对象类型
|
number
string
undefined
boolean
symbol
function
object
|
30
|
2
|
this 三种情况
|
直接调用foo,那this一定是window , 一定吗?
obj.foo(), 谁调用了函数,谁就是this
对于new的方式说, this被永远绑定在实例上面
箭头函数的this取决于第一个普通函数的this
|
31
|
2
|
什么是闭包
|
函数A内部有一个函数B,
函数B可以访问到函数A中的变量,
那么函数B就是闭包
|
32
|
2
|
经典闭包题答案
有三个,只需答两个
|
方法一
for( var i = 0 ; i <= 5 ; i ++ ){
(function(j){
setTimeout( function timer() {
console.log(j);
}, j * 1000 ) ;
}
})( i ) ;
方法二
setTimeout() 的第三个参数传 i
方法三
用 let 来定义 i
for( let i = 0 ; i <= 5 ; i ++ ){
setTimeout( function timer(){
console.log( i );
}, i * 1000 );
}
|
33
|
1
|
如何实现浅拷贝
|
let b=Object.assign( {}, a ) ;
let b = { ... a } ;
|
34
|
1
|
如何实现深拷贝
|
JSON.parse( JSON.stringify( a ) ) ; 不支持 undefined Symbol 和 循环引用的对象
方法二:用MessageChannel
|
35
|
2
|
async 和 await 的使用方法
|
async function foo(){
return 1
}
函数前面的async一词意味着这个函数总是返回一个promise,如果代码中有return <非promise>语句 以
则会自动把返回的这个value值包装成promise的resolved的值
即foo().then( 这里可取到 value 的值 )
|
36
|
2
|
原型和原型链
|
每个实例对象都有一个__proto__指向它的原型对象
这个原型对象的constructor的prototype也指向这个原型对象
对象的 __proto__ 指向原型,对象和原型连接起来就组成了原型链
Object是所有对象的爸爸,所有对象都可以通过 __proto__ 找到它
Function是所有函数的爸爸,所有函数都可以通过 __proto__ 找到它
函数的 prototype 是一个对象
|
37
|
2
|
什么是变量提升
|
1 函数提升优先于变量提升,函数提升会把整个函数挪到作用域顶部,变量提升只会把声明挪到作用域顶部
2 let const 不能提升,在window上找不到
|
38
|
1
|
class
|
语法糖 本质还是函数
|
39
|
2
|
继承类型
|
组合继承
寄生组合继承
|
40
|
2
|
为什么要使得模块化
|
解决命名冲突
提高复用性
提高代码的可维护性
|
41
|
1
|
es6模块化
|
1 es6模块不是对象
es6是编译时加载或者叫静态加载,即在编译时完成模块加载
export变量有两种方法
export var name:string = a; 或者
var name:string = 'a';
export {name } ; (我习惯用第一种,但书上建议用第二种)
export { name as test } 可以重命名 但不建议
import
如果模块名不含路径,那么import命令会去 node_modules 目录寻找这个模块
引入变量
import { first as test } from '路径'
import 都是在编译时加载的,不能在运行时加载
也可以整体加载
import { * as circle } from '路径'
关于default
export default XXX
import YYY from "" // 这样引入的YYY代表的就是XXX
require是运行时加载模块
|
42
|
|
proxy
|
Vue3.0中将会通过Proxy来替换原本的Object.defineProperty 来
实现数据响应式
|
43
|
1
|
map
filter
reduce
forEach
|
生成一个新数组
过滤生成一个新数组
const sum = arr.reduce( (acc, current) => acc + current, 0 ) ;
对每一项来执行
|
44
|
2
|
并发和并行concurrency
|
并发是宏观概念,我分别有任务A和任务B,在一段时间内通过任务间的切换完成了这两个任务
并行是微观概念,假设cpu存在两个核心 那么我就可以同时完成任务A和B
|
45
|
1
|
回调函数的缺点
|
改变牵一发而动全身
不能return
不能用try catch
|
46
|
2
|
generator函数返回什么
|
generator函数是一个状态机,封闭了内部状态。
执行generator会返回一个遍历器对象,
var hw = helloWorldGenerator() // hw是一个指向内部状态的指针对象
|
|
2
|
generator有哪两个特征
|
function后有一个*
内部使用yield表达式
|
|
2
|
Promise的本质
|
Promise的写法只是回调函数的改进,只能让异步任务看得更清楚,另外多了一个整体catch错误的方法
|
47
|
3
|
异步编程方法有哪些
|
回调函数
事件监听
发布订阅
Promise
|
48
|
2
|
js是什么线程
|
一个进程包括很多线程,线程只能逐个执行
js是单线程执行的
|
49
|
2
|
什么是执行栈
|
遵循先进后出的原则 |
50
|
2
|
异步代码执行顺序是什么 |
Event Loop
先执行微任务 再执行宏任务
微任务: process.nextTick() promise MutationObserver
宏任务有: script setTimeout setInterval setImmdiate I/O UI
rendering
|
51
|
2
|
V8下的垃圾回收机制
|
新生代算法:新分配的对象会被放入From空间中,
当From空间被占满时,GC 就会启动,
、检查From空间中存活的对象并复制到To空间中,如果有失活的对象就会销毁。当复制完成后将From和To空间互换
|
52
|
2
|
开发者工具里的技巧
|
Element里右键选择 scroll into view
Edit Break,在for循环里当i是某值时,就停在断点
|
53
|
2
|
事件触发过程
|
window -> 捕获 -> 目标 -> 冒泡 -> window
|
55
|
3
|
stopPropagation
|
来用阻止事件的进一步传播,可以阻止事件冒泡和捕获
|
56
|
2
|
stopImdiatePropagation
|
stopPropagation + 阻止该事件目标执行别的注册事件
|
57
|
2
|
什么是事件代理
|
即子节点需要注册事件的话,就注册到父节点上
|
58
|
3
|
跨域是为了防什么
|
用来防止csrf攻击,即利用用户的登录态发起恶意请求,浏览器拦截了这个响应
|
59
|
2
|
解决跨域问题的方法
|
方法一 jsonp
jsonp
function jsonp(url, jsonpCallback, success) {
let script = document.createElement('script')
script.src = url
script.async = true
script.type = 'text/javascript'
window[jsonpCallback] = function(data) { success && success(data)
}
document.body.appendChild(script);
}
jsonp('http://xxx', 'callback', function(value) {
console.log(value)
})
方法二 Cors cross origin resources sharing
需要目标服务器的后端response.setHeader 把 Access-Control-Allow-Origin 设置为 * 或允许www.test.17zuoye.net的加载
要找专门的cdn服务端 比如bootCDN
// 接收跨域的cookie response.setHeader("Access-Control-Allow-Credentials", "true");
|
60
|
|
实现储存有哪些方法
|
cookie sessionStorage localStorage indexDB
|
61
|
2
|
cookie的属性
|
cookie.http-only 不能通过js来访问,以减少xss攻击
cookie.secure 只能在https中携带
cookie.same-site 不能在跨域请求中携带
|
62
|
|
浏览器的缓存有哪引起位置 |
Service Worker
Memory Cache
Disk Cache
Push Cache
网络请求
|
63
|
3
|
两种缓存策略
|
强缓存 协商缓存
|
64
|
2
|
firefox ui引擎
|
Gecko
|
65
|
2
|
chrome 和 safari 里的 ui 引擎
|
Webkit
|
66
|
4
|
html渲染过程
|
浏览器接收到字节数据 -> 字符串 -> token -> Node 连接成Dom树
|
67
|
4
|
css渲染过程
|
字节数据 -> 字符串 -> Token -> Node -> 连接成CSSOM树
过于具体的css选择器,因要通过递归寻找,所以非常消耗资源
|
68
|
1
|
DOM树 CSSOM树
|
两个一志渲染树 -> reflow painting -> 调用gpu绘制 合成图层
|
69
|
3
|
如果实现插入很多Dom页面不卡顿
|
方法一:requestAnimationFrame 循环插入Dom
方法二:虚拟滚动 visualized scroller,即用react-visualized
|
70
|
3
|
如何减少阻塞渲染
|
1 减少html层级,减少css的复杂度
2 defer: script放到body最后,或者给script标签增加defer属性,表示js文件或并行下载,htmll解决完顺序执行
3 async: 对于没有任何依赖的js文件可以加async属性,表示js下载和解析不会阻塞渲染
|
71
|
2
|
重绘 repaint
回流 reflow
|
重绘:改外观而不改布局,比如改变颜色
回流:改变布局
|
72
|
3
|
减少重绘和回流 5 个
|
使用transform代替top
使用visibility替代display:none
少用js改变dom
动画速度越多,回流次数越多
频繁变化的节点要设置为图层,这样不会影响别的节点
|
73
|
3
|
XSS攻击 如何防范
|
cross site scripting 插入可执行的代码
1 永远不信任用户的输入
2 建立 CSP Content-Security-Policy 白名单,可以http header里设置,也可在meta里
2.1 只允许加载本站资源 default-src: 'self'
2.2 只允许加载https协议图片 img-src: https://*
2.3 允许加载任何来源的 child-src:'none'
|
74
|
3
|
CSRF攻击 如何防范4种
|
cross site request forgery 跨站伪造请求(伪造前端请求向后端发请求)
1 用get请求不对数据进行修改
2 设置cookie.same-site 不让第三方网站访问到用户的 cookie
3 阻止第三方网站请求接口(验证referer来判断请求是否为第三方发起的)
4 请求时要带验证信息,比如验证码或Token
|
75
|
3
|
点击劫持 如何防范
|
将要攻击的网站放到iFrame里面,伪造入口让用户点击
方法一 X-Frame-Options
deny:表示页面不允许通过iframe的方式展示
sameorigin:表示页面只可以在相同域名下通过iframe的方式展示
allow from表示页面可以在指定来源的iframe中展示
方法二:js防御
if (self == top) { var style = document.getElementById('click-jack') document.body.removeChild(style) } else { top.location = self.location }
|
76
|
2
|
中间人攻击 防范
|
中间人和客户端和服务端都建立了连接
解决方法:用https,并且关闭对http的修改访问。
|
77
|
2
|
测试性能工具
|
Audits 和 Performance
|
78
|
2
|
v8 JS性能优化
|
js -》抽象语法树 -> 用ignition转成ByteCode -> 用compiler turboFan 转成Machine code
让代码尽可能多的转为机器容易读的machine code
就应该让类型强制
v8引擎能把性能提升20多倍
|
79
|
2
|
图片优化方法 |
用css 不用图片
移动端,最好请求裁好的图片
多个图片合并成一张图
大图用webP, 小图用png,图标用svg,照片用jpeg
|
80
|
1
|
DNS预解析
|
预解析出ip地址
|
81
|
1
|
节流方法
|
不希望滚动过程中一直发出请求,可用throttle来实现
即实现一个执行间隔,不断执行
下拉加载新内容
|
82
|
1
|
防抖方法
|
debounce 用于下拉条,在事件派发过来中,只执行一次行为
debounce分为前缘和后缘
|
83
|
|
预加载
|
<link rel='preload' />
|
84
|
|
预渲染
|
<link rel='prerender' href='http://example.com'/>
|
85
|
1
|
懒加载 |
即将不关键的资源延后加载
懒加载图片 js 视频
|
86
|
1
|
cdn
|
content delivery network 内容分发网络
即把静态资源放到不同服务器上
|
87
|
1
|
webpack打包速度和打包大小
|
1 优化Loader的文件搜索范围
{ // js 文件才使用 babel
test: /\.js$/,
loader: 'babel-loader', // 只在 src 文件夹下查找
include: [resolve('src')],
// 不会去查找的路径 exclude: /node_modules/ }
2 缓存Babel编译过的文件
loader: 'babel-loader?cacheDirectory=true'
3 HappyPack
Node是单线程的,所以Webpack也是单线程,特别是在执行Loader的时候,长时间编译的
任务很多,这样就会导致等待的情况。
HappyPack可以把Loader的同步执行转换为并行的
这样写:loader:'happpack/loader?id=happybabel'
plugins:[
new HappyPack(
id:'happybabel',
loaders:[ 'babel-loader?cacheDirectory'],
threads: 4 ,
)
]
4 DllPlugin 可以将特定的类库提前打包然后引入
这极大地减少打包类库的次数,只有当类库更新版本才有需要重新打包,并且
也实现了将公共代码抽离成单独文件的优化方案。
具体略
5 代码压缩
在 webpack4中,把mode设置为production时,就会并行压缩js代码了
resolve.extensions
resolve.alias
module.noParse
6 按需加载,底层原理都是Promise
7 Scope Hoisting
代码就会尽可能把打包出来的模块合并到一个函数中去
module.exports = {
optimization: { concatenateModules: true }
}
8 Tree Shaking
实现删除项目中未被引用的代码
webpack4中,mode设置为production,就会自动删去
|
88
|
3
|
MVVM的精髓是什么
|
通过ViewModel将视图中的状态和用户的行为分离出一个抽象
View Binder ViewModel Model
|
89
|
1
|
visual Dom
|
Virtual DOM 实际上没有使用什么全新的技术,仅仅是把 “ 双缓冲(double buffering)” 技术应用到了DOM上面。
这样一来,当你在这个单独的虚拟的DOM树上也一个接一个地修改30个节点的时候,它不会每次都去触发重绘,所以修改节点的开销就变小了。
之后,一旦你要把这些改动传递给真实DOM,之前所有的改动就会整合成一次DOM操作。这一次DOM操作引起的布局计算和重绘可能会更大,但是相比而言,整合起来的改动只做一次,减少了(多次)计算
|
90
|
3
|
路由实现方式
|
Hash History 模式
|
91
|
2
|
vue v-show v-if
|
|
92
|
2
|
响应式原理 |
Object.defineProperty() 来实现数据响应式
通过这个函数可以监听到set和get事件
|
93
|
|
Vue编译过程是什么
|
模板 -> AST -> render函数 -> virtual Dom --> 真实的dom
|
94
|
|
nextTick原理分析
|
可让我们在下次dom更新循环结束后执行延迟回调,用于获得更新后的Dom
setImmediate -> MessageChannel -> setTimeout
|
95
|
|
React - Fiber |
它是一个虚拟的堆栈帧,
|
96
|
2
|
UDP
|
不需要建立连接,不需要验证数据报文,不需要流量控制,
但它可在实时性要求高的地方有所作为。比如视频和游戏
|
97
|
2
|
TCP
|
建立连接或断开连接都需要先握手
在传输数据的过程中,通过各种算法来保证数据的可靠性
|
98
|
|
TCP的头部信息
|
sequence number 可保证传输的报文都是有序的
acknowlegement number 这个序号表示数据接收端期望接收的下
|
99
|
1
|
TCP如何连接
|
建立连接要三次握手
客户端向服务端发
服务端应答
客户端确认
断开连接要4次握手
|
100
|
|
HTTP协议三部分
|
请求行 首部 实体
请求行:请求方法 url 协议版本
|
101
|
|
头部有哪四种
|
用户首部 请求首部 响应首部 实体首部
|
102
|
|
get post区别
|
get 无副作用 且幂等
post 有副作用 不幂等
|
103
|
|
TLS 技术
|
https通过http来传输信息,但是信息通过tls协议进行了加密
有两种加载技术:对称加密 + 非对称加密
对称加密 即两边有相同的密钥
非对称加密
|
104
|
|
状态码的规律
|
2xx 成功
3xx 重定向
4xx 客户端错误
5xx 服务端错误
|
|
|
时间复杂度
|
O(N)
|
|
|
栈 |
先进后出 push pop shifit unshift
|
|
|
队列
|
先进先出
|
|
|
链表 |
|
|
|
二叉树
|
|
|
|
二分搜索数
|
|
|
|
AVL树
|
|
|
|
Trie
|
|
|
|
并查集
|
|
|
|
堆
|
|
|
|
MVVM的精髓
|
viewModel将视图中的状态和用户的行为分离出一个抽象
|
|
|
Virtual DOM
|
React团队优化了算法,实现了O(n)的复杂并来对比差异,只对比同层的节点,而不是跨层对比,这也是考虑到在实际业务中很少会跨层的移动Dom元素
|
|
|
路由原理
|
本质就是监听url的变化 有两种实现方式:Hash模式 History模式
|
|
|
Vue和React的区别
|
Vue的表单可使用v-model支持双向绑定
Vue上手成本更低
|
|
|
Vue有哪些钩子函数
|
beforeCreate
created
beforeMount
beforeUpdate
updated
activated
deactivated
beforeDestroy
destroyed
|
|
|
父子通讯方法
|
父组件通过props传递数据给子组件
子组件emit事件给父组件
通过访问@parent和$children来访问对方
$listener属性会将父组件中的v-on事件监听器传递给子组件
子组件通过访问$listenerso来自定义监听器
.sync
|
|
|
兄弟组件通过
|
this.$parent.$children 再查找name来实现
|
|
|
跨多层次组件通信
|
provide
inject
|
|
|
任意组件 | Vuex 或 Event Bus 解决 |
|
|
mixin和
mixins的区别
|
mixin用于全局混入,会影响到每个组件实例,通常插件都是这样初始化的
mixins是我们最常见的扩展组件的方式
|
|
|
computed和watch的区别
|
computed 只有当计算值变化才会返回内容
watch 监听到值的变化就会执行回调
vm.$watch()
|
|
|
v-show v-if
|
v-if 表示不渲染
|
|
|
哪些事件不支持冒泡
|
ui事件 load unload 鼠标事件 mouseleave 焦点事件 blur focus
|
|
|
|
|
零碎面试题
什么是函数柯里化
|
add()()
|
es6的方法实现数组去重
|
let array = [1, 1, 1, 1, 2, 3, 4, 4, 5, 3];
let set = new Set(array); let arr = Array.from(set);
|
css中的层叠
|
|
|
|
|
|