原生JS实现call apply bind

call apply  bind三者均可以改变this指向

call 和 apply 都可以动态改变 this 的指向。作用都是相同的,只是传参的方式不同。

除了第一个参数外,call 可以接收一个参数列表,apply 只接受一个参数数组。

bind将函数绑定到某个对象,bind()会创建一个函数,函数体内的this对象的值会被绑定到传入bind()中的第一个参数的值


下面涉及很多对伪数组arguments的操作,不能直接使用数组的方法

下面三种方法对取第二个之后的参数是等效的


call

整体思路:将函数或者方法添加在对象上,那么该对象就可以调用该函数了,但是要调用结束后删除掉该函数。

  1. 获得对象,当没有传递参数时候,为window(特殊情况处理)
  2. 给对象添加方法,方法赋值为该函数(this获取)
  3. 获得第二个之后的参数作为执行的参数
  4. 执行该对象的方法(传参)获得结果
  5. 删除对象的方法
  6. 返回结果
Function.prototype.mycall=function(context){
    var context=context||window;
    context.fn=this;//当前调用call的函数作为对象的方法
    var args=[...arguments].slice(1);
    var res=context.fn(...args);
    delete context.fn;
    return res;
}

验证:

var a=2;
var obj={a:1}
function say(b,c) {
	console.log(this.a)
	console.log(b+c)
}
say(4,3);//2,7
say.mycall(obj,1,1)//1 2

apply

思路:与call类似,对于传入参数进行判断,如果存在第二个参数(数组),展开数组传入函数执行

  1. 获得对象,当没有传递参数时候,为window(特殊情况处理)
  2. 给对象添加方法,方法赋值为该函数(this获取)
  3. 判断是否存在第二个参数(数组)存在,执行该对象的方法(传参)获得结果 不存在,执行该对象的方法(不传参)获得结果
  4. 删除对象的方法
  5. 返回结果
Function.prototype.myapply=function(context){
    var context=context||window;
    context.fn=this;
    var res;
    if(arguments[1]){//存在第二个参数
        res=context.fn(...arguments[1]);
    }else{不存在第二个参数
        res=context.fn();
    }
    delete context.fn;
    return res;
}

验证

var a=2;
var obj={a:1}
function say(b,c) {
	console.log(this.a)
	console.log(b+c)
}
say(4,3);//2,7
say.myapply(obj,[1,1])//1 2

bind

返回一个函数,使用apply方法

Function.prototype.mybind=function (context) {
	if (typeof this!=='function') {//调用bind的一定要是函数,返回绑定this后的函数,否则报错
		throw new Error(this+'is not a function')
	}
	var self=this;//保存调用bind的函数
	// var context=[].shift.call(arguments);
	// var context=Array.prototype.shift.call(arguments);
	//如果没有传入参数,通过arguments获得绑定的this上下文
	var args=[].slice.call(arguments,1);//获取绑定this时候传入的参数,与调用时的参数区分开
	// var args=Array.prototype.slice.call(arguments,1);//与上面一行等效
	var fbound=function () {
		var bindArgs=[...arguments];
		// 如果是构造函数,this为构造函数的实例,上下文仍为新创建的对象,不修改为context
		self.apply(this instanceof self ? this:context, args.concat(bindArgs));
	}
	//返回的函数的原型链要和调用bind的函数原型链相同
	fbound.prototype=Object.create(self.prototype);
	return fbound;
}

验证

function bar(){
	var sum=0;
	var arr=[...arguments];
	for (var i = 0; i < arr.length; i++) {
		sum+=arr[i];
	}
	console.log(this);
	console.log(sum)
}
var foob=bar.mybind({a:1},3);
bar(1,2);//window 3
foob(4)//{a:1} 7

 

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值