本文已同步:个人博客地址
前言
最近复习ES6时经常遇到这三个函数,发现用途很大,在尾递归,克隆方面都能用到,所以查询网上的资料后,准备好好复习复习
一、bind,call,apply的区别?
call 和 apply 都是为了解决改变 this 的指向。作⽤都是相同的,只是传参的⽅式 不同。 除了第⼀个参数外, call 可以接收⼀个参数列表, apply 只接受⼀个参数数组。bind 和其他两个⽅法作⽤也是⼀致的,只是该⽅法会返回⼀个函数。并且我 们可以通过 bind 实现柯⾥化
二、手写实现这三个函数
1.手写call
代码是背了别人的 再自己写的,这里主要是讲解保准你能动
代码如下(示例):
Function.prototype.myCall = function (context) {
debugger
var context = context || window //context赋值为传入来的对象
// console.log(context);
// console.log(this); //一开始的this是指向要调用的那个函数的
context.fn = this // 这里是将这个函数归纳到context对象里面
// console.log(context.fn);
// console.log(arguments);
var args = [...arguments].slice(1) //去后面列表的参数
// console.log(args);
var result = context.fn(...args) //调用这个函数
// console.log(result);
delete context.fn
return result
}
let a = {
value: 1
}
function getValue(name, age) {
console.log(name)
console.log(age)
console.log(this.value)
}
getValue.myCall(a, 'zhangshan', '12')
为了方便,我直接把执行过程的一些东西打印了出来
上面 是这个函数的执行过程,一目了然了
- 一开始传入进来的context 就是赋值为 a 这个对象了
- 因为是这个getValue.myCall(a, ‘zhangshan’, ‘12’)函数调用的,所以call里面的this是指向这个函数的
- 后面的将this赋值给context.fn 实际上context.fn 就是将这个函数了
- 所以最终context对象就变成了{value:1,fn:f}这样
- 最终再调用一下这个函数
建议你看懂了自己写一下 apply
2.手写apply
下面是我自己写的,我自己试了一下是可以的,如有不对还请指正
代码如下(示例):
Function.prototype.myApply = function(obj){
var obj = obj || window
// console.log(this);
obj.fn = this
// console.log(obj);
// console.log(arguments);
var args = [...arguments].slice(1)
// console.log(...args.flat());
var res = obj.fn(...args.flat())
delete obj.fn
return res
}
let a = {
value: 1
}
function getValue(name, age) {
console.log(name)
console.log(age)
console.log(this.value)
}
getValue.myApply(a, ['zhangshan', '12'])
3.手写bind
区别不大,但是有一点是需要注意的:return function fn 返回了个函数是闭包
Function.prototype.myBind = function(obj){
if(typeof this !== 'function'){
throw new TypeError('Error')
}
var _this = this
console.log(_this);
var args = [...arguments].slice(1)
console.log(args);
return function fn(){
// 如果this 是fn的实例
if(this instanceof fn){
return new _this(...args,...arguments)
}
return _this.apply(obj,args.concat(...arguments))
}
}
this.x = 9; // 在浏览器中,this 指向全局的 "window" 对象
var module = {
x: 81,
getX: function() { return this.x; }
};
module.getX(); // 81
var retrieveX = module.getX;
console.log(retrieveX());
// 返回 9 - 因为函数是在全局作用域中调用的
// 创建一个新函数,把 'this' 绑定到 module 对象
// 新手可能会将全局变量 x 与 module 的属性 x 混淆
var boundGetX = retrieveX.myBind(mduole);
// 81
console.log(boundGetX());
总结
反复看,反复写,才能记住的