call
call参数一:需要把调用者的this指向的对象,后续参数:a, b, c 调用者的参数;通过call 把fn的this指向了obj,并且执行了fn函数。
var obj = {
name: '张三'
}
function fn(a, b, c) {
console.log(this.name, a, b, c)
}
fn.call(obj, 1, 2, 3)
如果我们想自己让他指向obj,我们可以让函数fn以属性的方式在obj出现, 然后调用执行就行,执行完后删除掉fn
var obj2 = {
name: '李四',
fn2: fn2
}
function fn2(arg) {
console.log(this.name, ...arg)
}
obj2.fn2([1, 2, 3])
delete obj2.fn2
console.log(obj2)
/**
* 通过这个思路 我们可以自己实现call
*/
Function.prototype.myCall = function(ctx) {
// 调用者必须是函数
if(typeof this !== 'function') {
throw new Error('调用者必须是函数')
}
// 找到需要执行的函数的参数
let arg = [...arguments].slice(1),
_this = ctx || window, // ctx 第一个参数 -> 对象
result = null; // 执行的函数可能会有返回值 存起来
// 给对象新增一个fn属性
_this.fn = this
// 执行fn函数传入参数
result = _this.fn(...arg)
// 删除掉给对象新增的fn属性
delete _this.fn
return result
}
function fn3(a, b) {
console.log(this.name, a, b)
return 'call'
}
console.log(fn3.myCall(obj2, 1, 2))
apply
apply的第二个参数以数组形式传给要执行的函数的
Function.prototype.myApply = function(ctx) {
if(typeof this !== 'function') {
throw new Error('调用者必须是函数')
}
let arg = [...arguments].slice(1),
_this = ctx || window,
result = null;
_this.fn = this
result = _this.fn(...arg)
delete _this.fn
return result
}
function fn4(arg) {
console.log(this.name, ...arg)
return 'call'
}
console.log(fn4.myApply(obj2, [1, 2]))
bind
不会立即执行该函数,改变调用者的this指向 并返回一个函数,传参方式和apply一样。
Function.prototype.myBind = function(ctx) {
if(typeof this !== 'function') {
throw new Error('调用者必须是函数')
}
let arg = [...arguments].slice(1),
_this = ctx || window,
result = null,
fn = this;
return function Fn() {
const result = fn.apply(_this, arg)
return result
}
}
function fn5(a, b) {
console.log(this.name, a, b)
return 'call'
}
let newFn = fn5.myBind(obj2, 11, 22)
console.log(newFn(), 111)