1. bind函数
Function.prototype.myBind = function (thisArg, ...args) {
if (thisArg == null) {
thisArg = window || global
}
const fn = this
if (typeof fn !== 'function') {
throw 'wrong called'
}
return function (...otherArgs) {
return fn.apply(thisArg, args.concat(otherArgs))
}
}
2. call函数
改变内部this指向,立即执行
Function.prototype.myCall = function (thisArg, ...args) {
const fn = this
if (typeof fn !== 'function') {
throw 'wrong called'
}
if (thisArg == null) {
thisArg = window || global
}
thisArg[fn] = fn
let res = thisArg[fn](...args)
delete thisArg[fn]
return res
}
3. new创建对象
function myNew(con, ...args) {
let newObj = Object.create(con.prototype) // 空对象的原型设置为构造函数的原型,即obj.proto = func.prototype;
let res = con.apply(newObj, args) //继承对像属性和方法
return typeof res === 'object' && res != null ? res : newObj
}
4. instanceof实现
用于检测构造函数的 prototype属性是否出现在某个实例对象的原型链上
例如数组实例 arr的构造函数 Array的原型对象就在该实例对象的原型链上。
function myInstanceof(left, right) {
if (typeof left !== 'object' || right == null) {
return false
}
left = left.__proto__
right = right.prototype
while (true) {
if (left == null) return false
if (left === right) return true
left = left.__proto__
}
}
5. 防抖函数
在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。(函数防抖就是法师发技能的时候要读条,技能读条没完再按技能就会重新读条。)(用户频繁触发事件)
思路:外界事件触发定时器,定时器存在就清除重新定一个定时器,最后执行完将定时器初始化
function debounce(fn, delay = 500) {
let timer = null
return function (...args) {
// 如果定时器已经开启,则清除定时器
if (timer) clearTimeout(timer)
// 重新定时
timer = setTimeout(() => {
fn.apply(this, args)
timer = null
}, delay)
}
}
6. 节流函数
函数节流是间隔时间执行。
规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发多次函数,只有一次生效。(函数节流就是fps游戏的射速,就算一直按着鼠标射击,也只会在规定射速内射出子弹。)
function throttle(fn, delay = 200) {
let timer = null
return function (...args) {
// 如果定时器存在,说明还未到时,直接返回
if (timer) return
// 设置定时任务,到时后执行fn,并重置定时器为null
timer = setTimeout(() => {
fn.apply(this, args)
timer = null
}, delay)
}
}
7. 函数柯里化
部分求值,给函数分步传递参数
每次传递参数进行处理,并返回一个更具体的函数接受剩下的参数
const sum = (...args) => {
return args.reduce((a,b) => {
return a+b;
})
}
var currying = function(func){
const args = [] //func函数的参数
return function result(...rest){//接受剩下的参数,需要递归调用
if(rest.length === 0 ){//当长度等于0的时候就开始计算sum
return func(...args)
}else{//参数有长度
args.push(...rest);
return result;//链式调用
}
}
}
currying(sum)(1)(2,3)(5)()
8. 数组扁平化
Array.prototype.flat = function(){
const result = this.map(item=>{ //对数组每项进行map处理,返回新的数组
if(Array.isArray(item)){//元素还是个数组,继续进行扁平化
return item.flat()
}
return [item]//[[1],[2],[3]]
})
eturn [].concat(...result)
}
//去重set
Array.prototype.unique = function(){
return [...new Set(this)]
}
//排序
const sotrFn = (a,b) => a-b;
arr.flat().unique()..sort(sortFn)
9. 数组转树形结构
var menu_list = [
{
id: '1',
menu_name: '设置',
menu_url: 'setting',
parent_id: 0,
},
{
id: '1-1',
menu_name: '权限设置',
menu_url: 'setting.permission',
parent_id: '1',
},
{
id: '1-2',
menu_name: '菜单设置',
menu_url: 'setting.menu',
parent_id: '1',
},
{
id: '2',
menu_name: '订单',
menu_url: 'order',
parent_id: 0,
},
{
id: '2-1',
menu_name: '报单审核',
menu_url: 'order.orderreview',
parent_id: '2',
},
{
id: '2-2',
menu_name: '退款管理',
menu_url: 'order.refundmanagement',
parent_id: '2',
},
]
function toTree{
var res = []
var map = {}
data.forEach(item=>{//根据id弄个字典
map[item.id] = item;
})
data.foreach(item=>{
let parent = map[item.pid];
if(parent){
(parent.child || (parent.child = [])).push(item)
}else{//pid找不到导致parent不存在
res.push(item)
}
})
return res
}
10. 对象深拷贝
浅拷贝方法: Object.assign({},list)、[...list]、{...list}、map、filter、reduce
深拷贝方法:
-
Json
JSON.parse(JSON.stringify(list))- json能解决数组的深拷贝也能解决Object的深拷贝
function deepCopy(newObj, oldObj){
for(let k in oldObj){
// 判断我们的属于那种数据类型
// 1. 获取属性值
let item = oldObj[k]
// 2. 判断值是否是数组
if(item instanceof Array){
newObj[k] = [];
deepCopy(newObj[k], item)
}else if(item instanceof Object){// 3. 判断是是否是对象
newObj[k] = {}
deepCopy(newObj[k], item)
}else{// 4. 属于简单数据类型
newObj[k] = item
}
}
}
11.洋葱模型
app.use(async next => {
console.log(1)
await next()
console.log(2)
})
app.use(async next => {
console.log(3)
await next()
console.log(4)
})
app.use(async next => {
console.log(5)
await next()
console.log(6)
})
app.compose() //135642
12.手写发布订阅模式
class EventEmitter {
events: {[key: string]: Function[]} = {}
// 订阅
on(type: string, callback: Function) {
if(!this.events) this.events = Object.create(null)
if(!this.events[type]) {
this.events[type] = [callback]
}else {
this.events[type].push(callback)
}
}
// 取消订阅
off(type: string) {
if(!this.events[type]) return
delete this.events[type]
}
// 只执行一次订阅
once(type: string, callback: Function) {
function fn() {
callback()
this.off(type)
}
this.on(type, fn)
}
// 触发事件
emit(type: string, ...rest) {
this.events[type] && this.events[type].forEach(fn => fn(...rest))
}
}
// 使用情况
const event = new EventEmitter()
event.on('click', (...rest) => {
console.log(rest)
})
event.emit('click')
event.off('click')
event.once('click', (...rest) => {
console.log(rest)
})
13. 手写Promise系列
//实现promise.all()
/*
Promise函数对象的all方法
返回一个promise对象,只有当所有promise都成功时返回的promise状态才成功
*/
Promise.myAll = function(promises){
const values = new Array(promises.length)
var resolvedCount = 0; //计状态为resolved的promise的数量
return new Promise((resolve,reject)=>{
// 遍历promises,获取每个promise的结果
promises.forEach((p,index)=>){
Promise.resolve(p).then(
value =>{
// p状态为resolved,将值保存起来
values[index] = value
resolvedCount++;
// 如果全部p都为resolved状态,return的promise状态为resolved
if(resolvedCount === promises.length){
resolve(values)
}
},
reason =>{ //只要有一个失败 return的promise状态reject
reject(reason);
})
})
})
}
//实现Promise.race()
/*
Promise函数对象的race方法
返回一个promise对象,状态由第一个完成的promise决定
*/
Promise.myRace = function(promises){
return new Promise((resolve,reject)=>{
// 遍历promises,获取每个promise的结果
promises.forEach((p,index)=>{
Promise.resolve(p).then(
value => {
// 只要有一个成功,返回的promise的状态就为resolved
resolve(value)
},
reason => { //只要有一个失败,return的promise状态就为reject
reject(reason)
}
)
})
})
}
//手写promise
class myPromise{
constructor(fn){
//将成功的函数集成在successList数组里面
this.successList = [];
//将所有的失败函数集成在failList里面
this.failList = [];
//pending(进行中) fulfilled(已成功) rejcet(以失败)
this.state = "pending"
//传入的函数对象(异步操作函数内容)
fn(this.resolveFn.bind(this),this.rejectFn.bind(this));
}
// 状态转变为 resolve 方法
resolveFn(res){
this.state = "fulfilled";
this.successList.forEach(function(item){
//将成功的事件循环调用
item(res)
})
}
// 状态转变为 rejected 方法
rejectFn(res){
//将注册到的失败所有事件进行调用
this.state = "rejected";
this.failList.forEach(function(item){
item(res)
})
// throw Error(res);
}
//then方法
then(successFn,failFn){
if(typeof successFn == "function"){
this.successList.push(successFn);
}
if(typeof failFn == "function"){
this.failList.push(failFn)
}
}
//catch方法
catch(failFn){
if(typeof failFn == "function"){
this.failList.push(failFn)
}
}
}
var fn = function(resolve,reject){
setTimeout(function(){
if(false){
resolve("自定义成功")
}else{
reject("自定义失败")
}
},2000)
}
14.使用class 手写一个promise
/创建一个Promise的类
class Promise{
constructor(executer){//构造函数constructor里面是个执行器
this.status = 'pending';//默认的状态 pending
this.value = undefined//成功的值默认undefined
this.reason = undefined//失败的值默认undefined
//状态只有在pending时候才能改变
let resolveFn = value =>{
//判断只有等待时才能resolve成功
if(this.status == pending){
this.status = 'resolve';
this.value = value;
}
}
//判断只有等待时才能reject失败
let rejectFn = reason =>{
if(this.status == pending){
this.status = 'reject';
this.reason = reason;
}
}
try{
//把resolve和reject两个函数传给执行器executer
executer(resolve,reject);
}catch(e){
reject(e);//失败的话进catch
}
}
then(onFufilled,onReject){
//如果状态成功调用onFufilled
if(this.status = 'resolve'){
onFufilled(this.value);
}
//如果状态失败调用onReject
if(this.status = 'reject'){
onReject(this.reason);
}
}
}
15. 手写ajax的get和post封装
16. 手写Vuex
let Vue;
class Store{
constructor(options){// options就是new Vuex.Store传入的参数
// 1.使用vue实列来实现响应式变化,保证状态更新会刷新视图
this.vm = new Vue({//1.data会被使用Object.defineProperty重新定义
date: {
state: options.state
}
});
// 2.解析options.getters,它是一个对象,里面都是函数
this.getters={};
Object.keys(options.getters).forEach(getterName=>{
Object.definePropery(this.getters, getterame,{
get:()=>{return options.getters[getterName](this.state)}
})
});
//3.解析options.mutations
this.mutations = {};
Object.keys(options.mutations).forEach(mutationsName=>{
this.mutations[mutationsName] = (payload)=>{
options.mutations[mutationsName](this.state, payload)
}
});
// 4.解析options.actions
this.actions = {};
Object.keys(options.actions).forEach(actionsName=>{
this.actions[actionsName] = (payload)=>{
options.actions[actionsName](this, payload)
}
});
}
get state(){ //1.获取实例上的state——>store.state
// 1.相当于this.state = this.vm.state
return this.vm.state
}
// 3.用箭头函数的目的是让this一直指向Store——>$store.commit
commit = (mutationName, payload) => {this.mutations[mutationsName](payload)};
// 4.$store.dispatch
dispatch = (actionName, payload) =>{this.actions[actionsName](payload)}
}
// 每一个插件都有一个install函数,主要就是只有当前的实例才能使用这个插件
const install = (_Vue) => { //_Vue是vue的构造函数
// 使得当前插件不再依赖Vue而是通过用户把Vue传过来,import vue打包的时候体量太大?
Vue = _Vue; //传过来的vue的构造函数
// 下载不是下载到vue的原型上,我们只想给当前实列下的组件使用
// 使用mixin,抽离组件的公共逻辑,每个组件(vue)调用beforeCreate都会执行里面的方法
// 值得注意的是,main.js(父)有个vue,app.vue也有个vue(子)
Vue.mixin({
beforeCreate(){
// console.log(this.name)//root-->app-->app的子...
// 为了让所有子组件使用store,就把root的store属性放在每个组件的实列上
if(this.$options.store){//是root,这个root是有store的
this.$store = this.$options.store
}else{// 是子组件
this.$store = this.$parent && this.$parent.$store
}
}
})
}
export default{
Store,
install
}