質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

4回答

2558閲覧

javascriptのthisが何を指しているか?

pato

総合スコア32

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

1クリップ

投稿2015/07/19 03:41

javascript

1<html> 2 <head> 3 <title>test</title> 4 <style type="text/css"> 5 div{ 6 width:500px; 7 height:300px; 8 border:1px solid blue; 9 } 10 </style> 11 </head> 12 <body> 13 14 <script type="text/javascript"> 15 16 function MyDiv(name){ 17 this.div = document.createElement("div"); 18 this.name=name; 19 this.div.textContent="このdiv要素は"+name+"です"; 20 document.body.appendChild(this.div); 21 22 this.div.addEventListener('click',function(e){ 23 console.log(this.name); 24 },false); 25 } 26 27 var div1 = new MyDiv("div_1"); 28 </script> 29 </body> 30</html>

javascriptで動的にdiv要素を作って、それをクリックしたらそのdiv要素のnameプロパティの値がコンソールに表示される、というスクリプトなんですが、実行すると結果は「undefined」になります。
「イベントを元に関数を呼び出した場合、関数内の this はイベントの発生元の要素を指す」と認識していました。この場合addEventListenerの第2引数の関数内のthisは、
イベント発生元であるインスタンスdiv1を指すのでコンソールには「div_1」と表示されるのではないかと思うのですが、なぜ結果がundefinedなのでしょうか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

JavaScriptのthisは関数が実行される環境での自分自身です。
これは特別な変数で、クロージャの変数束縛から除外されています。
addEventListenerに引数として引き渡されたfunction(e) {...}は、
イベントが実行されたあとに実行される関数ですが、
その実行環境はfunction MyDiv(name){...}内では無いため
(rikさんが示したとおり、今回はdivオブジェクトが実行環境になります)、
ここでのthisfunction MyDiv(name){...}内のthisが異なるものになります。
このように、コールバック等で関数に関数を渡す場合は、
その渡された関数の実行環境はつねに意識する必要があります。
また、Array.prototype.map()のようにthisが何になるかを指定することが
できる場合もあります。

で、今回の場合どうするかというと、方法は主に三つです。

  1. Function.prototype.bind()thisを束縛する。
    bind()を使うと関数の実行環境を束縛できます。

    JavaScript

    1this.div.addEventListener('click', function(e) { 2 console.log(this.name); 3}.bind(this), false);
  2. ファットアロー=>を使用する。(ECMAScript2015から)
    ファットアローで作成した関数はthisも変数束縛してくれます。
    策定されたばかりのECMAScrpit2015からの新機能であるため、ほとんどのブラウザで
    まだ対応していません。※ Firefoxはすでに対応しているようです。
    実際に使うにはbabel等でECMAScript5に変換する必要があります。

    JavaScript

    1this.div.addEventListener('click', (e) => { 2 console.log(this.name); 3}, false);
  3. 適当な変数を作ってに入れる。
    this以外の変数であれば変数束縛により、クロージャの関数内でも同じものを示すよう
    になります。
    ですので、適当な変数_thisとかに入れておいてから使います。
    babel等でファットアローを変換したときもこのようになります。

    JavaScript

    1var _this = this; 2this.div.addEventListener('click', function(e) { 3 console.log(_this.name); 4}, false);

投稿2015/07/19 08:35

編集2015/07/20 15:22
raccy

総合スコア21735

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

this.name=name;
ではなく、
this.div.name=name;
の間違いでしょうか?

投稿2015/07/19 03:55

rik

総合スコア1151

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

pato

2015/07/19 04:22

あるサイトのサンプルなんですが、そのサンプルでは this.name=name; となってます。質問に「div要素のnameプロパティ」と書いてしまいましたが、MyDivはコンストラクタなので、そのコンストラクタから生成されたインスタンスdiv1のnameプロパティの値、と書くべきでしたかね。
guest

0

ベストアンサー

(ちょっと思考まとめ不足で自信ないのですが)

関数をコンストラクタ呼び出しした場合のthisは生成されるオブジェクトになるから
MyDiv内のthisはこれから生成されるオブジェクトを参照してると思います。
参考

var div1 = new MyDiv("div_1");
そしてこのdiv1に入っているのはHTMLのdivではなく、MyDivのオブジェクトかも。
イベントリスナーは生成したdivにつくけど、そのdivにはthis.nameは無いので
undefinedになっているのではないでしょうか?

投稿2015/07/19 08:21

hirohiro

総合スコア2068

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

コードに追記して実行してみました。

html

1<html> 2 <head> 3 <title>test</title> 4 <style type="text/css"> 5 div{ 6 width:500px; 7 height:300px; 8 border:1px solid blue; 9 } 10 </style> 11 </head> 12 <body> 13 14 <script type="text/javascript"> 15 16 function MyDiv(name){ 17 this.div = document.createElement("div"); 18 this.name = name; 19 this.div.name = 'div_2'; 20 this.div.textContent = "このdiv要素は" + name + "です"; 21 document.body.appendChild(this.div); 22 23 this.div.addEventListener('click',function(e){ 24 console.log(this.name); 25 console.log(div1.name); 26 },false); 27 } 28 29 var div1 = new MyDiv("div_1"); 30 </script> 31 </body> 32</html>

div_2
div_1
と表示されます。
つまり、this.div.addEventListener内のfunction(e){...}では
thisは div を示すもので、MyDiv を示すものではないという事だと思います。
私はthisは混乱のもとですので極力使わない様にしていますし使わなくても何とかなります。
使った方がいいという方もおられるでしょう。
「javascript this」で検索すると詳しく解説しているサイトが見つかります。

投稿2015/07/19 05:35

rik

総合スコア1151

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

pato

2015/07/20 03:32

解答ありがとうございました。MyDivクラスのインスタンス(オブジェクト)と、createElementメソッドで返されて変数divに代入されるオブジェクトは別のものなんですよね。その違いがわかっていませんでした。頂いたコードだとその違いがよくわかります。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問