资讯专栏INFORMATION COLUMN

call,apply and bind in JavaScript

JohnLui / 2402人阅读

摘要:文章尽量使用大量实例进行讲解,它们的使用场景。在严格模式下,函数被调用后,里面的默认是后面通过调用函数上的和方法,该变指向,函数里面的指向。利用,可以传入外层的上下文。同样适用的还有,里面的对象,它也是一种类数组对象。

call,apply and bind in JavaScript
在ECMAScript中,每个函数都包含两个继承而来的方法:apply() 和 call(),这两个方法的用途都是在特定的作用域中调用函数,主要作用跟bind一样,用来改变函数体内this的指向,或者说是在函数调用时改变上下文。

文章尽量使用大量实例进行讲解,它们的使用场景。同时,也会由浅入深的引导出一些理论,毕竟这几个常用方法,在MDN上都能找到合理的解释

基本功能 改变this的指向
  var fruit = {
    fruitName:"apple"
  }
  function getFruit() {
    console.log("I like "+this.fruitName)
  }

  getFruit();    // log   I like undefined
  getFruit.call(fruit)    // log   I like apple
  getFruit.apply(fruit)   // log   I like apple
  var newBind = getFruit.bind(fruit)
  newBind();              // log   I like apple

当 getFruit 并非作为一个对象的属性,而是直接当做一个函数来调用,里面的this就会被绑定到全局对象上,即window上, 所以直接调用 getFruit,里面的this指向了全局对象上,返回 undefined

在严格模式下,函数被调用后,里面的this默认是 undefined

后面,通过调用函数上的callapply方法,该变this指向,函数里面的this指向fruit

区别:
bind同样实现了改变this指向的功能,但是它不会立即执行,而是会重新创建一个绑定函数,新函数被调用时,使用bind()方法里面的第一个参数作为this

接受参数

这三个方法,从接受的第二参数开始,都直接传递给函数,但是接受参数的方法却很大的不同。

call,从第二个参数开始,以参数列表的形式展示,

apply,则把传递的函数参数,放在一个数组里面作为第二个参数。

fn.call(obj,arg1,arg2);
fn.apply(obj,[arg1,arg2])

bind,从第二个参数开始,同样以参数列表的形式,但是会提前放在新绑定函数的参数之前

 var foo = function(name,age){
   console.log("name: "+name+"- age: "+age)
 }

 var p1 = foo.bind(this,"popo");   // "popo" 作为新函数的第一个参数。
 p1(13);                       // logs    name: popo- age: 13
 p1("bobo",14)                 // logs    name: popo- age: bobo
应用场景

绑定事件回调中

  $(".div-class").on("click",function(event) {
        /*TODO*/
        }.bind(this));
      }
  }

通常,我们在改变函数上下文之前,都会使用类似that = this,或者self,_this,来把this赋值给一个变量。利用.bind(),可以传入外层的上下文。

循环回调

循环中利用闭包来处理回调

for(var i = 0;i < 10;i++){
 (function(j){
     setTimeout(function(){            
         console.log(j);
     },600);
 })(i)
}

每次循环,都会产生一个立即执行的函数,函数内部的局部变量j保存不同时期i的值,循环过程中,setTimeout回调按顺序放入消息队列中,等for循环结束后,堆栈中没有同步的代码,就去消息队列中,执行对应的回调,打印出j的值。

同理,可以利用bind,每次都创建新的函数,并且已经预先设置了参数,传入不同的指针

  function func(i) {
    console.log(i)
  }
  for(var i =0 ;i< 10;i++) {
    setTimeout(func.bind(null,i),600)
  }

实现继承

 var Person = function(name,age) {
   this.name = name;
   this.age = age;
 }

 var P1 = function(name,age) {
   // 借用构造函数的方式实现继承
   // 利用call 继承了Person
   Person.call(this,name,age)
 }
 P1.prototype.getName = function() {
   console.log("name: "+this.name+", age: "+this.age);
 }

 var newPerson = new P1("popo",20);   // logs name: popo, age: 20
 newPerson.getName();

实质上,可以看成通过call()或者apply()方法,在即将新建的对象,即这里的newPerson上,执行超类型的构造函数,分别在当前上下文this上添加nameage属性。

数组验证的终极方法

  function isArray(value) {
    return Object.prototype.toString.call(value) == "[object Array]"
  }

