最近要开始前端春招了,所以在这个文章中记下一些常见的手写代码题,巩固一下,顺带练一下手。 废话不多说,直接开始
1.手写call方法
// call函数
Function.prototype.myCall = function(context) {
// 判断调用对象
if (typeof this !== 'function') {
console.error('type error')
}
// 获取除了第一项以外的所有参数
let args = [...arguments].slice(1),
result = null
// 判断context是否传入,如果未传入则设置为 window,
// 这与原生call方法一致,若不传入this值的时候,默认this指向全局对象window
context = context || window
// 将调用函数设置为对象的方法
context.fn = this
// 调用函数
result = context.fn(...args)
// 将属性删除
delete context.fn
return result
}
2.手写apply方法
// 手写apply函数 (思路和call差不多)
Function.prototype.myApply = function (context) {
if (typeof this !== 'function') {
console.error('type error')
}
context = context || window
let result = null
context.fn = this
// 如果存在传入参数数组,就代入fn方法中,如果没有,就直接执行fn函数
if (arguments[1]) {
result = context.fn(...arguments[1])
} else {
result = context.fn()
}
delete context.fn
return result
}
- 手写bind方法
// 手写bind方法(详细)
Function.prototype.myBind = function (context) {
// 判断调用对象类型是否为函数
if (typeof this !== 'function') {
console.error('type error')
}
// 获取参数,创建fn保存调用myBind原始函数
let args = [...arguments].splice(1),
fn = this
// 创建绑定函数
const bound = function () {
return fn.apply(
// 判断 bound 函数是否是作为构造函数被调用(即是否使用 new 关键字)
// 如果是作为构造函数调用,this 指向新创建的对象,那么就使用这个新对象作为 this 值;
// 如果不是作为构造函数调用,就使用传入的 context 作为 this 值。
this instanceof bound ? this : context,
args.concat(...arguments)
)
}
// 处理原型链,这里的目的是让 bound 函数作为构造函数调用时,新创建的对象能够继承原始函数 fn 的原型。
let f = function () { }
f.prototype = fn.prototype
bound.prototype = new f()
// 返回绑定函数
return bound
}
// 手写bind函数(袁老师版,比较推荐)
Function.prototype.myBind = function (context, ...args) {
// 首先绑定调用 myBind 方法的对象
const fn = this
// bind方法返回一个函数,传递参数
return function A(...agrs2) {
// 判断是否是作为构造函数被创造(即new)
if (Object.getPrototypeOf(this) === A.prototype) {
// 如果是,返回一个new 构造函数
return new fn([...args, ...agrs2])
} else {
// 如果不是,直接返回
return fn.apply(context, [...args, ...agrs2])
}
}
}
// 手写bind函数(简单)
Function.prototyep.myBind = function(context, ...args) {
// 绑定调用的对象到方法fn上
let fn = this
// 返回一个新函数,接受任意数量的参数args2
return function A(...args2) {
// 使用apply方法调用原始函数
return fn.apply(context, [...args, ...args2])
}
}
这个简易版手写的 myBind 函数虽然实现了 bind 方法的基本功能,但与原生的 bind 方法相比,存在一些局限性:
- 作为构造函数调用的处理:原生
bind方法返回的函数如果作为构造函数使用(即使用new关键字调用),this会指向新创建的对象,而不是传入的context。但这个myBind2函数没有处理这种情况,无论是否使用new关键字,this始终绑定到传入的context。 - 原型链继承:原生
bind方法返回的函数在作为构造函数调用时,新创建的对象会继承原函数的原型。而myBind2函数没有实现这一特性。