资讯专栏INFORMATION COLUMN

对ES5中apply、call和bind三个方法的解读

王笑朝 / 3264人阅读

摘要:对中和三个方法的解读中,和都是为了改变某个函数运行时的上下文而存在的,其实就是为了改变所调用的函数体内部的指向。

对ES5中apply、call和bind三个方法的解读

JavaScript中,apply、call 和 bind 都是为了改变某个函数运行时的上下文而存在的,其实就是为了改变所调用的函数体内部 this 的指向

Function.prototype.apply()方法

Example

var nodeList = document.querySelectorAll("div");
Array.prototype.slice.apply(nodeList).forEach((node)=>{
  console.log(node);    // 输出每一个div节点对象
});

代码解读:
上面是一段JS中常用的代码,这段代码表示的意义是,当我们获取到一个类数组的对象的时候如何让它可以调用所有数组所拥有的方法。我们都知道,所有的获取dom元素的方法,返回的不是dom节点对象,就是包含节点对象的类数组,而类数组虽然从输出来看和数组是没什么区别的,但是在原型链上是有很大的差异的。像NodeList这个类数组就是不包含基本上所有数组的常用方法的,所以这个时候就需要 数组的slice方法来将NodeList这个歌类数组转成真正的数组对象,这样就可以直接调用push方法了。

Function.prototype.call()方法

Example

var nodeList = document.querySelectorAll("div");
Array.prototype.slice.call(nodeList).forEach((node)=>{
  console.log(node);    // 输出每一个div节点对象
});

代码解读:上面这段代码和apply方法中的例子是一模一样的,所以,其实他们两个方法的作用都是一致的,用法呢就是类似的,而为什么说是类似的呢,看下面这个例子:
Example:

var max1 = Math.max.call(null, 1,2,3); 
var max2 = Math.max.apply(null, [1,2,3]);
console.log(max1);      // 结果是3
console.log(max2)       // 结果是3

代码解读:从上面这个例子中可以看出,call和apply的用法不同之处在于,如果所调用的方法方法需要传入参数,那么call需要从第二个入参开始传入需要的,而apply是在第二入参用数组来传递参数,这里要注意的是哪怕是参数只需要传入一个,也全都按照这种语法规则,不然如上面的Math.max就会报TypeError,所以建议如下:当所调用的方法是0个参数的,那随便哪个都可以,如果是1~2个参数的建议使用call方法,如果是3个及以上的用apply方法

Function.prototype.bind()方法

Example

var nodeList = document.querySelectorAll("div");
var nodeArray = Array.prototype.slice.bind(nodeList);
nodeArray().forEach((node)=>{
  console.log(node);    // 输出每一个div节点对象
});

代码解读:从上面的例子看一看出bind方法只是替换了所调用方法的this指向,并不会主动去执行这个方法,而apply和call方法是即改变了this指向,又立即执行的,所以bind一般用于不需要立即执行,只要求更改this指向的场景,如:click事件的回调函数一般就会用bind去改变回调函数的this指向,而在click事件触发的时候执行。最后说明一下,bind的参数和call的参数传递是一致的,例子如下:

Example

var maxBind = Math.max.bind(null, 1,2,3); 
var max = maxBind();
console.log(max);      // 结果是3

结束语:上面就是javaScript对于如何改变运行时上下文的三个方法了,下面是我自己实现的一个类似运行时改变上下文的方法,不适合在实际场景中使用,仅供大家参考:

var Person = {
  context:null,
  name:"小明",
  say:function(greeting){
    var me = this.context || this;
    return greeting + me.name
  }
}
Person.say.__proto__.callCopy = function(_context,greeting){
  Person.context = _context;
  return Person.say(greeting);
}
var world1 =Person.say("你好 ");
var world2 = Person.say.callCopy({name:"xiaoMing"},"hello ");
console.log(world1);    // 你好 小明  
console.log(world2);    // hello xiaoMing

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/84151.html

相关文章

  • underscore 源码解读bind 方法实现

    摘要:概括地讲,如果构造函数有返回值,且返回值是对象不能是,那么对其进行操作返回该对象,否则返回构造实例。所以在方法中,我们需要进一步判断这个构造函数有没有返回值,返回值是不是对象。 自从进入七月以来,我的 underscore 源码解读系列 更新缓慢,再这样下去,今年更完的目标似乎要落空,赶紧写一篇压压惊。 前文 跟大家简单介绍了下 ES5 中的 bind 方法以及使用场景(没读过的同学建...

    xiaodao 评论0 收藏0
  • 可能遇到假面试题:不用callapply方法模拟实现ES5bind方法

    摘要:来自朋友去某信用卡管家的做的一道面试题,用原生模拟的方法,不准用和方法。他们的用途相同,都是在特定的作用域中调用函数。不同之处在于,方法传递给调用函数的参数是逐个列出的,而则是要写在数组中。 本文首发我的个人博客:前端小密圈,评论交流送1024邀请码,嘿嘿嘿?。 来自朋友去某信用卡管家的做的一道面试题,用原生JavaScript模拟ES5的bind方法,不准用call和bind方法。 ...

    李世赞 评论0 收藏0
  • 可能遇到假面试题:不用callapply方法模拟实现ES5bind方法

    摘要:来自朋友去某信用卡管家的做的一道面试题,用原生模拟的方法,不准用和方法。他们的用途相同,都是在特定的作用域中调用函数。不同之处在于,方法传递给调用函数的参数是逐个列出的,而则是要写在数组中。 本文首发我的个人博客:前端小密圈,评论交流送1024邀请码,嘿嘿嘿?。 来自朋友去某信用卡管家的做的一道面试题,用原生JavaScript模拟ES5的bind方法,不准用call和bind方法。 ...

    ConardLi 评论0 收藏0
  • 从一道面试题,到“我可能看了假源码”

    摘要:返回的绑定函数也能使用操作符创建对象这种行为就像把原函数当成构造器。同时,将第一个参数以外的其他参数,作为提供给原函数的预设参数,这也是基本的颗粒化基础。 今天想谈谈一道前端面试题,我做面试官的时候经常喜欢用它来考察面试者的基础是否扎实,以及逻辑、思维能力和临场表现,题目是:模拟实现ES5中原生bind函数。也许这道题目已经不再新鲜,部分读者也会有思路来解答。社区上关于原生bind的研...

    Carson 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<