借用了Object原生的toString()方法,打印出对应变量的构造函数名,

类数组转换为数组

  // 实现一个简单的数组 "unshift"方法
  Array.prototype.unshift = function(){
    this.splice.apply(this,
      [0,0].concat(Array.prototype.slice.apply(arguments)));
      return this.length;
  }

首先,利用this.splice.apply(),其中splice,可以直接从数组中移除或者插入变量。apply()则以数组的形式传递参数,需要利用concat拼接数组。

当函数被调用时,在函数内部会得到类数组arguments,它拥有一个length属性,但是没有任何数组的方法。所以,将slice方法中的this指向arguments,获取到arguments的长度,从而确定方法的startend下标,得到一个数组变量。

同样适用的还有,DOM里面的NodeList对象,它也是一种类数组对象。

深入理解 实现bind 方法

bind方法在ECMAScript5里面被引入,前面提到过,调用该方法时,返回一个新的函数,可以简单使用下面方法实现其改变this指向的功能。

  Function.prototype.bind = function(scope) {
    var fn = this;
    return function() {
      return fn.apply(scope)
    }
  }

接着,就可以利用concat把bind传递的预置参数拼接到新函数的参数列表中。

   Function.prototype.bind = function(scope) {
      var args = Array.prototype.slice.call(arguments,1)
      var fn = this
      return function() {
        return fn.apply(scope,args.concat(Array.prototype.slice.call(arguments)))
      }
   }

参考链接

Javascript之bind

Understanding JavaScript Bind ()

深入浅出妙用 Javascript 中 apply、call、bind

前端基础进阶:全方位解读 this

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

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

相关文章

  • 理解 JavaScript call()/apply()/bind()

    摘要:理解文章中已经比较全面的分析了在中的指向问题,用一句话来总结就是的指向一定是在执行时决定的,指向被调用函数的对象。与和直接执行原函数不同的是,返回的是一个新函数。这个新函数包裹了原函数,并且绑定了的指向为传入的。 理解 JavaScript this 文章中已经比较全面的分析了 this 在 JavaScript 中的指向问题,用一句话来总结就是:this 的指向一定是在执行时决定的,...

    duan199226 评论0 收藏0
  • Brief introduction of how to 'Call, Apply and

    摘要:关于在绝大多数情况下,函数的调用方式决定了的值。不能在执行期间被赋值,并且在每次函数被调用时的值也可能会不同。它们除了参数略有不同,其功能完全一样。它们的第一个参数都为将要指向的对象。 关于 this 在绝大多数情况下,函数的调用方式决定了this的值。this不能在执行期间被赋值,并且在每次函数被调用时this的值也可能会不同。 全局 this window.something = ...

    incredible 评论0 收藏0
  • JavaScript的作用域、闭包、(apply, call, bind

    摘要:闭包闭包的概念与词法域关系紧密。闭包甚至在函数已经返回后也可以获取其外部函数的变量。一种常见的闭包导致的由立即调用函数表达式解决的例子事实上结果的所有都是,而不是按顺序得出的,。 介绍 JavaScript 有一个特征————作用域。理解作用域scope可以使你的代码脱颖而出,减少错误,帮助你用它构造强大的设计模式。 什么是作用域 作用域就是在代码执行期间变量,函数和对象能被获取到的特...

    tyheist 评论0 收藏0
  • Function Definition, This and Bind in JavaScript

    I thought I know the Function definition, execution context and the behavior of this in JavaScript. However, I realized that actually I dont or the knowlege is still not firmly grounded in my mind wh...

    siberiawolf 评论0 收藏0
  • 不再彷徨:完全弄懂JavaScript中的this(译文总结)

    摘要:至于,其只是以数组的方传入参数,其它部分是一样的,如下它们也可用于在中的类继承中,调用父级构造器。间接调用,调用了父级构造器对比方法和,它俩都立即执行了函数,而函数返回了一个新方法,绑定了预先指定好的,并可以延后调用。 其实this是一个老生常谈的问题了。关于this的文章非常多,其实我本以为自己早弄明白了它,不过昨天在做项目的过程中,还是出现了一丝疑惑,想到大概之前在JavaScri...

    YanceyOfficial 评论0 收藏0

发表评论

0条评论

JohnLui

|高级讲师

TA的文章

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