原生js实现简单版apply、call以及bind方法

我们先来实现apply,上代码:

<script type="text/javascript">
	function Person(name, age) {
		this.name = name,
		this.age = age
	}
	Person.prototype.sayThis = function(x, y) {
		console.log('------' + x + y);
		console.log(this);
		console.log('------' + x + y);
	}
	let per1 = new Person('xiaoxiao', 15);
	
	function Anamil(name) {
		this.name = name
	}
	let ana1 = new Anamil('dog');

//因为方法本身是一个对象来的,要让所有的方法都能调用到myApply方法,最好的做法就是添加
//到Function构造函数的原型对象中

	Function.prototype.myApply = function(obj, arr) {
		obj = obj === null ? window : obj === undefined ? window : obj;
//这里的this是谁?答案是,谁调用就是谁,有点绕口,但是你想明白这里就成功了
		obj.fun = this;
		let res;
		if(arr){
			res = obj.fun(...arr);
		}else{
			res = obj.fun();
		}
		delete obj.fun;
		return res;
	}

	per1.sayThis.myApply()
	per1.sayThis.myApply(null, [6,6])
	per1.sayThis.myApply(ana1, [6,6])
</script>

这是运行结果:

 呃呃,这就是为啥说是简单版的了,因为我们是在最后才删除fun,如果在方法中有输出本身,就会尴尬地发现多了个fun方法。

        apply方法只有两个参数,第一个参数是this所要指向的对象,第二个是参数数组,

因为第一个参数可以是null,或者没有传,所以简单判断一下,没传或者位null就赋值为window对象。

        然后我们必须要明确一点,apply方法的作用,就是让另外一个对象,调用这个对象的方法,然后就做到了所谓的改变this指向,想明白了这个,一切都解决了。

我们在那个要调用方法的对象中新建一个属性,并把方法赋值给它,这样子就在那个对象中有了想要调用的方法,然后调用,用完就删掉。

实现call方法:

<script type="text/javascript">
	function Person(name, age) {
		this.name = name,
		this.age = age
	}
	Person.prototype.sayThis = function(x, y) {
		console.log('------' + x + y);
		console.log(this);
		console.log('------' + x + y);
	}
	let per1 = new Person('xiaoxiao', 15);
	
	function Anamil(name) {
		this.name = name
	}
	let ana1 = new Anamil('dog');

	Function.prototype.mycall = function(obj, ...arr) {
		obj = obj === null ? window : obj === undefined ? window : obj;
		obj.fun = this;
		let res;
		if(arr){
			res = obj.fun(...arr);
		}else{
			res = obj.fun();
		}
		delete obj.fun;
		return res;
	}


	per1.sayThis.mycall()
	per1.sayThis.mycall(null, [6,6])
	per1.sayThis.mycall(ana1, [6,6])
</script>

运行结果:

大体思路跟apply方法的差不多,如果你搞明白了apply的实现,那么这个call的实现就只剩下一个问题,就是怎么获取到参数,我这里是用扩展运算符,然后截取除了第一个参数外的所有参数存储到数组中。

实现bind方法:

        它返回的是一个函数;

        我们在使用bind方法的时候可以传进去部分需要参数,再调用bind方法返回的函数时再把剩下的参数传进去;

        bind返回的函数可以当作构造函数来用,也就是使用new来创建返回的函数的实例,也就是说this指向不一样(通过构造函数,new出来的实例,这个实例里面的this就是实例本身),也就是说在bind这里,如果我们直接调用返回的函数,那么this就是原本我们希望指向的对象;如果通过new来调用,那么this指向就是本身。

想明白了这个,就可以动手写代码了:

oh,不,写代码之前先来看看提供给我们的bind方法的效果吧!

<script type="text/javascript">
	function Person(name, age) {
		this.name = name,
		this.age = age
	}
	Person.prototype.sayThis = function(x, y) {
		console.log('------' + x + y);
		console.log(this);
		console.log('------' + x + y);
	}
	let per1 = new Person('xiaoxiao', 15);
	
	function Anamil(name) {
		this.name = name
	}
	let ana1 = new Anamil('dog');

	per1.sayThis.bind(ana1, 6)(6)
	console.log('-----aaaaaaaaaaaaaaaaaa---')
	let a = per1.sayThis.bind(ana1, 6);
        //这里用到了bind分开传参的功能
	let b = new a(9);
        //这里因为a里面的代码是打印的,就打印出来了。同时因为new a(),相当于构造了一个对象b,也就是说现在a里面的this是b了,也就是一个空对象,所以打印出来的this就是一个空对象。
</script>

这是运行效果:

 接下来来原生实现代码:

<script type="text/javascript">
	function Person(name, age) {
		this.name = name,
		this.age = age
	}
	Person.prototype.sayThis = function(x, y) {
		console.log('------' + x + y);
		console.log(this);
		console.log('------' + x + y);
	}
	let per1 = new Person('xiaoxiao', 15);
	
	function Anamil(name) {
		this.name = name
	}
	let ana1 = new Anamil('dog');

	Function.prototype.myBind = function(obj, ...arr) {
		obj = obj === null ? window : obj === undefined ? window : obj;
		let _this = this;
		let fun = function(...data) {
            //这里是判断调用方法的this是不是fun,new出来的实例对象。
                //因为apply方法已经在上面实现过了,所以直接用原生的
			if(this instanceof fun){
				_this.apply(this, [...arr, ...data]);
			}else{
				_this.apply(obj, [...arr, ...data]);
			}
		}
		fun.prototype = _this.prototype;
		return fun;
	}

	per1.sayThis.myBind(ana1, 6)(6)
	console.log('-----aaaaaaaaaaaaaaaaaa---')
	let a = per1.sayThis.myBind(ana1, 6);
	let b = new a(9);
</script>

这样子就实现了一个简单版的bind方法了,这是运行结果:

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

酒客->老张

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值