前端优化
-
减少http请求, 合理设置http缓存
-
合并css 合并js 合并图片
-
-
使用浏览器缓存
-
设置http头的Cache-Control 和 Expires设置缓存有效期
-
-
对代码使用gzip压缩
-
css sprite svg font
-
图片懒加载
-
css放在最上面,JavaScript放在后面,浏览器碰到js立即执行,阻断了后面的进程
-
减少cookie的传输
-
在页面加载完后触发方法 window.onload
-
js优化
-
避免eval 和function
-
减少作用域查找
-
css选择符优化,层级不宜过多
-
cdn加速,cdn本质缓存,数据缓存在离用户最近的地方,使用户最快的获取到数据,一般多是静态资源文件
-
Nginx反向代理,分发用户请求
-
防抖与节流
// 使用setTimeout来存放待执行的函数, 然后使用clearTimeout在合适的时机清除待执行的函数
// 防抖 不管事件发生的频率多快,一定在wait的时间后执行,记录开始的timer延时事件, 新事件有操作,后面覆盖前面的事件,最后那一次一定触发
function debounce (fn, wait) {
let timer = null
return function (...args) {
clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, args)
}, wait)
}
}
// 节流 不管事件发生频率多快,在wait时间内,无论怎么去触发,执行效果只有一次。 timer存在就不会执行下面的操作。只有在执行下面的操作重置timer为null,事件在wait时间内执行完毕后才能触发下次事件
function throttle (fn, wait) {
let timer = null
return function (...args) {
if (!timer) {
timer = setTimeout(() => {
fn.apply(this, args)
timer = null
}, wait)
}
}
}
严格判断数据类型
Object.prototype.toString.call({}) => [Object Object]
Object.prototype.toString.call([]) => [Object Array]
typeof() 判断简单类型 undefined => undefined null => Object array => object
实现promise
function Promis (exactor) {
let _this = this
_this.status = 'padding'
_this.failCallBack = null
_this.successCallBack = null
exactor(resolve.bind(_this), reject.bind(_this))
function resolve (params) {
if (_this.status == 'padding') {
_this.status = 'success'
_this.successCallBack(params)
}
}
function reject (params) {
if (_this.status == 'padding') {
_this.status = 'fail'
_this.failCallBack(params)
}
}
}
Promis.prototype.then = function (full, fail) {
this.successCallBack = full
this.failCallBack = fail
}
new Promis((resolve, reject) => {
setTimeout(() => {
resolve('成功')
}, 1000)
}).then(res => {
console.log(res)
})
vue的生命周期
beforeCreate: 实例创建之前,不能访问到实例的data和method
created: 实例创建完成 这时候能够访问实例的data和method
beforeMounted: 实例挂在到dom树之前
mounted: 实例dom挂载完成,可以操作dom
beforeUpdate: 数据更新之前
update: 数据更新完成
beforeDestoryed: 实例销毁之前
destoryed: 实例销毁
闭包
// 定义:能狗访问局部作用域的函数,上级函数作用域不会被清除
// 应用 自执行函数
for (var i = 0; i < 5; i++) {
(function son(j) {
setTimeout(() => {
console.log(j)
}, j * 1000)
})(i)
}
// 每隔1s输出 0 1 2 3 4
for (var i = 0; i < 5; i++) {
setTimeout(() => {
console.log(i)
}, i * 1000)
}
// 每隔1s输出 5 5 5 5 5
原型链和原型
// 实例被构造函数通过new关键字构建出来,实例的__proto__会指向构造函数的prototype, 构造函数的prototype的__proto__指向Function.prototype, Function.prototype的__proto__会指向Object.prototype, 而Object.prototype的__proto__会指向null,这样就形成了一条原型链。实例可以通过原型链寻找自己本身没有的方法,有利于方法的拓展。如Object.prototype.toString.call({})
js继承
-
原型链继承: 通过原型链指向继承,引用属性会共用,不能向父级传递参数
-
构造函数继承:通过call或apply改变this指向调用父函数,属性不会共享, 可以向父级传递参数,复用性不强
-
组合继承:通过call或apply改变this指向调用父函数,属性不会共享,可以向父级函数传递参数,能够实现代码的复用
-
原型式继承: 借助原型已有对象创建新对象,需要一个对象作为父级基础, 父级引用属性可以共用
-
寄生式继承: 借助原型已有对象创建新对象,并给他添加方法或属性,并且返回这个对象,父级阴影属性不能共用
-
寄生组合式继承: 通过call或apply改变this指向调用父函数,然后将父函数的原型复制给子函数,并且改变子函数的额原型的constructor,引用属性不会共用, 能够向父函数传递参数,有好的复用性
-
es6继承 extend
class father {
constructor ({name, age}) {
this.name = name
this.age = age
}
sayHi () {
console.log('哈哈哈')
}
}
class Son extends father {
constructor (arr) {
super(arr)
}
sayName () {
console.log(this.name)
}
}
const peo = new Son({
name: '张三',
age: 13
})
peo.sayHi() // 哈哈哈
peo.sayName() // 张三
console.log(peo) // { name: '张三', age: 13, __proto__: father }
call和apply、bind的区别
// call和apply、bind都是改变函数内部的指向
// call和apply是直接调用, 传入参数call可以接受多个参数, apply是接受一个数组
// bind是返回一个函数,需要再次调用
Function.prototype.myCall = function (context) {
// 赋值作用域,没有就默认window,即访问全局
context = context || window
context.fn = this
let args = [...arguments].slice(1)
// 4.执行调用函数就是第二步保存的fn,记录返回值
let result = context.fn(...args);
// 5.销毁调用函数,以免作用域污染;
Reflect.deleteProperty(context, 'fn');
return result;
}
Function.prototype.mApply = function(context) {
context = context || window;
context.fn = this;
let result;
if (arguments[1]) {
result = context.fn(...arguments[1]);
} else {
result = context.fn();
}
Reflect.deleteProperty(context, "fn");
return result;
}
test.mApply(tempObj, [1, 2, 3]);
Function.prototype.mBind = function (context) {
// 获取绑定时的传参
let args = [...arguments].slice(1),
// 定义中转构造函数,用于通过原型连接绑定后的函数和调用bind的函数
F = function () {},
// 记录调用函数,生成闭包,用于返回函数被调用时执行
self = this,
// 定义返回(绑定)函数
bound = function () {
// 合并参数,绑定时和调用时分别传入的
let finalArgs = [...args, ...arguments]
// 改变作用域,注:aplly/call是立即执行函数,即绑定会直接调用
// 这里之所以要使用instanceof做判断,是要区分是不是new xxx()调用的bind方法
return self.call((this instanceof F ? this : context), ...finalArgs)
}
// 将调用函数的原型赋值到中转函数的原型上
F.prototype = self.prototype
// 通过原型的方式继承调用函数的原型
bound.prototype = new F()
return bound
}