说说 Js 的数据类型都有哪些
基本类型
- String
- Number
- Boolean
- null
- undefined
- symbol
引用类型
object
说说 Http 状态码
1** 信息, 服务器收到请求, 需要请求者继续执行操作(101, 升级为 websocket 协议)
2** 成功, 操作被成功接收并处理(206, 部分内容, 分段传输)
3** 重定向, 需要进一步操作以完成请求(301,302 重定向; 304, 资源不存在)
4** 客户端错误, 请求包含语法错误或无法完成请求(401, 要求身份验证; 403, 服务器理解客服端需求, 但是禁止访问)
5** 服务器错误, 服务器在处理请求的过程中发生了错误
说说 ajax 状态码, ajax 一定是异步的吗?
ajax 不一定是异步的, 可以通过 open 方法的第三个参数来配置(默认为 true, 异步)
状态码:
0 - (未初始化)还没有调用 send()方法
1 - (载入)已调用 send()方法, 正在发送请求
2 - (载入完成)send()方法执行完成
3 - (交互)正在解析响应内容
4 - (完成)响应内容解析完成, 可以在客户端调用了
说说 ajax 是什么? 优势? 劣势? 应该注意的问题?
ajax 是一种和后台通信的标准. 全称是 Asynchronous Javascript And XML(异步 javascript 和 XML).
优势:
无需刷新页面请求数据, 可以使产品更快, 更小, 更友好
可以把以前服务端的任务转嫁到客户端来处理, 减轻服务器负担, 节省带宽
浏览器支持好, 无需插件
劣势:
不支持浏览器的回退按钮
安全性存在问题, 能够在用户不知情的情况下发送请求
暴露了 http 交互细节
对搜索引擎 (网络爬虫) 的支持比较弱
程序不容易调试
注意的问题:
浏览器兼容性问题, 这个问题 jQuery 等库已经帮我们封装好了
跨域问题, 不同域之间不允许通过 ajax 进行访问, 可以参考阮一峰老师的跨域资源共享 CORS 详解 http://www.ruanyifeng.com/blog/2016/04/cors.html
为了更快的速度和对搜索引擎友好, 首页尽量不要用 ajax 而是服务端渲染(当然这看分场景)
ajax 适合增删改查操作
你把下面的表达式的打印结果写出来
- 1.toString() //Uncaught SyntaxError: Invalid or unexpected token
- true.toString() //"true"
- [].toString() //""
- {}.toString() //Uncaught SyntaxError: Unexpected token .
- null.toString() //Uncaught TypeError: Cannot read property 'toString' of null
- undefined.toString() //Uncaught TypeError: Cannot read property 'toString' of undefined
- NaN.toString() //"NaN"
这些需要刻意背一下, 其中报错的这些都是因为没有 toString 方法. 当然你可以使用 call 来借用, 不过得到的是另外一种结果:
- Object.prototype.toString.call(1) //[object Number]
- Object.prototype.toString.call({}) //[object Object]
- Object.prototype.toString.call(null) //[object Null]
- Object.prototype.toString.call(undefined) //[object Undefined]
前端性能优化你了解哪些
内容层面
使用 CDN
单域名, 多域名, 单域名可以减少 DNS 查找次数, 多域名可以增加浏览器并行下载数量, 这需要权衡, 一般同一个域下不要超过四个资源.
避免重定向(分场景)
避免 404
网络层面
利用缓存, 可以参考另一篇文章手写文件服务器, 说说前后端交互
文件压缩(通过响应头 Accept-Encoding: gzip, deflate, br 告诉服务器你支持的压缩类型)
按需加载, 提取公共代码, tree-shaking 等(都可以通过 webpack 来实现)
减少 cookie 大小
文件合并, 通过 CSS 雪碧图合并图片
文件预加载, 图片懒加载
渲染层间
js 放底部, css 放顶部
减少 reflow(回流)和 repaint(重绘)
减少 dom 节点
代码层面
缓存 dom 节点, 减少节点查找, css 选择器层级优化
减少 dom 节点操作
合理使用 break,continue,return 等, 优化循环
像 react 用到的事件委托, 对象池等手段
说说浏览器的 reflow 和 repaint
浏览器解析过程
解析 html 生成 dom 树
解析 css
把 css 应用于 dom 树, 生成 render 树(这里记录这每一个节点和它的样式和所在的位置)
把 render 树渲染到页面
reflow(回流)
reflow 翻译为回流, 指的是页面再次构建 render 树. 每个页面至少发生一次回流, 就是第一次加载页面的时候
此外, 当页面中有任何改变可能造成文档结构发生改变(即元素间的相对或绝对位置改变), 都会发生 reflow, 常见的有:
添加或删除元素(opacity:0 除外, 它不是删除)
改变某个元素的尺寸或位置
浏览器窗口改变(resize 事件触发)
repaint(重绘)
repaint 翻译为重绘, 它可以类比为上面的第四步, 根据 render 树绘制页面, 它的性能损耗比回流要小. 每次回流一定会发生重绘. 此外, 以下操作 (不影响文档结构的操作, 影响结构的会发生回流) 也会发生重绘:
元素的颜色, 透明度改变
text-align 等
浏览器优化
我们不太容易精确知道哪些操作具体会造成哪些元素回流, 不同的浏览器都有不同的实现. 但是确定是他们的的耗时是比较长的, 因为涉及到大量的计算.
浏览器为了提升性能也对这个问题进行了优化. 方案就是维护一个队列, 把所有需要回流和重绘的操作都缓存起来, 一段时间之后再统一执行. 但是, 有的时候我们需要获取一些位置属性, 当我们一旦调用这些 api 的时候, 浏览器不得不立即计算队列以保证提供的数据是准确的. 例如以下操作:
offsetTop, offsetLeft, offsetWidth, offsetHeight
- scrollTop/Left/Width/Height
- clientTop/Left/Width/Height
- width,height
getComputedStyle 或者 IE 的 currentStyle
注意问题
批量处理
使用 DocumentFragment 进行缓存, 这样只引发一次回流
把频繁操作的元素先 display:null, 只引发两次回流
cloneNode 和 replaceChild, 只引发两次回流
不要频繁更改 style, 而是更改 class
避免频繁调用 offsetTop 等属性, 在循环前把它缓存起来
绝对定位具有复杂动画的元素, 否则会引起父元素和后续大量元素的频繁回流
如何去除字符串首位空格?
- //es6
- 'ab'.trim() //"ab"
- // 正则
- 'ab'.replace(/^\s*|\s*$/g,'') //"ab"
如何获取 url 中的查询字符串
- function queryUrlParameter(str) {
- let obj = {}
- let reg = /([^?=&#]+)=([^?=&#]+)/g;
- str.replace(reg, function () {
- obj[arguments[1]] = arguments[2]
- })
- // 如果加上 hash
- // reg = /#([^?&=#]+)/g
- // if (reg.test(str)) {
- // str.replace(reg, function () {
- // obj.hash = arguments[1]
- // })
- // }
- return obj
- }
- console.log(queryUrlParameter('http://www.baidu.com?a=1&b=2#12222')) //{ a: '1', b: '2'}
如何实现一个深拷贝, 深比较
深拷贝
- function clone(obj) {
- if (obj == null || typeof obj !== 'object') return obj
- let newObj = null
- // 时间对象有特殊性
- if (obj.constructor === Date) {
- newObj = new obj.constructor(obj)
- } else {
- obj.constructor()
- }
- for (let key in Object.getOwnPropertyDescriptors(obj)) {
- newObj[key] = clone(obj[key])
- }
- return newObj
- }
深比较
- function deepCompare(a, b){
- if(a === null
- || typeof a !== 'object'
- || b === null
- || typeof b !== 'object'){
- return a === b
- }
- const propsA = Object.getOwnPropertyDescriptors(a)
- const propsB = Object.getOwnPropertyDescriptors(b)
- if(Object.keys(propsA).length !== Object.keys(propsB).length){
- return false
- }
- return Object.keys(propsA).every( key => deepCompare(a[key], b[key]))
- }
如何实现函数节流和防抖
节流
- function throttle(fn, delay) {
- delay = delay || 50
- let statTime = 0
- return function () {
- statTime === 0 && fn.apply(arguments)
- let currentTime = new Date()
- if (currentTime = statTime> delay) {
- fn.apply(arguments)
- statTime = currentTime
- }
- }
- }
- let throttleFn = throttle(fn)
- throttleFn()
- throttleFn()
- throttleFn()
- throttleFn()// 只会执行一次
防抖
- function debounce(fn, delay) {
- delay = delay || 50
- let timer = null
- return function () {
- let self = this
- clearTimeout(timer)
- timer = setTimeout(fn.bind(self, arguments), delay);
- }
- }
你给我写一个原生 bind 方法
- Function.prototype._bind = function (context) {
- let self = this
- let args_1 = [].prototype.slice.call(arguments, 1)
- return function () {
- let args_2 = [].prototype.slice.call(arguments)
- let args = args_1.concat(args_2)
- return this.apply(context, args)
- }
- }
这只是对 bind 的一种简单实现, 如果有兴趣了解更多可以参考 Javascript 中 bind()方法的使用与实现 https://segmentfault.com/a/1190000002662251
如何实现一个数组的展平
- function (ary) {
- return ary.toString().split(',')
- }
这是一个投机取巧的方法(面试写个这个也凑合吧), 如果有兴趣可以搜索一下其他实现方法
如何添加, 删除, 移动, 复制 DOM 节点
创建
- createTextNode() // 创建文本节点
- createElement() // 创建元素节点
- createDocumentFragment() // 创建文档碎片
操作
- appendChild() // 增加
- removeChild() // 删除
- replaceChild() // 替换
- insertBefore() // 插入
查找
- getElementById()
- getElementByTagName()
- getElementByName()
来源: https://juejin.im/post/5af8f00c51882567105fda7b