call、apply、bind的实现
call/apply
call和apply的区别
调用 call 和 apply改变了函数的 this 上下文后 马上 执行该函数,若指向 undefined 或者 null ,会将 this 指向 window
call:可以接收多个参数,第一个参数为函数上下文(this),后边参数为函数本身的参数apply:只能接收两个参数,第一个参数为函数上下文(this),第二个参数为函数本身的参数,但是以数组形式传入
call
var name = '了不起'
let obj = {
name: '贾正经'
}
function fun() {
console.log(this)
console.log(this.name)
}
Function.prototype._call = function (ctx, ...args) {
//判断ctx,如果为null或undefined,则为window,否则用Object()转为对象
const context = (ctx === null || ctx === undefined) ? window : Object(ctx)
//使用Symbol为context添加一个独一无二属性,将this(调用_call的函数)赋值给这个属性
const key = Symbol()
context[key] = this
//立即执行一次
context[key](...args)
//删除方法
delete context[key]
}
测试一下
fun._call(obj)//{ name: '贾正经', [Symbol()]: [Function: fun] } 贾正经
fun._call(null)//window 了不起
fun._call(undefined)//window 了不起
apply
apply和call的的唯一区别就是传参不一样,所以改变对参数的处理,其他一致就可以了
var age = 18
let obj = {
age: 20
}
function fun(b, c) {
console.log(this.age)
console.log(this.age + b + c);
}
Function.prototype._apply = function (ctx, arr = []) {
//判断ctx,如果为null或undefined,则为window,否则用Object()转为对象
const context = (ctx === null || ctx === undefined) ? window : Object(ctx)
//使用Symbol为context添加一个独一无二属性,将this(调用_call的函数)赋值给这个属性
const key = Symbol()
context[key] = this
//立即执行一次
context[key](...arr)
//删除方法
delete context[key]
}
测试一下
fun._apply(obj, [1, 2 ]) // 20 23
fun._apply(null, [1, 2 ])//18 22
bind
bind 是返回改变了上下文后的函数, 不执行该函数, bind可以接收多个参数,第一个参数为函数上下文(this),后边参数为函数本身的参数,bind返回一个未执行的函数,可以在执行时再次传入参数
var name = '了不起'
let obj = {
name: '贾正经'
}
function fun(...args) {
console.log(this)
console.log(this.name)
console.log(...args);
}
Function.prototype._bind = function (ctx, ...args) {
//先保存一下this
let self = this
//bind不会立即执行,创建一个函数
const fn = (...rest) => {
//使用call改变this指向
return self.call(ctx, ...args, ...rest)
}
//若没有prototype(如箭头函数),则需要给fn的prototype赋值为源函数的prototype
if (self.prototype) {
fn.prototype = Object.create(self.prototype)
}
//返回函数
return fn
}
测试一下
fun._bind(obj,1,2)()//{"name": "贾正经"} 贾正经 1 2
fun._bind(obj,1,2)(3,4)//{"name": "贾正经"} 贾正经 1 2 3 4
fun._bind(null,1,2)(3,4)//window 了不起 1 2 3 4
第一次写文章欢迎指点吐槽or点赞!