bind源码重写

前言

在了解怎么实现bind之前我们先来了解一下bind的功能,正所谓知己知彼百战不殆。

原生bind的功能

bind的功能主要用来强制绑定函数的this,然后返回一个新的函数

function show (...args) {
	console.log(this, ...args)
}
var obj = {
	x: 20
}
var newShow0 = show.bind()
var newShow1 = show.bind(obj)
var newShow2 = show.bind(obj, 1, 2, 3)
var newShow3 = show.bind(obj, 1, 2, 3)
var newShow4 = show.bind(obj, 1, 2, 3)
newShow1()
newShow1.isShow = true
console.log(newShow1.isTrue, show.isTrue)
newShow2()
newShow3(4)
new newShow4()
new newShow4(4)

实现效果如下:
在这里插入图片描述

总结bind的功能

以上例子我们可以看出bind的功能主要有一下几点:
1. 函数show调用bind方法,需要传递参数target, ...args
2. 调用bind方法后的函数返回一个新的函数,向新的函数对象添加属性不会修改原本函数。
3. 函数newShow在执行的时候,具体的功能还是用的show的功能,只不过showthis改为了target。如果不任何参数,那么showthis指向window
4. 函数newShow在执行的时候可以传递参数,并且传递的参数会拼接到bind的时候传递的参数后面
5. 当以new的构造函数形式执行newShow时,showthis依旧是show而不是bind时传入的obj

实现方法

总结了bind的以上功能之后,我们可以依据功能书写源码。

实现绑定this,传递参数后返回一个新函数
Function.prototype.bind = function (target) {
	// target是bind绑定this的对象
	var self = this; // 保存当前函数的this
	// 从第二个参数开始截取实参列表并转换为数组
	var args = Array.prototype.slice.call(arguments, 1);
	var f = function () {
		// 将执行返回的新方法时传递的参数转换成数组
		var _args = Array.prototype.slice.call(arguments)
		// 根据target的有无确定this,然后将bind的参数和执行时的参数拼接
		// 并返回一个Function函数执行之后的结果
		return self.apply(target || window, args.concat(_args))
	}
	return f
}

  根据以上代码我们就完成了上述功能的1、3、4功能,还剩下两个功能。

用圣杯模式实现新函数和老函数原型的解绑
Function.prototype.bind = function (target) {
	var self = this;
	var args = Array.prototype.slice.call(arguments, 1);
	var f = function () {
		var _args = Array.prototype.slice.call(arguments)
		return self.apply(target || window, args.concat(_args))
	}
	// 圣杯模式:通过new 创建的中间构造函数temp,实现f和temp的继承
	var temp = function () {};
	temp.prototype = self.prototype;
	f.prototype = new temp()
	return f
}

  通过圣杯模式我们可以实现新函数和老函数的关系解绑,当我们给新函数增加属性的时候就不会影响老函数。
  接下来我们就只需要实现最后一个功能:当以new的构造函数形式执行newShow时,showthis依旧是show而不是bind时传入的obj

实现new的形式构造函数

  注意我们此时并没有改变fthis指向,我们只是修改了执行fshowthis
  在我们没有使用自己的bind方法时,在此之前我们想一个问题:当我们通过new的形式时,我们的this是指向原函数show的,那么中间就必然存在一个判断问题,判断什么呢?判断当前的f函数的this是否存在于temp的原型链上。为什么这么说呢?因为当我们使用bind的时候,在没有new的情况下fthis是指向window,而在使用new时,fthis指向show。
  由圣杯模式的继承关系我们可以得出一个结论:f的原型指向的是temp。所以我们只需判断当前新函数f的在没在temp的原型链上来确定apply函数的第一个参数。

Function.prototype.bind = function (target) {
	var self = this;
	var args = Array.prototype.slice.call(arguments, 1);
	var f = function () {
		var _args = Array.prototype.slice.call(arguments)
		// 由于f的祖先是self的原型,所以这里写self也可以
		return self.apply(this instanceof temp ? this : (target || window), args.concat(_args))
	}
	var temp = function () {};
	temp.prototype = self.prototype;
	f.prototype = new temp()
	return f
}

  通过以上例子我们就实现了bind源码内部解构,小伙伴们可以自己去试试

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值