这是我参与11月更文挑战的第6天,活动详情查看:2021最后一次更文挑战
本篇文章是一些手写题目相关的学习笔记,持续更新。
call
主要思想:将函数作为当前绑定对象的属性方法进行调用,之后再销毁。
Function.prototype.call = function(ctx) {
ctx.fn = this;
ctx.fn();
delete ctx.fn;
}
需要额外考虑的点:
- this 参数可以传 null,当为 null 的时候,视为指向 window
- this 参数需要是对象
- 函数有返回值
- 除了 this,还可以有其它参数
Function.prototype.call = function(ctx) {
var ctx = (ctx == null ? window : Object(ctx));
ctx.fn = this;
var args = [];
for (let i = 1; i < arguments.length; i++) {
args.push('arguments[' + i + ']');
}
var result = eval('ctx.fn(' + args +')');
// 或者用 es6 相关语法实现
// var args = Array.from(arguments).slice(1);
// var result = ctx.fn(...args);
delete ctx.fn;
return result;
}
apply
apply 的实现与 call 类似,只是参数传递方式不同。
Function.prototype.apply = function (ctx, arr) {
var ctx = ctx == null ? window : Object(ctx);
ctx.fn = this;
var result;
if (!arr) {
result = ctx.fn();
} else {
var args = [];
for (var i = 0, len = arr.length; i < len; i++) {
args.push('arr[' + i + ']');
}
result = eval('ctx.fn(' + args + ')')
// 或者 es6 语法实现
// result = ctx.fn(...arr);
}
delete ctx.fn
return result;
}
bind
主要思想:以闭包的方式实现,将 this 存起来。
Function.prototype.bind = function (ctx) {
var self = this;
return function () {
return self.apply(ctx);
}
}
bind 的特点:
- 返回一个函数;
- 可以传入参数;
- 被 new 调用的时候,指定的 this 会失效,传入参数依然生效。
Function.prototype.bind = function(ctx) {
if (typeof this !== "function") {
throw new Error("只有 function 才能调用 bind");
}
var self = this;
var args = [].slice.call(arguments, 1); // 把 绑定对象 和 参数 存在闭包变量中
var fBound = function() {
var bindArgs = [].slice.call(arguments);
// 需要判断是否被 new 调用
return self.apply(this instanceof fBound ? this : ctx, args.concat(bindArgs));
};
var fNOP = function() {};
fNOP.prototype = this.prototype; // 避免修改 fBound.prototype 的时候修改了 this.prototype
fBound.prototype = new fNOP();
return fBound;
}
new 实现
由于 new 是操作符,这里我们通过函数的形式来实现。
new 的特点:
- 创建一个对象,并经过构造函数处理;
- 如果返回值是一个对象,则返回该对象,否则返回所创建的对象。
function objectFactory() {
var obj = new Object(),
Constructor = [].shift.call(arguments);
obj.__proto__ = Constructor.prototype;
var ret = Constructor.apply(obj, arguments);
// 判断构造函数返回值是否是对象
return typeof ret === 'object' ? ret : obj;
};
debounce(防抖)
防抖目的:让函数在多次调用时,停止调用一段时候后才真正执行。降低函数指定的频次。
简单实现:利用闭包和定时器实现。
function debounce(func, wait) {
var timeout;
return function () {
clearTimeout(timeout)
timeout = setTimeout(func, wait);
}
}
需要考虑 this 指向和参数问题。
function debounce(func, wait) {
var timeout;
return function () {
var context = this;
var args = arguments;
clearTimeout(timeout)
timeout = setTimeout(function(){
func.apply(context, args)
}, wait);
}
}