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)
相關文章
相關標籤/搜索