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

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

新規登録して質問してみよう
ただいま回答率
85.48%
オブジェクト

オブジェクト指向において、データとメソッドの集合をオブジェクト(Object)と呼びます。

オブジェクト指向

オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

JavaScript

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

Q&A

解決済

2回答

1545閲覧

javascript this

koko122102

総合スコア39

オブジェクト

オブジェクト指向において、データとメソッドの集合をオブジェクト(Object)と呼びます。

オブジェクト指向

オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

JavaScript

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

1グッド

1クリップ

投稿2021/11/10 15:04

javascriptのthisについて質問です。
Accordionというクラスの中にある、openAccordionというメソッド内でthisを呼ぶと、クリックした要素が呼び出される、sumというメソッド内でthisを呼ぶとAccordionが呼びだされる、ということが理解できません。

クラスのメソッド内でthisを呼ぶとwindowオブジェクトが呼び出されるという認識でしたが違うのでしょうか。また、addEventlisnerのclickで呼び出される関数内でthisを呼んだら必ずクリックした要素が呼び出されるという事でしょうか。
長々としていて大変恐縮ですが、ご教授お願いいたします。

※constructor関数内でthisを呼ぶと、Accordionが呼び出されるのは理解できます。

html

1<!DOCTYPE html> 2<html lang="en"> 3<head> 4 <meta charset="UTF-8"> 5 <meta http-equiv="X-UA-Compatible" content="IE=edge"> 6 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 7 <title>Document</title> 8 <link rel="stylesheet" href="style.css"> 9</head> 10<body> 11 12 <div class="accordion"> 13 <p>Q1.なんでピノのアイスって売れていると思いますか。</p> 14 </div> 15 <div class="accordion-answer"> 16 <p>A1.知りません。</p> 17 </div> 18 <div class="accordion"> 19 <p>Q2.なんでピノのアイスって売れていると思いますか。</p> 20 </div> 21 <div class="accordion-answer"> 22 <p>A1.知りません。</p> 23 </div> 24 25 26 27 28 <script src="main.js"></script> 29</body> 30</html>

js

1 2document.addEventListener('DOMContentLoaded',function(){ 3 4 class Accordion{ 5 constructor(){ 6 7 let accordion = document.querySelectorAll(".accordion"); 8 let content = document.querySelectorAll("p"); 9 accordion = [...accordion]; 10 content = [...content]; 11 console.log(this); 12 13 for(let i = 0; i < accordion.length; i++){ 14 accordion[i].addEventListener('click',this.openAccordion,false) 15 } 16 } 17 18 openAccordion(){ 19 console.log(this); 20 } 21 22 sum(){ 23 console.log(this); 24 } 25 } 26 27 const acd = new Accordion(); 28 29 30 acd.sum(); 31 32}); 33
miyabi_pudding👍を押しています

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

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

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

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

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

hoshi-takanori

2021/11/11 12:14

this.openAccordion() として呼んだ場合は this が渡されるけど、var f = this.openAccordion; f() とした場合は this が渡らないってことでは。 (addEventListener の引数に this.openAccordion を渡すってことは、いったん this.openAccordion を変数に入れてそれを呼び出すのと同等です。)
guest

回答2

0

ベストアンサー

ルールはわりとシンプルです。アロー関数のケースを除くと、

  • foo.bar() と呼んだ場合、bar() 実行中は foothis となる。
  • barbind(foo) の結果なら、bar() と呼んだ場合は foothis となる。
  • bar.call(foo)bar.apply(foo, []) と呼んだ場合、bar() 実行中は foothis となる。
  • そうではない場合、bar() と呼んだときは、非strictモードでは window などグローバルオブジェクトがthis となる。strict モードでは thisundefined になる。
  • addEventLisetner() など、コールバックするAPIの場合、コールバック内のthisはAPIの仕様を参照する必要がある

コールバックをどう呼ぶかはAPIを使う側からは見えないため。たいていは bind() した結果を渡すことで変更することができる)

「どう呼ばれるか」が重要です。

accordion[i].addEventListener('click',this.openAccordion,false)

このコードの場合、this.openAccordionopenAccordion 関数を実行していないので、addEventListener() の仕様に従いイベントターゲットの要素が this になります。thisAccordion クラスのインスタンスになって欲しい場合は、this.openAccordion.bind(this) を渡します。

