call() 与 apply() 和 bind()

首先了解this

若是想用好这几个方法,须要先了解this被调用方式不一样而致使值不一样的各类状况,而后就会认识到使用这几个方法的缘由在哪里。(能够指定this的值)
全局上下文中this指向全局对象,函数上下文this取决于被调用的方式es6

例:数组

  • 在非严格模式下,全局调用函数this默认指向全局(window)
var a = 3

function exp(){
  var a = 4
  console.log(this.a)
}

var b = exp()
// 输出3
  • 在严格模式下,由于this为其进入上下文时的值,因此为undefined
function exp(){
 "use strict"
  return this
}

console.log(exp() === undefined)
// 输出 true

下面分析各个调用场合下this的值app

做为函数被直接调用

上面已经写出了这种状况,值得注意的是,咱们每每并不须要this值为window函数

做为方法被调用

做为方法被调用时,this指向方法所在的对象上
例:this

var exp =  {
  obj: function context() {
     var text = "hello"
     return this 
  }
}

console.log(exp.obj() === exp)
var a = exp.obj()
console.log(a === exp)

var b = exp.obj
console.log(b() === window) //true,,注意这里当对象的方法被全局调用后this是b的this,则是window

//均输出 true

做为构造函数被调用

咱们知道构造函数建立一个对象的过程code

  1. 建立新对象
  2. 新对象做为this指向的对象
  3. 为新对象添加方法、属性、、并返回对象

须要注意的地方:构造函数返回一个非对象类型时,建立新对象时并不妨碍this的使用,也会返回新建立的对象。可是当构造函数显示返回一个对象时就会将这个对象赋值给变量,this的使用则无效。对象

function Fn (){
  this.obj = function() {
    return this
  }
}

let a = new Fn()
console.log(a.obj() === Fn) // false
console.log(a.obj() === a) //true

let newObj = {
  name: "小明"
}

function reObj (){
  this.name = "康康"
  return newObj
}

let b = new reObj()
console.log(b.name) //小明,返回的对象是newObj

进入正题,在这么多变化中随时均可能出错,因此call()、apply()、bind()就提供了一个能够指定this的方式ci

方法的使用

  1. call()作用域

    这个方法接受多个参数,第一个参数是指定的this值,剩下的都是调用的函数的参数列表
    fn.call(this, arg1, arg2, ...);
    若是第一个参数须要是对象,若是传入了数字、字符串、布尔值的话this会指向该原始值的自动包装对象字符串

    function f(){
          console.log(this)
          console.log(arguments)
      }
      f.call() // window
      f.call({name:'小明'}) // {name: '小明'}, []
      f.call({name:'小红'},1) // {name: '小红'}, [1]
      f.call({name:'康康'},1,2) // {name: '康康'}, [1,2]
  2. apply()

    apply() 与call()区别在于第二个参数接受的是一个包含多个参数的数组,对于一些方法须要传入的参数不能使数组,可使用apply()调用函数使其可使用数组做为参数。

    var a = [1,2,3,4,5,6,7,8,9]
    sum.apply(null,a)
    //将参数a全都传入,它会把参数做为数组传入。
    
    //求数组的最大元素
    Math.max.apply(null,[1,2,6]) // 6

    不少使用场景均可以被es6里的扩展运算符替代

  3. bind()

    bind()方法建立一个新的函数, 当被调用时,将其this关键字设置为提供的值.

    this.name = "大牛"
    
    let obj = {
      name: "康康",
      age: 18,
      city:"上海"
    }
    
    let newObj =  {
      name: "小明",
      sayName: function() {
        console.log(this.name)
      }
    }
    
    newObj.sayName()// 小明
    
    let a = newObj.sayName.bind(obj)
    a() //康康
    
    let b = newObj.sayName
    b() //大牛
  4. 箭头函数
    这里说一下箭头函数,由于箭头函数没有this,因此会根据做用域链进行寻找this,这也衍生了不少用法,好比在setTimeout里常常出现的上下文(做用域)问题,若是不使用箭头函数,在函数运行时做用域就变成了全局,使用箭头函数会使函数里用到的this绑定在setTimeout的做用域上

    var timer = {
    fn1() {
        setTimeout(function(){
            console.log(this)
        }, 10)
    },
    fn2() {
        setTimeout(()=>{
            console.log(this)
        },20)
    },
    fn3: ()=> {
        setTimeout(()=>{
            console.log(this)
        },30)        
    }
     }
     timer.fn1() //window
     timer.fn2() // timer
     timer.fn3() //window
     
     //第一个在执行时是在全局调用,至关于 fn1.call(undefined)
     // 第二个使用箭头函数自身没this,使this 指向了timer
     // 第三个自身没this的状况下,根据箭头函数的规则找到了最外层全局(window)
相关文章
相关标签/搜索