call & apply & bind
// call
Function.prototype.mycall = function (context, ...args) {
// 1. 让fn中的this关键字变为context的值
eval(this.toString().replace('this', context))
// 2. 让fn方法执行
this(...args)
}
方法二 原理就是将函数作为传入的上下文参数(context)的属性执行, 这里为了防止属性冲突使用了 ES6 的 Symbol 类型
Function.prototype.mycall = function (context = window, ...args) {
let caller = Symbol('caller')
context[caller] = this
let res = context[caller](...args)
delete context[caller]
return res
}
// apply
Function.prototype.myapply = function (context, arr = []) {
eval(this.toString().replace('this', context))
this(...arr)
}
// bind
Function.prototype.myBind = function (context, ...args) {
return function () {
this.call(context, ...args)
}
}
call方法的重点知识
首先通过原型链机制找到Function.prototype上的call方法, 并且让call方法执行, call方法中的this是fn1
然后, 在call方法执行的过程中先让fn1中的'this关键字变为fn2', 然后再让fn1方法执行
function fn1 () {console.log(1)}
function fn2 () {console.log(2)}
fn1.call(fn2) // 1
首先通过原型链机制找到Function.prototype上的call方法, 并且让call方法执行(即最后一个call执行), call方法中的this是fn1.call这个方法,然后, 在最后一个call方法执行的过程中先让fn1.call中的'this关键字', 变为fn2, 再让fn1.call执行
fn1.call.call(fn2) // 2
fn1.call.call.call.call.call(fn2) // 2
// call方法下面的情况执行this都是window
fn1.call() // window
fn1.call(null) // window
fn1.call(undefined) // window
bind & call
// bind区别于call和apply
fn1.call(fn2, 1, 2) // 改变fn1的this为fn2, 然后执行fn1(改变后的)
fn1.bind(fn2, 1, 2) // 只是改变了fn1中的this为fn2, 但是不执行fn1, 会返回改变this之后的fn1