apply
function myApply(obj,args){
/*
1. this指向调用者
2. 使用隐式绑定 obj.fn = this
3. obj.fn()
4. 调用完以后删除fn
*/
// 确保obj是一个对象
obj = (obj===null || obj === undefined) ? window:Object(obj)
obj.fn = this
obj.fn(...args)
delete obj.fn
}
// 添加到Function原型上
Function.prototype.myApply = myApply
call
Function.prototype.myCall = function(obj,...args){
obj = (obj===null || obj === undefined) ? window:Object(obj)
obj.fn = this
obj.fn(...args)
delete obj.fn
}
bind
Function.prototype.myBind = function(obj,...args){
// 判断是否为对象类型
obj = obj ===null||obj ===undefined ? window:Object(obj)
obj.fn = this
return (...fnArgs)=>{
obj.fn(...args,...fnArgs)
}
}
new
function myNew(fn){
/*
0. 判断是否是一个函数
1. 创建一个空对象,对象的原型指向fn的原型
2. fn绑定this
3. 返回对象或fn的返回值
*/
if (typeof fn !== 'function') {
throw 'must be a function'
}
var obj = Object.create(fn.prototype)
var args = [...arguments].slice(1)
var result = fn.apply(obj,args)
if ((typeof result ==='object' && typeof result !== null) || typeof result ==='function') {
return result
}
return obj
}
防抖函数
function debounce(fn, wait = 500, immediate = true) {
let timer = null
let isInvoke = false
const _debounce = function (...args) {
if (timer) clearTimeout(timer)
if (immediate && !isInvoke) {
fn.apply(this, args) // this 参数 绑定
isInvoke = true
return
}
timer = setTimeout(() => {
fn.apply(this, args) // this 参数 绑定
timer = null
isInvoke = false
}, wait)
}
_debounce.cancle = function(){
if (timer) clearTimeout(timer)
timer = null
isInvoke = false
}
return _debounce
}
const inp = document.querySelector('input')
inp.oninput = debounce(function (event) {
console.log(this.value)
}, 1000)
节流函数
function throttle(fn, interval, immediate = true, trailing = false) {
let startTime = 0
let timer = null
let res = null
const _throttle = function (...args) {
return new Promise((resolve, reject) => {
try {
let endTime = new Date().getTime()
if (!immediate && startTime === 0) {
startTime = endTime
}
let wait = interval - (endTime - startTime)
if (wait <= 0) {
if (timer) clearTimeout(timer)
res = fn.apply(this, args)
resolve(res)
startTime = endTime
timer = null
return
}
// 判断是否执行尾部
if (trailing && !timer) {
timer = setTimeout(() => {
res = fn.apply(this, args)
resolve(res)
startTime = new Date().getTime()
timer = null
}, wait)
}
} catch (error) {
reject(error)
}
})
}
// 取消功能
_throttle.cancel = function () {
if (timer) clearTimeout(timer)
timer = null
startTime = 0
}
return _throttle
}
const inp = document.querySelector('input')
inp.oninput = throttle(function () {
console.log(this.value)
}, 1000)
深拷贝
1. JSON方法:JSON.parse(JSON.stringify(obj)) 创建出一个全新的对象
缺点:
1.1 对一些数据无力,如:函数、Symbol
1.2 如果存在对象的循环引用,会报错
function isObject(value){
const valueType = typeof value
return (value !== null) && (value === 'object' || value === 'function')
}
function deepCopy(obj,map=new weakMap()){
// Symbol
if (typeof obj === 'symbol') {
return Symbol(obj.description)
}
if (!isObject(obj)) {
return obj
}
// Set 集合
if (obj instanceof Set) {
const newSet = new Set()
for (let item of obj) {
newSet.add(item)
}
return newSet
}
// Map
if (obj instanceof Map) {
return new Map(obj)
}
if (map.get(obj)) {
return map.get(obj)
}
const newObj = Array.isArray(obj)?[]:{}
map.set(obj,newObj)
// 遍历普通对象
for (const key in obj) {
newObj[key] = deepCopy(obj[key],map)
}
// 遍历Symbol
let objSymbols = Object.getOwnpropertySymbols(obj)
for (const key of objSymbols) {
objSymbols[key.description] = deepCopy(obj[key],map)
}
return newObj
}
事件总线
event-bus: 跨文件、跨组件通信
class EventBus {
constructor(){
this.eventObj = {}
}
on(eventName,eventFn){
let eventFns = this.eventObj[eventName]
if (!eventFns) {
this.eventObj[eventName] = []
}
eventFns.push(eventFn)
}
off(eventName,eventFn){
let eventFns = this.eventObj[eventName]
if (!eventFns) {
Reflect.delete(this.eventObj,eventName)
return
}
for (let i=0;i<eventFns.length;i++){
const fn = eventFns[i]
if (fn === eventFn) {
eventFns.splice(i,1)
break
}
}
}
emit(eventName,...args){
const eventFns = this.eventObj[eventName]
if (!eventFns) return
for (let fn in eventFns) {
fn(...args)
}
}
}