投稿2021/11/10 23:31

編集2021/11/11 00:35
int32_t

総合スコア20850

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

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

0

本質問は、JavaScriptにおける、thisの厄介さを顕著に表しているように思います。

解説を試みます。

クラスのメソッド内でthisを呼ぶとwindowオブジェクトが呼び出されるという認識でしたが違うのでしょうか。

違います。
束縛されたthisつまりは、クラスのインスタンス自身を参照します。
クラスメソッドではない、functionを使用し、ルートで定義し、
ルートで実行をした場合は、実行時におけるthisが参照されるため、
Windowオブジェクトが参照されますが、
クラスは、JSにおいては、途中から導入された、糖衣構文のため、
thisのややこしい仕様を、他のクラスベースの言語のように使用できるよう、導入されたと思われる)
おそらく、暗黙的にクラスメソッドは、bindメソッドを使っている状態、もしくはアロー関数を使い、thisをインスタンス自身に束縛していると思われます。
(JSは、thisは、束縛しないと、実行時のthisを参照してしまうため、
クラスベースのクラスメソッドのような仕様には非常にしずらい)

また、addEventlisnerのclickで呼び出される関数内でthisを呼んだら必ずクリックした要素が呼び出されるという事でしょうか。

はい、これはその通りで、
クラスメソッドとして、そのままインスタンスのopenAccordionを実行すれば、
インスタンス自身を参照しますが、
addEventlisnerclickは、逆に、要素をthisとして扱った方が、
さまざまな実装がしやすいのでしょう。
暗黙的には、thisを束縛せずに、
callなどの、thisを要素に置き換えて実行するような仕様としているものと思われます。

投稿2021/11/10 16:51

miyabi_takatsuk

総合スコア9528

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

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

raccy

2021/11/10 23:17

色々と間違っているのですが、とりあえずの指摘として、普通のメソッドの書き方をしても、暗黙的にbindしたりアロー関数になったりしません。
miyabi_takatsuk

2021/11/11 00:46 編集

コメント、ご指摘、ありがとうございます。 今回は、そもそも、根本的に間違っていると思われるので、直しようがなく、 そのまま回答残しておこうと思います・・・。 (全部書き直しになりそうで、それなら、正答が出ているので、それを見て勉強し直します)
Lhankor_Mhy

2021/11/11 01:51

ごめんなさい。0まではスコアを下げます。 ところで、今 [0,1,2].map(console.log) を試したら普通に動作したんですが、以前はエラーだったような……?
miyabi_takatsuk

2021/11/11 02:08 編集

Lhankor_Mhyさん > 逆にありがとうございます。 回答消すのも簡単にできないですからね 汗 なんでしょう、ブラウザはなんですか?? (ブラウザじゃなかったらすみません)
Lhankor_Mhy

2021/11/11 02:22

Chrome でも Firefox でもエラーが出なかったんですよね。 以前は this 参照関係のエラーになっていたと記憶しています。内部仕様が変わったんですかね?便利になったからいいんですが。
miyabi_takatsuk

2021/11/11 02:30

うむむ、なるほど。 ブラウザ間で共通ということは、勧告あったのかな… 勧告あったとしてもブラウザ実装のズレもあるかと思いますが。 とかく、JSのthisは良い意味でも悪い意味でも面白いですね。
maisumakun

2021/11/11 02:31

Consoleのspecでは、内部処理としてthisを使用していないですので、各ブラウザがそれに沿ってthisなしでconsoleを呼べるようにしているようです。 https://console.spec.whatwg.org/
Lhankor_Mhy

2021/11/11 02:40

ほんとですね、ありがとうございます。 じゃあ、私の記憶違いか、Firefox の実装上の変更があったのかもですね。(記憶違い、というのが一番ありそう)
miyabi_takatsuk

2021/11/11 02:51

maisumakunさん > ありがとうございます! そうか、もともとthisを使用しない仕様ってことですね。 Lhankor_Mhyさん > こんな仕様じゃなかったけ、とか、確か現象見たことが・・・とか、 記憶違い、あったりしますよね、、、 私は鳥頭なので、しょっちゅうありますがw
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問