再谈JavaScript中bind、call、apply三个方法的区别与使用方式

 更新时间:2022年05月03日 11:47:48   作者:Ahuiyo の Blog  
这篇文章主要介绍了Javascript中bind、call、apply三个方法的使用方式,需要的朋友可以参考下

call的基本使用

var ary = [12, 23, 34];
ary.slice();

以上两行简单的代码的执行过程为:ary这个实例通过原型链的查找机制找到Array.prototype上的slice方法,让找到的slice方法执行,在执行slice方法的过程中才把ary数组进行了截取。

注意slice方法执行之前有一个在原型上查找的过程(当前实例中没有找到,再根据原型链查找)。

当知道了一个对象调用方法会有一个查找过程之后,我们再看:

var obj = {name:'iceman'};
function fn() {
    console.log(this);
    console.log(this.name);
}
fn(); // this --> window
// obj.fn(); // Uncaught TypeError: obj.fn is not a function
fn.call(obj);

call方法的作用:首先寻找call方法,最后通过原型链在Function的原型中找到call方法,然后让call方法执行,在执行call方法的时候,让fn方法中的this变为第一个参数值obj,最后再把fn这个函数执行。

知道这个原型上的原理后,咱们就可以动手分析实现这三个方法了。

bind、call、apply 区别

  • call 和 apply 都是为了解决改变 this 的指向。作用都是相同的,只是传参的方式不同。
  • 除了第一个参数外,call 可以接收一个参数列表,apply 只接受一个参数数组
let a = {
    value: 1
}
function getValue(name, age) {
    console.log(name)
    console.log(age)
    console.log(this.value)
}
getValue.call(a, 'yck', '24')
getValue.apply(a, ['yck', '24'])

bind 和其他两个方法作用也是一致的,只是该方法会返回一个函数。并且我们可以通过 bind 实现柯里化

如何实现一个 bind 函数

对于实现以下几个函数,可以从几个方面思考

  • 不传入第一个参数,那么默认为 window
  • 改变了 this 指向,让新的对象可以执行该函数。那么思路是否可以变成给新的对象添加一个函数,然后在执行完以后删除?

当然是肯定的,于是我们可以这样写:

Function.prototype.myBind = function (context) {
  if (typeof this !== 'function') {
    throw new TypeError('Error')
  }
  var _this = this
  var args = [...arguments].slice(1)
  // 返回一个函数
  return function F() {
    // 因为返回了一个函数,我们可以 new F(),所以需要判断
    if (this instanceof F) {
      return new _this(...args, ...arguments)
    }
    return _this.apply(context, args.concat(...arguments))
  }
}

如何实现一个 call 函数

Function.prototype.myCall = function (context,...arg) {
  var context = context || window  // 给 context 添加一个属性
  // getValue.call(a, 'yck', '24') => a.fn = getValue
  //使用symbol 选择一个独一无二的值作为新添加的属性
  let symbol = new Symbol();
  context[symbol] = this;
  let result = context[symbol](...arg)
  // 删除添加的函数
  delete context[symbol]  
  return result
}

如何实现一个apply 函数

apply实现原理与call实现基本类似,只有传值的方式不一样。

Function.prototype.myApply = function (context,arg) {
  var context = context || window // 给 context 添加一个属性
 // getValue.call(a, 'yck', '24') => a.fn = getValue
 //使用symbol 选择一个独一无二的值作为新添加的属性
 let symbol = new Symbol();
 context[symbol] = this;
 let result = context[symbol](arg)
 // 删除添加的函数
 delete context[symbol]
 return result
}

经过对以上的函数进行检测 , 完美通过。

const obj = {  
 name : 'xiaoxiao',  
 getName : function (arg) {  
 console.log(`我是${this.name}里面的,我里面有${arg}`);  
 }  
}  
obj.getName([0,0,0,0,0]); // 我是xiaoxiao里面的  
const obj2 = {  
 name : 'huahua'  
}  
//传值不一样  
obj.getName.myCall(obj2,1,1,1,1,1,1);  
obj.getName.myBind(obj2)(2,2,2,2,2,2);  
obj.getName.myApply(obj2,[3,3,3,3,3,3]);

 更多关于JS中call、apply三个方法的区别与使用方式请查看下面的相关链接

相关文章

  • replace()方法查找字符使用示例

    replace()方法查找字符使用示例

    查找字符的情况下会使用replace()方法,此方法很常见也很实用,下面有个不错的示例,感兴趣的朋友可以参考下,希望对大家有所把帮助
    2013-10-10
  • JavaScript前端静态资源预加载实现示例

    JavaScript前端静态资源预加载实现示例

    这篇文章主要为大家介绍了JavaScript前端静态资源预加载实现示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-11-11
  • javascript call和apply方法

    javascript call和apply方法

    用于改变方法的当前对象
    2008-11-11
  • CSS3 动画卡顿性能优化的完美解决方案

    CSS3 动画卡顿性能优化的完美解决方案

    今天小编就为大家分享一篇关于css3 动画卡顿性能优化的完美解决方案,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2018-09-09
  • 深入理解TypeScript 类型兼容性

    深入理解TypeScript 类型兼容性

    本文主要介绍了TypeScript 在函数、枚举、类和泛型中的类型兼容性规则,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-01-01
  • JavaScript+CSS实现模态框效果

    JavaScript+CSS实现模态框效果

    这篇文章主要为大家详细介绍了JavaScript+CSS实现模态框效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-07-07
  • javascript实现全局匹配并替换的方法

    javascript实现全局匹配并替换的方法

    这篇文章主要介绍了javascript实现全局匹配并替换的方法的总结,十分的简单实用,有需要的小伙伴可以参考下。
    2015-04-04
  • js图片自动切换效果处理代码

    js图片自动切换效果处理代码

    自己设置每张图片切换的时间间隔,自己设置每张图片的路径(绝对、相对路径都可以)虽然很简单,但是很实用
    2013-05-05
  • js contains方法实现代码

    js contains方法实现代码

    IE有许多好用的方法,后来都被其他浏览器抄袭了,比如这个contains方法。如果A元素包含B元素,则返回true,否则false。唯一不支持这个方法的是IE的死对头firefox。
    2011-01-01
  • ajax 缓存 问题 requestheader

    ajax 缓存 问题 requestheader

    最近刚刚遇到一个问题是这样的,我的treeview点击结点显示地图要素是通过prototype的ajax实现的
    2010-08-08

最新评论