手写call,apply,bind

简介: 手写call,apply,bind

call() 方法调用一个函数, 其具有一个指定的this值和分别地提供的参数(参数列表)。


apply() 方法调用一个具有给定this值的函数,以及作为一个数组(或类数组对象)提供的参数。

bind() 方法创建一个新的函数,在调用时设置this关键字为提供的值。并在调用新函数时,将给定参数列表作为原函数的参数序列的前若干项。


以上内容源自MDN


下面我用自己的理解说一下call,apply及bind都做了啥


foo.call(obj,argument1,augument2,argument3)
复制代码


以上代码的作用:


执行函数foo,并将其this指定为obj,后面的参数为调用foo时传入的参数


foo.apply(obj,[argument1,augument2,argument3])
复制代码


以上代码的作用:


执行函数foo,并将其this指定为obj并将数组


[


argument1,augument2,argument3]中的每一项作为调用foo时传入的参数


let bar = foo.bind(obj,argument1,augument2,argument3);
bar();
复制代码


以上代码的作用:


返回一个绑定了this为obj,参数为argument1,augument2,argument3的函数,所以如果想要执行foo,需要把返回结果再执行一下


了解了方法的功能和原理,接下来让我们分别实现它们


call的实现:


首先实现一个简单的call方法


Function.prototype.call2 = function(obj){
  obj.fn = this;
  if(arguments.length>1){
    obj.fn(...([...arguments].slice(1)));
  }else{
    obj.fn();
  }
  delete obj.fn;
}
复制代码


以上代码仅仅实现了this的绑定以及函数调用传参,但是忽略了函数的返回值,而且默认把当前函数赋给了obj.fn,而没有考虑obj.fn存在的情况,改进后的代码如下:


Function.prototype.call2 = function(obj){
  let _fn = "fn",result;
  while (obj.hasOwnProperty(_fn)) {
    _fn = "fn" + Math.random(); // 循环判断并重新赋值
  }
  obj[_fn] = this;
  if(arguments.length>1){
    result = obj[_fn](...([...arguments].slice(1)));
  }else{
    result = obj[_fn]();
  }
  delete obj[_fn];
  return result;
}
复制代码


这样似乎完善了一些,但是还有一种情况需要考虑,即调用call方法没有传参的情况,或者第一个参数为null或者undefined


var name = 'window.name';
function foo(){
  console.log(this);
  console.log(this.name)
};
foo.call(); //  window window.name
foo.call(1); // Number {1}  undefined
复制代码


通过上面的代码我们可以得出结论,如果调用call方法没有传入参数或者第一个参数为null或者undefined,会将函数的this绑定到window对象(注意如上测试代码,不可以使用let声明name哦),而如果传入的参数为基本数据类型,会将其转换为对象


继续完善后的call方法如下:


Function.prototype.call2 = function(obj){
  obj = obj?Object(obj):window;
  let _fn = "fn",result;
  while (obj.hasOwnProperty(_fn)) {
    _fn = "fn" + Math.random(); // 循环判断并重新赋值
  }
  obj[_fn] = this;
  if(arguments.length>1){
    result = obj[_fn](...([...arguments].slice(1)));
  }else{
    result = obj[_fn]();
  }
  delete obj[_fn];
  return result;
}
复制代码


而有了如上思考过程,实现apply就很简单了,代码如下:


Function.prototype.apply2 = function(obj,arr){
  obj = obj?Object(obj):window;
  let _fn = "fn",result;
  while (obj.hasOwnProperty(_fn)) {
    _fn = "fn" + Math.random(); // 循环判断并重新赋值
  }
  obj[_fn] = this;
  if(arr){
    result = obj[_fn](...arr);
  }else{
    result = obj[_fn]();
  }
  delete obj[_fn];
  return result;
}
复制代码


bind实现:


Function.prototype.bind2 = function (obj) {
  obj = obj ? Object(obj) : window
  let myArguments = arguments
  let self = this
  if (arguments.length > 1) {
    return function () {
      self.apply(obj, [...[...myArguments].slice(1), ...arguments])
    }
  }
  return function () {
    self.apply(obj, [...arguments])
  }
}
复制代码


bind的实现借用了apply方法,有兴趣的朋友可以尝试不借用apply实现bind


如果有错误或者不严谨的地方,请给予指正,十分感谢!

相关文章
|
7月前
new bind apply call instanceof 等笔记
new bind apply call instanceof 等笔记
18 0
|
8月前
|
JavaScript 前端开发
面试官: call、apply和 bind有什么区别?
面试官: call、apply和 bind有什么区别?
|
8月前
bind、call、apply 区别
bind、call、apply 区别
51 0
|
9月前
手写call-apply-bind以及了解柯里化
手写call-apply-bind以及了解柯里化
|
10月前
call、apply、bind笔记
call、apply、bind笔记
46 0
|
前端开发
前端学习案例1:apply,call,bind使用1
前端学习案例1:apply,call,bind使用1
54 0
前端学习案例1:apply,call,bind使用1
|
前端开发
前端学习案例2:apply,call,bind使用2
前端学习案例2:apply,call,bind使用2
56 0
前端学习案例2:apply,call,bind使用2