this這個單詞是一個代詞,因此this應該是 指代某些東西
搞清楚this的關鍵之處,就是要搞清楚this指代了什麼node
那麼this到底指代了什麼呢?
就像你平時
指着一個蘋果說 this is an apple
指着一個香蕉說 this is a banana面試
一樣,this也會由於狀況的不一樣而不一樣segmentfault
在JavaScript中
按照常規理解,this的值是什麼取決於函數如何被調用
然而,this的值是什麼徹底取決於對應函數被call時傳入的第一個參數,而這通常是由js提早就預置好的數組
注意:這種方法能夠判斷通常狀況下的this是什麼
// 例子 function fn() { console.log(this) } let obj = { a: '', fn: fn } // 場景一 fn() // window[瀏覽器] or global[node] // 場景二 obj.fn() // obj // 場景一:全局調用 // 場景二:方法調用
function VS method瀏覽器
更詳細的說明請看 深刻淺出面向對象和原型【概念篇1】
// test1 function fn() { console.log(this) } let obj1 = { wrapper: { a: 'a', fn: fn } } obj1.wrapper.fn() // ? // fn()是被當作wrapper的方法被調用的,因此this是wrapper // this指向調用它的距離最近的那一個 // test2 function executeCallback(cb) { cb() } executeCallback(obj1.wrapper.fn) // this是全局變量 // 由於executeCallback函數是把cb當成全局函數進行調用的 // 不像是obj.cb(),如果obj.cb()就是方法調用了
按照常規理解已經能夠解決大部分的面試、筆試題了,但若是想究this之根本,還須要經過call
注意:經過對call的初步理解,你能夠知道this的值爲何是這樣的,但這種思惟不方便你猜this
首先,咱們要清楚this在函數中的位置app
function fn1([this], parameter) { // this就是隱藏的第一個參數,並且永遠是第一個參數 console.log(this) }
其次,咱們要知道call的語法函數
fun.call(thisArg, arg1, arg2, ...)
OK,如今咱們要知道你在使用call的時候
call傳入的第一個參數能夠指定(改變)fn1的第一個參數,也就是隱藏的this測試
因此,爲何直接全局調用fn1時,打印出來的是window呢?
由於js已經幫你call了this
// 你寫的代碼 fn1() // 在你寫上面代碼的時候,js幫你寫了一行你看不到的代碼 fn1().call(undefined) // 你可能回問:這樣打出來的值應該是undefined呀 // 但瀏覽器有個機制 // 若是你傳的 thisArg 就 null 或者 undefined,那麼 window 對象就是默認的 context(嚴格模式下默認 context 是 undefined)
咱們從新來看待一下全局調用和方法調用,以及js是如何用call指定this的
// 例子 function fn() { console.log(this) } let obj = { a: '', fn: fn } // 場景一 fn() // window[瀏覽器] or global[node] // js幫你寫的代碼 fn().call(undefined) // 場景二 obj.fn() // obj // js幫你寫的代碼 obj.fn().call(obj)
小測試(小陷阱)
let module = { x: 42, getX: function () { return this.x; } } let retrieveX = module.getX; console.log(retrieveX()); // undefined console.log(module.getX()) // 42
嚴格模式下只須要 注意一點就行,其它狀況下與非嚴格模式相同
全局做用域裏函數中的this是undefined
code
function test() { "use strict" console.log(this) } test() // undefined
因此,在使用構造函數時,若是忘了加new,this再也不指向全局對象,而是報錯
,由於這就是函數的全局調用
let People = function (name) { "use strict" this.name = name } People() // Cannot set property 'name' of undefined
function fn() { console.log(this) } arr[fn, fn2, fn3] arr[0]() // ?? // answer:arr // 解析 // 數組也是對象的一種 // arr[0]() 能夠看作 arr.0().call(arr)
// 例子一 function fn0() { function fn() { console.log(this); } fn(); } fn0(); // fn中this是全局變量 // 例子二 let a = { b: function () { console.log(this) // {b:fn} function xx() { console.log(this) // window } xx() } } a.b()
document.addEventListener('click', function (e) { console.log(this); setTimeout(function () { console.log(this); // 這裏的this是全局變量 }, 200); }, false);
document.querySelector('div').addEventListener('click',function (e) { console.log(this) // <div></div> }) // 事件裏的this指向的是觸發事件的DOM節點
若是幾種複雜狀況下的this你看完了,你應該會有疑惑
爲啥我明白了全局調用和方法調用,但this的值仍然和我推斷的不同呢?
我說過了,this的值是call的第一個參數,js已經給不少this進行call了
因此,總結一下
關於call/apply/bind 請看 this總結【2】—— call/apply和bind