基础题
https://juejin.im/post/5af8f00c51882567105fda7b
https://www.cnblogs.com/kevin2chen/p/6418327.html
event loop
task主要包含:setTimeout、setInterval、setImmediate、I/O、UI交互事件
获取H5页面打开时间
准备工作
- 一部测试手机(安卓,ios)
- 一部iPhone手机(可以是自己的手机)
- Aegisub(读音:/ˈiːdʒisʌb/)是一个免费、开源、跨平台的字幕编辑软件
测试手机
用来打开需要测试的h5页面,测试的时候需要考虑几种情况(安卓,ios,Wi-Fi,4G,有缓存,无缓存)。
主要是看点击按钮以后,从新webview显示第一帧到页面第一个元素可见的时间(不包括灰图或者loading)。
iPhone手机
iPhone进行60fps拍摄,开启方式:设置 → 相机 → 录制视频 → 1080p HD, 60fps,
经过实测,录制的视频为60fps, 精度在16 毫秒左右,对app本身性能无影响。
设置好以后录制测试手机打开h5页面的视频。
为了保证准确率建议录制5-10次去掉特殊情况取平均值。
Aegisub视频工具
把iPhone录制好的视频拖入Aegisub里面,按方向键,如图记录新开webview的时间和页面第一个元素可见时间,然后使用可见时间减去新开webview的时间即为页面打开时间。
microtask主要包含:Promise、process.nextTick、MutaionObserver
css 权重
!important > 行内样式(比重1000) > id(比重100) > class/属性(比重10) > tag / 伪类(比重1);
css的百分比定位
- 一个元素的border-radius定义的百分比值,参照物是这个元素自身的尺寸
- margin和padding,其任意方向的百分比值,参照都是包含块的宽度。
- 由放置背景图的区域尺寸,减去背景图的尺寸得到,可以为负值
- font-size 参照是直接父元素的font-size
- line-height参照是元素自身的font-size
react setstatus删除对象
this.setState((prevState, props) => {
delete prevState.prop;
return prevState;
});
this.setState({
a:'',null,undefind
});
浏览器渲染dom顺序
- HTML解析出DOM Tree
- CSS解析出Style Rules
- 将二者关联生成Render Tree
- Layout 根据Render Tree计算每个节点的信息
- Painting 根据计算好的信息绘制整个页面
js中new一个对象的过程
优先级由高到低:小括号(xxx) ---> 属性访问. ---> new foo() ----> foo()
js 代码优化
- if(!myValue)
- var a = function(){} 方法执行完之后立马销毁
- 请尽量避免使用全局变量
map 对象
var item = {};
size Object.Keys(items).length;
set items[key] = value;
remove
if (this.has(key)) {
delete items[key];
return true;
}
return false;
has return key in items;
get return this.has(key)?items[key]:undefined;
clear items = {};
values
promise对象
repaint 和reflow
repaint主要是针对某一个DOM元素进行的重绘,reflow则是回流,针对整个页面的重排
触发repaint:
color的修改,如color=#ddd;
text-align的修改,如text-align=center;
a:hover也会造成重绘。
:hover引起的颜色等不导致页面回流的style变动。
等等太多,一时间写出来也太难想了。
触发reflow:
width/height/border/margin/padding的修改,如width=778px;
动画,:hover等伪类引起的元素表现改动,display=none等造成页面回流;
appendChild等DOM元素操作;
font类style的修改;
background的修改,注意着字面上可能以为是重绘,但是浏览器确实回流了,经过浏览器厂家的优化,部分background的修改只触发repaint,当然IE不用考虑;
scroll页面,这个不可避免;
resize页面,桌面版本的进行浏览器大小的缩放,移动端的话,还没玩过能拖动程序,resize程序窗口大小的多窗口操作系统。
读取元素的属性(这个无法理解,但是技术达人是这么说的,那就把它当做定理吧):读取元素的某些属性(offsetLeft、offsetTop、offsetHeight、offsetWidth、scrollTop/Left/Width/Height、clientTop/Left/Width/Height、getComputedStyle()、currentStyle(in IE));
promise静态方法
Promise.resolve()
Promise.reject()
Promise.all()
Promise.race()
this 关键字
this是Javascript语言的一个关键字。它代表函数运行时,自动生成的一个内部对象,只能在函数内部使用。
完全取决于他的执行环境
this指的是,调用函数的那个对象
new 执行过程
创建一个空的对象
let p1 = new Object();
Object.create({})
设置原型链
p1.proto = SouthSu.prototype;
让 构造函数 的this 指向 p1 这个空对象
let funCall = SouthSu.call(p1);
判断 js 中的数据类型
typeof
instanceof
其实 instanceof 主要的作用就是判断一个实例是否属于某种类型
let person = function () {
}
let nicole = new person()
nicole instanceof personconstructor [a.constructor,b.constructor]
Object.prototype.toString.call(a) === ‘[object String]’
数据类型
Object,Number,String, Boolean, Undefined,Null.
undefined,表示一个未知状态,声明了但是没有初始化的该变量.
null 表示尚未存在的对象,null 是一个有特殊意义的值。
parseInt(arg)将指定的字符串,转换成整数
parseFloat(arg)将指定的字符串,转换成浮点数
Number(arg)
String(arg)把给定的值(任意类型)转换成字符串;
Boolean(arg)把给定的值(任意类型)转换成 Boolean 型;
原型链,对象,构造函数之间的一些联系
每一个函数(类)都有属性protytype(原型)属性,属性值是一个对象;这个对象中存储了当前供实例调用的共有属性和方法;
在浏览器默认给原型开辟的堆内存中存在属性constructor;存储的是当前类本省;
每一个对象(实例)都有proto(原型链)属性,这个属性指向所属类的原型(不确认所属的类,都指向object.prototype)
function People(){}
var p = new People()
p.proto === People.prototype
People.proto === Function.prototype
People.prototype.proto === Object.prototype
//代码2
Function.prototype === Function.proto
Function.prototype === Object.proto
Function.prototype.proto === Object.prototype
Function instanceof Object
call,apply,bind
let arr1 = [1, 2, 19, 6];
//例子:求数组中的最值
console.log(Math.max.call(null, 1,2,19,6)); // 19
console.log(Math.max.call(null, arr1)); // NaN
console.log(Math.max.apply(null, arr1)); // 19 直接可以用arr1传递进去
而bind则是返回改变了上下文后的一个函数。
说说xss与csrf,怎么防止
xss:跨站脚本攻击,如果不过滤执行了js代码,可能导致cookie泄露等。防止:过滤
csrf:跨站请求伪造,挟制用户在当前已登录的Web应用程序上执行非本意的操作。防止:设置token、写操作用post、JSON API禁用CORS、禁用跨域请求、检查referrer
事件委托代码
// 给父层元素绑定事件
document.getElementById('list').addEventListener('click', function (e) {
// 兼容性处理
var event = e || window.event;
var target = event.target || event.srcElement;
// 判断是否匹配目标元素
if (target.nodeName.toLocaleLowerCase() === 'li') {
console.log('the content is: ', target.innerHTML);
}
});
局限性
比如 focus、blur 之类的事件本身没有事件冒泡机制,所以无法委托;
mousemove、mouseout 这样的事件,虽然有事件冒泡,但是只能不断通过位置去计算定位,对性能消耗高,因此也是不适合于事件委托的;
闭包
把闭包简单理解成"定义在一个函数内部的函数"。
保存和保护函数内部的变量
另一个就是让这些变量的值始终保持在内存中。
因为 IE。IE 有 bug,IE 在我们使用完闭包之后,依然回收不了闭包里面引用的变量。
内容层面
- 使用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用到的事件委托、对象池等手段
跨域解决办法
浏览器的同源策略导致了跨域
不同域名,不同domain,不同端口
解决办法:
- nginx 反向代理(nginx 服务内部配置 Access-Control-Allow-Origin *)
- cors 前后端协作设置请求头部,Access-Control-Allow-Origin 等头部信息
- iframe 嵌套通讯,postmessage
通过修改docment.domain来实现跨域
该方法必须是在同主域,不同子域的情况下才生效
比如:morningstar.com 和test.morningstar.com - jsonp ,允许 script 加载第三方资源
- postMessage
不同域之间的跨域请求 使用postMessage。postMessage是HTML5新增的方法
Array对象常用方法中:
不改变原数组:
1、 concat()
[].concat([1])
连接两个或多个数组
不改变原数组
返回被连接数组的一个副本
2、join()
[1,2,3].join('1')
把数组中所有元素放入一个字符串
不改变原数组
返回字符串
3、 slice()
[12,3,4,5,6].slice(1,2)
从第几个到第几个
从已有的数组中返回选定的元素
不改变原数组
返回一个新数组
4、 toString()
把数组转为字符串
不改变原数组
返回数组的字符串形式
改变原数组:
5、 pop()
删除数组最后一个元素,如果数组为空,则不改变数组,返回undefined
改变原数组
返回被删除的元素
6、 push()
向数组末尾添加一个或多个元素
改变原数组
返回新数组的长度
7、 reverse()
颠倒数组中元素的顺序
改变原数组
返回该数组
8、 shift()
把数组的第一个元素删除,若空数组,不进行任何操作,返回undefined
改变原数组
返回第一个元素的值
9、 sort()
对数组元素进行排序(ascii)
改变原数组
返回该数组
10、 splice()
从数组中添加/删除项目
改变原数组
返回被删除的元素
11、 unshift()
向数组的开头添加一个或多个元素
改变原数组
返回新数组的长度
基本的数据类型
5个简单数据类型(基本数据类型)+ 1个复杂数据类型
undefiend, number string null boolean + object
ES6 新增Symbol
深拷贝对象方法
- 直接遍历
function copy (obj) {
let newObj = {};
for (let item in obj ){
newObj[item] = obj
}
return newObj;
}
var copyObj = copy(obj);
- ES6的Object.assign
var copyObj = Object.assign({}, obj); - ES6扩展运算符:
var copyObj = { ...obj } - 多层嵌套拷贝
JSON.parse(JSON.stringify(XXXX)) - immutable
const map1 = Map({ a: 1, b: 2, c: 3 })
const map2 = map1.set('b', 50)
React生命周期
https://zhuanlan.zhihu.com/p/35587283
React 16新特性
Error Boundary
在React 16中,render方法支持直接返回string,number,boolean,null,portal,以及fragments(带有key属性的数组),这可以在一定程度上减少页面的DOM层级。
使用createPortal将组件渲染到当前组件树之外
setState传入null时不会再触发更新
React.lazy() 和 Suspense
Loading...