1. 实现new方法
function objectCreate(Constructor, ...rest) {
// 以构造函数的原型创建新对象
var obj = Object.create(Constructor.prototype);
// 以obj为this上下文来执行构造函数
var res = Constructor.apply(obj, rest);
// 根据new生成对象的原则,若有返回值为对象,则返回该结果,若没有,则返回开始生成的对象
return typeof ret === 'object' ? res : obj
}
// 示例
function MyConstructor() {...}
var instance = objectCreate(MyConstructor, ...)
2.实现call方法
Function.prototype.myCall = function(context, ...args) {
// 第一个参数为执行上下文,若为null则指向window
var context = context || window;
// this为执行的函数fn
context.fn = this;
// 在context上下文中执行fn函数,并传入参数
var result = context.fn(...args)
delete context.fn
return result
}
3. 实现apply方法
Function.prototype.myApply = function(context, args) {
// 第一个参数为执行上下文,若为null则指向window
var context = context || window;
// this为执行的函数fn
context.fn = this;
// 在context上下文中执行fn函数,并传入参数
var result = context.fn(...args)
delete context.fn
return result
}
4.实现bind方法
Function.prototype.myBind = function(context, ...args1) {
const _this = this
var Func = function(...args2) {
return _this.apply(this instanceOf Func ? this : context, args1.concat(args2))
}
Func.prototype = this.prototype
return Func
}
注: this instanceOf Func ? this : context
为了判断调用的方法是否为构造函数,如果是构造函数,则用new来调用, 此时上下文this不再是绑定的this,而是最后调用该函数的对象
5. 实现防抖方法
- 不管事件触发频率多高,一定在事件触发
n
秒后才执行,如果你在一个事件触发的n
秒内又触发了这个事件,就以新的事件的时间为准,n
秒后才执行,总之,触发完事件n
秒内不再触发事件,n
秒后再执行。 - 关联记忆: 函数防抖就是法师发技能的时候要读条,技能读条没完再按技能就会重新读条。
function debounce(fn, wait) {
var timer = null;
return function(...args) {
var context = this;
clearTimeout(timer);
// 当timer为空时代表第一次执行, 立即进行执行
if (!timer) {
fn.call(context, ...args)
}
timer = setTimeout(() => {
fn.call(context, ...args)
}, wait)
}
}
6.实现节流方法
- 不管事件触发频率多高,只在单位时间内执行一次。
// 方法1,第一次不会立即执行, 最后一次一定触发
function throttle(fn, wait) {
var timer = null;
return function(...args) {
var context = this;
if (timer) return
timer = setTimeout(() => {
fn.call(context, ...args)
timer = null
}, wait)
}
}
// 方法2, 第一次触发会立即执行, 最后一次不会触发
function throttle2 (fn, wait) {
var prevTime;
return function(...args) {
var context = this;
var nowTime = +new Date();
if (!preTime || nowTime - preTime > wait) {
fn.call(context, ...args)
prevTime = nowTime;
}
}
}
// 方法3,结合版,第一次和最后一次触发事件都会执行
function throttle3 (fn, wait) {
var timer = null;
var prevTime = 0;
return (...args) => {
var context = this;
var nowTime = +new Date();
if (nowTime - prevTime > wait) {
clearTimeout(timer);
timer = null;
fn.apply(context, args);
prevTime = nowTime;
} else {
timer = setTimeout(function() {
fn.apply(context, args);
}, wait)
}
}
}