call,apply and bind in JavaScript

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)))
      }
   }

参考链接

    原文作者:不可能的是
    原文地址: https://segmentfault.com/a/1190000013683646
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