21436


**引数を渡そうとすると、thisがグローバルオブジェクトを指します**  
・この書き方の場合は、イベントハンドラ関数ではなくてただの関数扱いになる、ということでしょうか？

[code]

    function clickHandler(ev, str) {
      alert(this);
    };
    
    var button = document.getElementById("click-target");
    
    button.addEventListener("click", function(ev) {
      clickHandler(ev, "test");
    }, false);
[/code]

[code]

    <button id="click-target">Click me</button>
[/code]


CC BY-SA 3.0
2016-01-28T07:28:57.313
21430
2016-01-30T03:09:58.977
2016-01-28T08:03:33.243
13493
7886
question
javascript
イベントハンドラ関数内で、thisがグローバルオブジェクトを指すことがあるのは何故でしょうか？


そうです。this が指すものは呼び出し方によって変わります。

[code]

    function method() {
        alert(this); 
    };
    
    method(); // window
    
    var obj = {};
    obj.method = method;
    obj.method(); // object
    
[/code]

method と obj.method は同じものですが、直接 `method()` を呼び出すと this には window
が入り、`obj.method()` で呼ぶと obj が入っています。

addEventListener の場合には、`function(ev){ }` でくくらずに、次のように clickHandler
自体を渡すのも手かと思います。

[code]

    var button = document.getElementById("click-target");
    
    function clickHandler(ev) {
      // this は button (HTML Element)
      // ev は MouseEvent
      alert(this);
    };
    
    button.addEventListener("click", clickHandler, false);
[/code]

[code]

    <button id="click-target">Click me</button>
[/code]


CC BY-SA 3.0
2016-01-28T08:34:04.493
21436
2016-01-28T08:34:04.493
8771
21430
answer


javascriptのthisは関数の呼び出し方により変わります。  
すべて理解するのは難しいので、とりあえず、以下の3種類を覚えておけば問題ないと思います。

  1. new演算子を使用している  
→thisは作成されるインスタンス

(例)  
new func();  
new instance.func();

  2. new 演算子を使用せず、xxxx.func();という形  
→thisはxxxx部分

(例)  
instance.func();  
instance1.instance2.func();

  3. 関数そのまま実行  
→thisはグローバルオブジェクト(window)  
(厳格モード(use strict)ではundefined)

（例）  
func();

* * *

## サンプル

func関数を色々な呼び出しでthsに何が入るか確認するサンプル  

[code]

    function func(no){
       $('#log')
           .append('【'+ no +'】')
           .append('  '　+ (this instanceof func))
           .append('   '　+ typeof this)
           .append(' ⇒  ')
           .append(this.toString())
           .append('<br>');
    }
    
    // (0) 準備　funcを色々のものに代入
    // test1はObject
    // test2は関数オブジェクト
    // test3は関数
    var test1 = {};
    test1.func = func;
    
    var test2 = function(){ return 'test2_func'; };
    test2.func = func;
    
    function test3(){ return 'test3_func'; }    
    test3.func = func;
    
    // (1) new演算子の場合、thisは作成されたインスタンス
    new func('new[1]');
    new test1.func('new[2]');
    new test2.func('new[3]');
    new test3.func('new[4]');
    
    // (2) xxxx.funcという形の場合、xxxx部分
    test1.func('xxx.func[1]');
    test2.func('xxx.func[2]');
    test3.func('xxx.func[3]');
        
    // (3) 関数そのままの場合、window
    func('そのまま');
[/code]

[code]

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
    
    <div id='log'></div>
[/code]

* * *

## 例外１(bind)

すべての関数はbind関数が実装されており、この関数を用いる事でthisを固定化した関数を作成できます  
(古いブラウザーは実装されていません)

<https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Function/bind>

[code]

    function func(){}
    var obj = {};
    var bindFunc = func.bind(obj);  // bind関数で新たに関数が作成される
    bindFunc();                     // この関数を呼ぶと、func関数が実行され
                                    // thisはbind関数の第一引数のものとなる
    
[/code]

* * *

## 例外２(apply/call)

すべての関数はapply/call関数が実装されており、この関数を用いる事で関数の呼び出し時にthisを指定する事ができます  
（addEventListenerの第2引数で渡した関数のthisが変わるのも、この関数によるものだと考えられます）

<https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Function/apply>  
<https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Function/call>

[code]

    function func(){}
    var obj = {};
    func.apply(obj);                // 第一引数がthisとしてい使用される
    func.call(obj);                 // 第一引数がthisとしてい使用される
                                    // apply/callの違いは、実行する関数に引数があった場合の引数の渡し方が異なります
    
[/code]

* * *

最後に、例えばaddEventListenerに渡されたthisをclickHandlerのthisにする場合

[code]

    button.addEventListener("click", function(ev) {
      clickHandler.call(this, ev, "test");  // callの第一引数にaddEventListenerのthisを渡す
    }, false);
    
[/code]


CC BY-SA 3.0
2016-01-30T02:49:39.040
21497
2016-01-30T03:09:58.977
2016-01-30T03:09:58.977
4191
4191
21430
answer