--- tags: Javascript, disqus: hackmd --- # Javascript的this|chrisHsiao 在看了Huli大神的[淺談 JavaScript 頭號難題 this:絕對不完整,但保證好懂](https://blog.huli.tw/2019/02/23/javascript-what-is-this/)後,我覺得很重要的重點。 ``` 1. 脫離物件的 this 基本上沒有任何意義 2. 沒有意義的 this 會根據嚴格模式以及環境給一個預設值 3. 嚴格模式底下預設就是 undefined,非嚴格模式在瀏覽器底下預設值是 window 4. 可以用 call、apply 與 bind 改變 this 的值 5. 要看 this,就看這個函式「怎麽」被呼叫 6. 可以把 a.b.c.hello() 看成 a.b.c.hello.call(a.b.c),以此類推,就能輕鬆找出 this 的值 ``` this的預設值在 1. 嚴格模式底下就都是undefined 2. 非嚴格模式,瀏覽器底下是window 3. 非嚴格模式,node.js 底下是global ## class跟object 基本上,在class跟object裡的this會是自己本身 ## 更改 this 的值 [[JS]call、apply、bind](https://hackmd.io/8mTXvpw-R0WJUJAQfSS7Bg?view) 更改 this 的值的方法有三種。 > call、apply、bind 而call跟apply這兩種非常相似 ```javascript= 'use strict'; function hello(a, b){ console.log(this, a, b) } hello(1, 2) // undefined 1 2 hello.call(undefined, 1, 2) // undefined 1 2 hello.apply(undefined, [1, 2]) // undefined 1 2 ``` ## class中的 this ## 物件中的 this ```javascript= const obj = { value: 1, hello: function() { console.log(this.value) } } obj.hello() // 1 ``` ## 不合群的箭頭函式 自己在寫物件的裡的function的時候就遇過這個問題,沒想到Huli大神也有提到,正好可以解我的疑惑。 > 「在宣告它的地方的 this 是什麼,它的 this 就是什麼」 不是我在講,真的很難懂。 ```javascript= const obj = { x: 1, hello: function(){ console.log(this) const test = () => { console.log(this.x) } test() } } obj.hello(); const hello = obj.hello; hello(); ``` 一開始看我也是混亂到不行,但如果回歸到單純一點,就是用call來看,我覺得就清楚很多了 ```javascript= obj.hello.call(obj); //帶了obj進去,所以hello裡的this會是obj這個物件 test.call(); //因為是箭頭函式,所以test的this會是在宣告這個函式時候的當下this, //也就是hello的this,所以this.x就會印出1 hello.call(); //沒有帶參數進去,所以hello裡的this會是window test.call(); //因為是箭頭函式,所以test的this會是在宣告這個函式時候的當下this, //也就是window,而window.x就會是undefined ``` --- 如果把test的箭頭函示改回原本的函式又會是怎樣呢? ```javascript= const obj = { x: 1, hello: function() { console.log('this', this) function test() { console.log('this.x', this.x) } test.call() } } obj.hello.call(); // const hello = obj.hello; // hello(); ``` 把呼叫hello跟test函式的地方加上call來看 ```javascript= obj.hello.call(obj); //帶了obj進去,所以hello裡的this會是obj這個物件 test.call(); //沒有帶參數進去,所以test裡的this會是window //但是他是 console this.x 所以會看到1 ``` 再把最下面註解的兩行打開,並把hello也加上call ```javascript= const hello = obj.hello; hello.call(); hello.call(); //沒有帶參數進去,所以hello裡的this會是window test.call(); //沒有帶參數進去,所以test裡的this會是window //但是他是 console this.x,而window底下沒有x所以是undefined ``` --- ### self this 先看看一個範例 ```javascript= var body = document.getElementById('body'); body.addEventListener('click', function() { console.log("body click's this", this); //id是body的元素 }); console.log('this', this); //window ``` #### 為什麼body click的this返回的不一樣? 簡單的說,因為這時候的this被指定到了body上,所以他返回的就會是id=body的元素。 #### 如何讓body click的時候拿到跟外面一樣的this? ##### 1. 在外層就先指定this ```javascript= var body = document.getElementById('body'); var test = this; body.addEventListener('click', function() { console.log("body click's this", test); //window }); console.log('this', this); //window ``` 這裡就回到標題的self this上,叫self \_this是因為,有人會把`var test = this`的test換成`self`、`_this`、`that`之類的,可以用這幾個關鍵字去搜尋看看。 但我個人是覺得沒差。 [Scope and this in JavaScript](https://www.jackfranklin.co.uk/blog/javascript-variable-scope-this/) [鐵人賽:JavaScript 的 this 到底是誰?](https://wcc723.github.io/javascript/2017/12/12/javascript-this/) ##### 2. bind() ```javascript= var body = document.getElementById('body'); body.addEventListener('click', function() { console.log("body click's this", this); //window }.bind(this)); console.log('this', this); //window ``` 使用函式預設有的bind()這個方法把this帶入。 ##### 3. 箭頭函示(arrow function) ```javascript= var body = document.getElementById('body'); body.addEventListener('click', () => { console.log("body click's this", this); //window }); console.log('this', this); //window ``` 這就必須提到箭頭函式的特性,他會依據他被建立時的this是什麼,他的this就是什麼。 --- ### 參考文章 [淺談 JavaScript 頭號難題 this:絕對不完整,但保證好懂](https://blog.huli.tw/2019/02/23/javascript-what-is-this/) [this 的值到底是什么?一次说清楚](https://zhuanlan.zhihu.com/p/23804247) [Scope and this in JavaScript](https://www.jackfranklin.co.uk/blog/javascript-variable-scope-this/) [作用域 (Scope)](https://hackmd.io/zbZx_kfNTQq1jRUA_03QUA?view) [[JS]call、apply、bind](https://hackmd.io/8mTXvpw-R0WJUJAQfSS7Bg?view) --- ###### tags: `Javascript` `this` `scope`