this
的五種不一樣情形在默認的,純粹的函數調用時,視做全局性調用,此時的this指向全局對象Global,在瀏覽器環境下,也即window對象。json
window.x = 'Jackie' function func() { console.log(this.x) } func() // Jackie
在嚴格模式("use strict"
)下,會禁止this
指向全局對象,此時的this
會是undefined
。數組
此時this
指向調用這個方法的對象。瀏覽器
var x = 'Property of Window' var obj = {} obj.x = 'Property of obj' obj.f = function () { console.log(this.x) } obj.f() // Property of obj // 值得注意的狀況 var f = obj.f f() // Property of Window
call
、apply
和bind
的顯式綁定call
、apply
和bind
均可以改變一個函數的this
指向。app
call
和apply
call
和apply
會將它們的調用對象的this
指向它們的第一個參數。函數
function f () { console.log(this.x) } var x = 'Property of Window' var obj = { x: "Property of obj" } f.apply(obj) // "Property of obj"
當傳入的第一個參數爲undefined,或者不傳入參數時,在非嚴格模式下,自動會將this
指向全局對象Global,在瀏覽器裏是window
對象,嚴格模式下則會是undefined
:this
function f () { console.log(this) } f.apply() // window f.apply(undefined) // window function ff () { 'use strict' console.log(this) } ff.apply() // undefined ff.apply(undefined) // undefined
call
和apply
沒有本質區別。惟一的區別在於:prototype
call()
方法接受的是若干個參數的列表,而apply()
方法接受的是一個包含多個參數的數組。指針
bind
bind
和前面二者也並未有什麼本質的區別,只不過bind
將第一個參數綁定當調用函數的this
上,並將這個函數返回(不執行)。code
function f () { console.log(this.x) } var x = 'Property of Window' var obj = { x: "Property of obj" } var ff = f.bind(obj) ff() // "Property of obj"
當一個函數被當作構造函數,用new
關鍵字新建一個對象的時候,這個函數內部的this
以及原型鏈上的this
都會指向這個新建的對象。對象
function Jackie(para) { this.para = para console.log(this) } Jackie.prototype.log = function(){ console.log(this) } Jackie('hehe') // Window var p = new Jackie('haha') // Jackie {para: "haha"} p.log() // Jackie {para: "haha"}
JavaScript中超時調用的代碼都是在全局做用域中執行的,所以函數中this的值會指向window對象,在嚴格模式下也同樣。由於超時調用的代碼都會有一個隱式綁定:setTimeout(f, time) == setTimeout(f.bind(window), time)
。
"use stric" var x = 'Property of Window' var obj = {} obj.x = 'Property of obj' obj.ff = function () { setTimeout( function () { console.log(this.x) }, 100) } obj.ff() // Property of Window // 能夠這麼解決問題 obj.fff = function () { var that = this setTimeout( function () { console.log(that.x) }, 100) } obj.fff() // Property of obj
事件監聽函數中的this
指向監聽對象。
var one = document.getElementById('one') one.onclick = function () { console.log(this) }; one.click() // <div id="one"></div>
箭頭函數中this
的指向,在函數定義時即綁定完畢,且後續沒法更改。
var obj = { x: 1 } var f1 = () => { console.log(this) } f1.apply(obj) // Window var f2 = function () { var f3 = () => { console.log(this) } return f3 } var f4 = f2.apply(obj) f4() // Object {x: 1}
一個更神奇的例子,超時調用的代碼在定義時,綁定了this
的指向。
function foo() { setTimeout(() => { console.log('id:', this.id); }, 100); } var id = 21; foo.call({ id: 42 }); // id: 42
var obj = {x: 0, name: 'obj'} var robj = {x: -1, name: 'robj'} var factory = function (x) { this.x = x console.log(this) } var factoryBind = factory.bind(obj) robj.factory = factoryBind robj.factory(2) // Object {x: 2, name: "obj"},做爲方法的綁定的優先級低於bind的顯式綁定 factoryBind.call(robj, 3) // Object {x: 3, name: "obj"},call的優先級低於bind console.log(robj) // Object {x: -1, name: "robj", factory: function},未對robj進行修改 console.log(obj) // Object {x: 3, name: "obj"},修改的是obj,由於this指針指向未變化 var p = new factoryBind(4) // factory {x: 4} console.log(p) // factory {x: 4} console.log(obj) // Object {x: 3, name: "obj"},構造函數綁定的優先級高於bind的顯式綁定
能夠見得,優先級從高到低:
new
,構造綁定
bind
,顯式綁定
call
/apply
,顯示綁定
做爲方法綁定
默認綁定