call的实现
function getType(obj) {
return Object.prototype.toString.call(obj).slice(8, -1)
}
// call
Function.prototype._call = function (context, ...args) {
let _self = this
context = (getType(context) === 'Null' || getType(context) === 'Undefined') ? window : Object(context)
context.fn = _self
let result = context.fn(...args)
delete context.fn
return result
}
apply的实现
// apply
Function.prototype._apply = function (context = window, ...args) {
let _self = this
context = (getType(context) === 'Null' || getType(context) === 'Undefined') ? window : Object(context)
context.fn = _self
args = !args ? Array.from(args) : []
let result = context.fn(args)
delete context.fn
return result
}
apply接受的第二参数不要求一定是数组,类数组对象也可以,所以使用Array.from转化一下
bind的实现
function A(sex, age) {
this.sex = sex
this.age = age
return this
}
let obj = {}
let B = A.bind(obj)
console.log(B(1, 20)) // {sex: 1, age: 20}
根据上面可以实现:
function getType(obj) {
return Object.prototype.toString.call(obj).slice(8, -1)
}
Function.prototype._bind = function (obj, ...args) {
let _self = this
obj = (getType(obj) === 'Null' || getType(obj) === 'Undefined') ? window : Object(obj)
return function (...argv) {
return _self.apply(obj, [...args, ...argv])
}
}
还要考虑到bind返回的函数作为构造函数被调用:
function A(sex, age) {
this.sex = sex
this.age = age
return this
}
let obj = {}
let B = A.bind(obj)
B(1, 20) // {sex: 1, age: 20}
let newObj = new B(0, 18)
console.log(obj) // {sex: 1, age: 20}
console.log(newObj) // {sex: 0, age: 18}
当bind返回的函数作为构造函数被调用时,this会指向通过该构造函数实例化后得到的对象,由此可以实现:
Function.prototype._bind = function (obj, ...args) {
let _self = this
obj = (getType(obj) === 'Null' || getType(obj) === 'Undefined') ? window : Object(obj)
function bindFn(...argv) {
return _self.apply(new.target ? this : obj, [...args, ...argv])
}
// 维护原型,使用一个空函数做中转,防止修改构造函数的原型时同时修改原函数的原型
function FNnop() { }
FNnop.prototype = _self.prototype
bindFn.prototype = new FNnop()
return bindFn
}
obj = (getType(obj) === 'Null' || getType(obj) === 'Undefined') ? window : Object(obj)
这段代码是因为call、apply和bind传入的第一个参数如果是null或者undefined时,非严格模式下函数中的this指向windows,其余的类型如数字、字符串等会被转为基础封装类型(Number { }、String{ })