call、apply和bind
call
思想:
- 使用对象调用函数,this指向该对象
- 将要调用call的函数放到传入的对象上
- 使用对象调用函数
- 删除掉该属性
Function.prototype.call2 = function (context) {
if (typeof this !== 'function') {
throw new TypeError('error')
}
// self表示传入的this
const self = [null, undefined].includes(context) ? Window : Object(context)
// args表示传入的参数
const args = [...arguments].slice(1)
// fn表示对象的属性,防止传入的this里就有fn属性,使用Symbol定义
const fn = Symbol('fn')
self[fn] = this
// 执行函数,result表示函数返回值
const result = self[fn](...args)
// 删除掉该属性
delete self[fn]
return result
}
apply
- 与call的思想相似
Function.prototype.apply2 = function (context) {
if (typeof this !== 'function') {
throw new TypeError('error')
}
// self表示传入的this
const self = [null, undefined].includes(context) ? Window : Object(context)
// fn表示对象的属性,防止传入的this里就有fn属性,使用Symbol定义
const fn = Symbol('fn')
self[fn] = this
// 根据是否传入的参数执行函数
const result = Array.isArray(arguments[1]) ? self[fn](...arguments[1]) : self[fn]()
delete self[fn]
return result
}
bind
- 注意考虑bind后的函数,可以用作构造函数的情况
Function.prototype.bind2 = function (context) {
if (typeof this !== 'function') {
throw new TypeError('error')
}
// self表示原函数
const self = this
// args表示bind时传入的参数
const args = [...argument].slice(1)
return function F() {
if (this instanceof F) {
// bind后的函数作为构造函数调用
return new self(...args, ...arguments)
}
return self.apply(context, args.contact([...arguments]))
}
}
函数防抖和节流
函数防抖
- 函数防抖指的是事件触发n秒后执行。若事件触发的n秒内又触发,则重新计时
function debounce(func, wait, immediate) {
let timer
return function () {
timer && clearTimeout(timer)
if (immediate) {
// immediate为真,表示事件触发立即执行,然后再n秒计时
const isCallNow = !timer
if (isCallNow) {
func.apply(this, arguments)
}
timer = setTimeout(() => {
timer = null
}, wait)
} else {
timer = setTimeout(() => {
func.apply(this, arguments)
}, wait)
}
}
}
函数节流
- 函数节流指的是事件频繁触发,每隔n秒执行一次
// 使用时间戳实现函数节流
function throttle (func, wait) {
let pre = 0
return function () {
const now = +new Date()
if (now - pre > wait) {
func.apply(this, arguments)
pre = now
}
}
}
// 使用计时器实现函数节流
function throttle (func, wait) {
let timer
return function () {
if (!timer) {
timer = setTimeout(() => {
timer = null
func.apply(this, arguments)
}, wait)
}
}
}
发布-订阅模式的事件类
class Event {
constructor() {
this._cache = new Map()
}
// 注册事件
on(type, cb) {
!this._cache.has(type) && this._cache.set(type, new Set())
!this._cache.get(type).has(cb) && this._cache.get(type).add(cb)
return this
}
// 触发事件
trigger(type, ...data) {
if (this._cache.has(type) && this._cache.get(type).size > 0) {
for (const cb of this._cache.get(type)) {
cb(...data)
}
}
return this
}
// 移除事件
off(type, cb) {
if (this._cache.has(type)) {
if (cb) {
const cbs = this._cache.get(type)
for (const callback of cbs) {
if (callback === cb || callback.cb === cb) {
cbs.delete(callback)
}
}
} else {
this._cache.delete(type)
}
}
return this
}
// 只监听一次
once(type, cb) {
const on = (...args) => {
this.off(type, cb)
cb.apply(this, args)
}
on.cb = cb
this.on(type, on)
return this
}
}
未完待续。。。