如下內容爲本人閱讀《你不知道的Javascript》中this部分的讀書小結,有興趣的話能夠直接看原著。app
若是判斷是不是默認綁定?
觀察函數的調用位置,不帶任何修飾的函數引用進行調用,適用默認綁定。注意嚴格模式下,不能將全局對象用於默認綁定,this 會綁定到undefined。函數
fucntion foo() { console.log(this.a) } var a = 2; foo() // 2
觀察調用位置是否有上下文對象,或者被某個對象擁有或者包含,以下:this
fucntion foo() { console.log(this.a) } var obj = { a: 2, foo: foo } obj.foo() // 2
對象屬性引用鏈上只有最後一層在調用位置中起做用。es5
function foo() { console.log(this.a) } var obj1 = { a: 2, foo: foo } var obj2 = { a: 42, obj1: obj1 } obj2.obj1.foo() //2
函數引用致使隱式綁定丟失prototype
1.函數引用code
var a = 'global' function foo() { console.log(this.a) } var obj1 = { a: 2, foo: foo } var bar = obj1.foo bar() // 'global'
2.參數傳遞或者回調函數(本質是隱式賦值)對象
var a = 'global' function foo() { console.log(this.a) } var obj1 = { a: 2, foo: foo } var bar = obj1.foo function bar(fn) { fn() } bar(obj1.foo) // 'global' setTimeout(obj1.foo, 500) //'global'
function foo(val) { this.a = val } let bar = new foo(2) console.log(bar.a ) // 2 // 此時函數中的this => bar。 // 簡單瞭解一下使用new來調用函數,會發生什麼 // 1.建立(或者說構造)一個全新的對象。 // 2.這個新對象會被執行[[Prototype]]鏈接。 // 3.這個新對象會綁定到函數調用的this。 // 4.若是函數沒有返回其餘對象,那麼new表達式中的函數調用會自動返回這個新對象。 // 也就是在第3步的時候纔會進行this綁定,更體現了this綁定是發生在函數調用的時候。
顯而易見,隱式綁定優先級高於默認綁定
function foo() { console.log(this.name) } let obj1 = { name: 'obj1', foo } let obj2 = { name: 'obj2', } obj1.foo.call(obj2) // 'obj2'
顯式綁定優先級高於隱式綁定繼承
function foo(name) { this.name = name } let obj1 = { name: 'obj1', foo } obj1.foo('new name') console.log(obj1.name) // new name var bar = new obj1.foo('bar') console.log(bar.name) // bar console.log(obj1.name) // new name
new綁定優先級高於隱式綁定ip
ES5中內置的Function.prototype.bind(..)作用域
function foo(name) { this.name = name } let obj1 = { name: 'obj1', foo } var newFoo = foo.bind(obj1) newFoo('new name') console.log(obj1.name) // new name var bar = new newFoo('bar') console.log(bar.name) // bar console.log(obj1.name) // new name
1.函數是否在new中調用(new綁定)?若是是的話this綁定的是新建立的對象。
2.函數是否經過call、apply(顯式綁定)或者硬綁定調用?若是是的話,this綁定的是指定的對象。
3.函數是否在某個上下文對象中調用(隱式綁定)?若是是的話,this綁定的是那個上下文對象。
4.若是都不是的話,使用默認綁定。若是在嚴格模式下,就綁定到undefined,不然綁定到全局對象。
(例外:若是你把null或者undefined做爲this的綁定對象傳入call、apply或者bind,這些值在調用時會被忽略,實際應用的是默認綁定規則)
1.箭頭函數不使用this的四種標準規則,而是根據外層(函數或者全局)做用域來決定this。
2.箭頭函數的綁定沒法被修改
3.箭頭函數用更常見的詞法做用域取代了傳統的this機制。
4.在沒有箭頭函數以前,咱們一般使用 that 或者 self,去代替函數內部的this
this.a = 'global' var obj1 = { a: 1 } function foo() { setTimeout_(() => { console.log(this.a) }) } function bar() { setTimeout_(function() { console.log(this.a) }) } function setTimeout_(fn) { fn() } foo.call(obj1) // 1 箭頭函數,須要觀察箭頭函數被建立時的詞法做用域,this取決於外層做用域 bar.call(obj1) // global 普通函數使用四條規則,主要觀察函數被調用時的狀況