本文主要用来理解底层函数的原理, 并没有苛求一定用最原始的语法解决问题。 好的 ,我们开始
1.call函数
首先,我们要知道 call 的用法 ,可以这里;
call 主要做了四件事 :
1).创建一个变量指向call函数的第一个参数,如果为null 或undefinedi则指向window, 如果是其他基本变量,则调用对应的构造函数返回对应的对象;如下代码简化。
2).把调用call的函数置为对象的方法。
3).调用函数 传入对应的参数。
4).obj 指向的是传入的对象,避免污染,删除添加fn方法.
Function.prototype.myCall=function(){
let obj=arguments[0]||window; // 获取想要指向的对象 一个参数为null 时候 指向window;
obj.fn = this;
const params= [...arguments].slice(1); // 获取通过call传入的参数 ,如果是apply 可以改成 params = arguments[1];
obj.fn(...params);
delete obj.fn ; // 删除添加的 方法。
}
var a= {b:2};
function test(context){
console.log(this.b)
console.log('context:',context);
}
test.myCall(a,222); // 2 context:222
2.apply 函数的原理类似,传参只接收两个有效参数,且第二个参数形式是数组 。
3.bind 函数为目标函数绑定好this ,并没有立即执行,而是返回一个 绑定好的函数, 供在其他地方调用。先看下bind函数的特点
1) bind函数支持传参,并且返回的新函数也同样支持传参,两者是拼接到一起 传给目标函数。
2) 绑定this 的过程中, 返回的函数如果 作为构造函数,new 操作符的优先级更高,即new 出的实例对象绑定this , 但是传入得参数还是有效的 。 ok 下面实现内容
Function.prototype.myBind = function (context){
if(typeof this!=='function'){
throw new Error(`Function.prototype.bind - what is trying to be bound is not callable`); // 如果调用bind 的 是非函数 throw error
}
const self = this;
const args= [...arguments].slice(1); // binding 时传入的参数。
const bindedFun= function (...rest){
const params = [...args,...rest ]; // 合并参数
self.call(this instanceof bindedFun ?this:context,...params);
}
return bindedFun;
}
function test (name,age){
console.log(this.value);
console.log('name',name);
console.log('age',age);
}
var obj={value:6};
var test1 = test.myBind(obj,'xuezh');
test1(29);
self.call(this instanceof bindedFun ?this:context,...params); // 这一步比较重要 判断 this 是否在bindedFun 原型链上, 返回的函数作为构造函数,在new 后生成的实例对象的 在构造函数的原型链上。具体可以查看这篇文章 new 都做了什么,
继承的知识
注意:
1、bind操作只有第一次绑定有效果,之后再次进行绑定,不会有效果
2、new操作的绑定操作优先度要高于bind,事实上,也会高于apply和call
一旦函数通过bind绑定了有效的this对象,那么在函数执行过程中this会指向该对象,即使使用call、apply也不能改变this的指向;