call
Function.prototype.myCall = function (context, ...args) {
const fn = this // 通过this获取调用call的函数
if (typeof fn !== 'function') {
throw new Error('caller is required function')
}
context = context === null || context === void 0 ? window : Object(context)
const symbol = Symbol('fn')
context[symbol] = fn // 防止与context属性名冲突
const result = context[symbol](...args)
delete context[symbol]
return result
}
foo.myCall(2)
foo.myCall('2')
foo.myCall(null)
foo.myCall(obj)
call
的第一个参数为上下文this
- 第一个参数为
null/undefined
时this
指向window
- 第一个参数也可以是基本类型,要转为对象类型;使用Object()
- 可以有返回值
apply
Function.prototype.myApply = function (context, ...args) {
const fn = this // 通过this获取调用call的函数
if (typeof fn !== 'function') {
throw new Error('caller is required function')
}
context = context === null || context === void 0 ? window : Object(context)
const symbol = Symbol('fn')
context[symbol] = fn
const result = context[symbol](args) // apply的参数是数组
delete context[symbol]
return result
}
apply
的第二个参数是数组
bind
基础版
Function.prototype.myBind = function (context, ...args) {
const fn = this
return function (...innerArgs) {
const result = fn.apply(context, [...args, ...innerArgs])
return result
}
}
bind
返回值是函数- 返回的函数可以继续传参
- 返回的函数可以作为构造函数使用,绑定的
this
会失效
添加可以作为构造函数
Function.prototype.myBind2 = function (context, ...args) {
const fn = this
function fBound(...innerArgs) {
context === this instanceof fBound ? this : context
const result = fn.apply(context, [...args, ...innerArgs])
return result
}
fBound.prototype = fn.prototype
return fBound
}
使用
const b = bar.myBind2(2, 1)
b.prototype.name = 'tianzhen'
const _b = new b(2)
console.log(_b, _b.name)
存在的问题
const b2 = bar.myBind2(2, 1)
const _b2 = new b(2)
console.log(_b2.name) // 也能找到name: tianzhen
b2.prototype.name = 'lisi'
console.log('b1.name', _b.name) // _b.name也会修改为lisi
fBound.prototype = fn.prototype
; 修改fBound.prototype也会修改构造函数的Prototype
bind(优化版)
Function.prototype.myBind2 = function (context, ...args) {
const fn = this
function F() {}
F.prototype = fn.prototype
function fBound(...innerArgs) {
context === this instanceof fBound ? this : context
const result = fn.apply(context, [...args, ...innerArgs])
return result
}
fBound.prototype = new F()
return fBound
}
这里利用了原型式继承(道格拉斯提出)