一. 首先bind 函数的三个特点:
1. 改变this指向
2. 第一个参数是 this的值后面的参数是 函数接收的参数的值
3. 返回值不变
二. 实现第一种:简易版实现
简易版实现 bind 函数 ,尽量不使用,但是可以借助里面的思想
<script>
/**
* bind 函数的三个特点:
* 1. 改变this指向
* 2. 第一个参数是 this的值,后面的参数是 函数接收的参数的值
* 3. 返回值不变
*/
function test(a, b, c) {
console.log(a, b, c);
console.log('this', this);
return '我是alright';
}
Function.prototype.myBind = function () {
const self = this;
// 将类数组转化为数组
const args = Array.prototype.slice.call(arguments);
const thisValue = args.shift();
return function () {
return self.apply(thisValue, args);
}
}
const boundTest = test.myBind({
name: '哈默'
}, 7, 77, 777);
const boundRes = boundTest();
console.log('boundRes', boundRes);
</script>
三. 终极版实现
<script>
// new 绑定的规则:
// 如果使用了 new 来创建函数,即发生了构造函数,那么实例会绑定到
// 函数调用的 this
function person(a, b, c) {
console.log(this.name);
console.log(a, b, c);
}
person.prototype.collection = '收藏';
var egg = {
name: '但老师'
};
Function.prototype.newBind = function (obj) {
// 根据MDN的官方建议需要加上这一条,检测一下数据类型
if (typeof this !== 'function') {
throw new TypeError('error');
}
var that = this,
arr = Array.prototype.slice.call(arguments, 1),
o = function () {},
newf = function () {
var arr2 = Array.prototype.slice.call(arguments),
arrSum = arr.concat(arr2);
// 判断this是否是 通过 new 实现的构造函数的实例
if (this instanceof o) {
// console.log(this); // 这里的 this 是 newf
that.apply(this, arrSum)
} else {
// console.log(this); // 这里的 this 是 window
that.apply(obj, arrSum);
}
};
// console.log(this); // newf 外面的 this 是 person,谁调用的就是谁
o.prototype = that.prototype;
newf.prototype = new o;
return newf;
};
var bibi = person.newBind(egg, '点赞', '投币');
var b = new bibi('充电');
// var b = bibi();
// console.log(b.collection);
/**
* 如果最后是 var b = bibi('充电'); ,那么newf里面的 this 就是 egg
* 但如果最后是 var b = new bibi('充电'); ,那么 newf 里面的this 就是 函数 o的实例b
*
* 所以最终就是 要把 原先的this(person) ---》 改为 传入的第一个参数 egg / 或者是 o 的实例对象
*
*/
</script>