若是想用好這幾個方法,須要先了解this被調用方式不一樣而致使值不一樣的各類狀況,而後就會認識到使用這幾個方法的緣由在哪裏。(能夠指定this的值)
全局上下文中this指向全局對象,函數上下文this取決於被調用的方式es6
例:數組
var a = 3 function exp(){ var a = 4 console.log(this.a) } var b = exp() // 輸出3
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
須要注意的地方:構造函數返回一個非對象類型時,建立新對象時並不妨礙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
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]
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裏的擴展運算符替代
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() //大牛
箭頭函數
這裏說一下箭頭函數,由於箭頭函數沒有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)