一、call和apply的特点
- 可以改变我们当前函数的this指向
- 还会让当前函数执行
var person = { value : 1}function bar() { console.log(this.value)}// 如果不对this进行绑定执行bar() 会返回undefined,this指向windowbar.call(person) // 1复制代码
试想一下当调用call的时候也就类似于
var person = { value: 1, bar: function() { console.log(this.value) }}person.bar() // 1复制代码
这样就把 this 指向到了 person上,但是这样给 person 对象加了一个属性,不太合适,不过不要紧,执行完删除这个属性就可以实现了。
也就是说步骤其实是这样的
- 将函数设为对象的属性
- 执行这个函数
- 删除这个函数
1、call模拟实现
Function.prototype.call = function(context){ context = context ? Object(context) : window;//不传递context默认为window context.fn = this;//this也就是调用call的函数 let args = [...arguments].slice(1); let r = context.fn(...args); delete context.fn; return r;}复制代码
2、apply模拟实现
apply
的方法和 call
方法的实现类似,只不过是如果有参数,以数组形式进行传。
Function.prototype.apply= function(context,args){ context = context ? Object(context) : window;//不传递context默认为window context.fn = this; if(!args){ return context.fn(); } let r = context.fn(...args); delete context.fn; return r;}复制代码
二、bind的特点
- bind方法可以绑定this指向 绑定参数
- bind方法返回一个绑定后的函数(高阶函数)
- 调用绑定后的方法,会让原方法执行
- 如果绑定的函数被new了,当前函数的this就是当前的实例
- new出来的结果,可以找到原有类的原型
1、bind方法模拟实现第一步
用法:
let obj = { name:'gjf'}function fn(){ console.log(this.name)}let bindFn = fn.bind(obj); //返因一个绑定后的方法findFn() //用绑定后的方法,让原方法执行复制代码
实现:
Function.prototype.bind = function(context){ let that = this; return function(){ return that.apply(context); }}复制代码
这样实现了最简单的改变this指向的bind,但是这样还远远不够,因为bind还可以绑定参数;
2、bind方法模拟实现第二步
方法传参可以分两批传,一批可以先在bind方法里面先绑定好,另一批在调用的时候传参,例如以下示例;
用法:
let obj = { name:'gjf'}function fn(name,age){ console.log(this.name+'养了一只'+name+age+'岁了')}let bindFn = fn.bind(obj,'猫'); //返因一个绑定后的方法findFn(8) //用绑定后的方法,让原方法执行复制代码
实现:
Function.prototype.bind = function(context){ let that = this; let bindArgs = Array.prototype.slice.call(argument,1)//['猫'] return function(){ let args = Array.prototype.slice.call(argument); return that.apply(context,bindArgs.concat(args)); }}复制代码
3、bind方法模拟实现第三步
调用bind返回的函数除了可以直接调用,还可以把函数当成一个类来调用;原函数上绑定了属性,new出来的实例上能否访问。
用法:
fn.prototype.flag = '哺乳类'; //原函数上绑定了属性let findFn = fn.bind(obj,'猫');let instance = new findFn(8);//如果绑定的函数被new了,当前函数的this就是当前的实例console.log(instance.flag) //undefined复制代码
实现:
Function.prototype.bind = function(context){ let that = this; let bindArgs = Array.prototype.slice.call(argument,1)//['猫'] function Fn(){} //Object.create的原理 function fBound(){ let args = Array.prototype.slice.call(argument); return that.apply(this instanceof fBound ? this:context,bindArgs.concat(args)); } Fn.prototype = this.prototype; fBound.prototype = new Fn(); return fBound;}复制代码
这里,我们js里的三种改变this指向的方法就实现啦。。。。。