手写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


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

相关文章
|
2月前
|
JavaScript 前端开发 开发者
call、bind、apply区别
【10月更文挑战第26天】`call`、`bind` 和 `apply` 方法在改变函数 `this` 指向和参数传递方面各有特点,开发者可以根据具体的需求和使用场景选择合适的方法来实现更灵活和高效的JavaScript编程。
37 1
|
3月前
|
前端开发 JavaScript
比较一下apply/call/bind ?
本文首发于微信公众号“前端徐徐”,详细介绍了 JavaScript 中 `apply`、`call` 和 `bind` 方法的概念、使用场景及手动实现。主要内容包括: - **apply**:使用数组作为参数调用函数,并指定 `this`。 - **call**:直接传递参数调用函数,并指定 `this`。 - **bind**:返回一个绑定了 `this` 和部分参数的新函数。 文章还对比了这三个方法的区别,并提供了手动实现的代码示例。
27 2
|
5月前
|
JavaScript 前端开发 测试技术
手写call , apply , bind 方法的实现
本文通过实例讲解了JavaScript中`call`、`apply`及`bind`方法的用途与实现。以`call`为例,展示了如何改变函数内的`this`指向,并立即执行该函数。通过在`Function.prototype`上定义`myCall`,利用`Symbol`确保新增属性的唯一性,从而避免命名冲突。接着介绍了如何处理不定数量的参数传递,最终实现了自定义的`myCall`方法。随后简述了`apply`与`call`的区别,并展示了其实现方式,主要在于参数传递形式的不同。最后,通过`bind`方法创建了一个返回新函数的例子,该新函数具有固定的`this`上下文,同时支持分批参数传递。
39 2
手写call , apply , bind 方法的实现
|
6月前
|
JavaScript
js【详解】bind()、call()、apply()( 含手写 bind,手写 call,手写 apply )
js【详解】bind()、call()、apply()( 含手写 bind,手写 call,手写 apply )
36 0
|
8月前
call\apply\bind详解
call\apply\bind详解
39 0
bind、call、apply 区别
bind、call、apply 区别
83 0
手写call-apply-bind以及了解柯里化
手写call-apply-bind以及了解柯里化
call、apply、bind笔记
call、apply、bind笔记
66 0
apply、bind和call
apply、bind和call
98 0