3
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【JavaScript】JavaScriptの 「this」とは 1

Last updated at Posted at 2020-12-06

※当方駆け出しエンジニアのため、間違っていることも多々あると思いますので、ご了承ください。また、間違いに気付いた方はご一報いただけると幸いです。

【JavaScript】JavaScriptにおけるクロージャーとは

↑こちらの記事に以下の通り記載しました。

「JavaScriptのスコープには、どの識別子がどの変数を参照するかが静的に決定されるという性質があります。
つまり、どこでinside関数を呼び出そうが、inside内のcountは、outside直下のcountを参照するということですね。

「this」という特別なキーワードだけは、呼び出し元によって動的に参照先が変わります。」

例えば、

function (){
  retrun this;
}

このような関数があった時、返却されるthisは呼び出し元によって変化します。

原則として、thisが参照するのは、ざっくりというと**「呼び出し元自体」**です。

まず、**「呼び出し先が異なる」**とはどういう意味なのか。

まず、以下のような内部処理にthisを含む関数があるとします。

function (){
console.log(this.name);
}

上記関数が、以下のようなhuman1, human2オブジェクトのgetNameプロパティーとして定義されているとします。それぞれ、プロパティーに
nameプロパティー(valueは文字列), getNameプロパティ(valueはメソッド(関数))が定義されています。


human1 = {
  name: "Taro",
  getName: function () {
    console.log(this.name);
  }
}

human2 = {
  name: "Ken",
  getName: function () {
    console.log(this.name);
  }
}

ちなみにイメージしやすいように、メソッドプロパティーを key : value で記載しましたが、

メソッドの定義部分は以下のように省略してもかけます。

human2 = {
  name: "Ken",
  getName() {
    console.log(this.name);
  }
}

話を戻しまして

それぞれのメソッドを呼び出してみます。

human1.getName();     ・・・※1
//Taro

human2.getName();     ・・・※2
//Ken

それぞれ、呼び出し元によって異なる文字列が返ってきました。

どのような動きとなっているのか。

※1の場合、getName()メソッドの呼び出し元は、 human1ですね。
つまり、メソッド内部のthisには、 呼び出し元自体の human1オブジェクトが参照されるわけですね。

イメージとしては、↓のような感じですね。

human1 = {
  name: "Taro",
  getName: function () {
    console.log(human1.name);
  }
}

再帰的に、呼び出し元オブジェクトが内部のthisから参照されます。

human2は

human2 = {
  name: "Taro",
  getName: function () {
    console.log(human2.name);
  }
}

ですね。

なぜ、thisから呼び出し元が参照されるかというと、イメージとしては呼び出し時に暗黙的に、仮引数に、呼び出し元オブジェクトを渡す感じです。
どういうことかといいますと、下のようなイメージです。

human1 = {
  name: "Taro",
  getName: function (x) { //暗黙的に呼び出元オブジェクトを仮引数xに渡す。
  this = x;  //thisにxを格納。
    console.log(this.name);
  }
}
console.log(human1.getName(human1));  //暗黙的に呼び出し元オブジェクトを引数に渡す。

thisを用いることによって、メソッド内部の定義を共通化できるのです。
これによりクラスからインスタンスを作った際に、それぞのインスタンスが持つインスタンス変数を参照することができます。

呼び出し元の種類によって、参照先が異なります。

場所 Thisの参照先
トップレベル(関数の外) グローバルオブジェクト
関数 グローバルオブジェクト
コンストラクター 生成したインスタンス
メソッド 呼び出し元のオブジェクト
イベントリスナー イベントの発生元
call/applyメソッド 引数で指定されたオブジェクト

原則は全て、呼び出し元がthisに入るということです。

call/applyメソッドについては、thisの参照先を指定することができます。

一つ一つ例を見ていきます。

###関数の外の場合

console.log(this);

//window

呼び出し元であるグローバルオブジェクト(windowオブジェクト)が参照されています。

###関数の場合

function test() {
  console.log(this);
};

test();

//window

同様に呼び出し元であるグローバルオブジェクト(windowオブジェクト)が参照されています。

ちなみに、グローバルオブジェクトがもつプロパティを参照した場合は、当然その値が参照されます。

function test() {
  console.log(this.document);
};

test();

//#document
//<html>
// <body>
//   <script src="practice.js"></script>
// </body>
//</html>

###コンストラクターの場合

class Member {
  constructor(name) {
    this.name = name;
  }
}

let member = new Member("Taro")
console.log(member);

//{name: Taro}

let member2 = new Member("Ken");
console.log(member2);

//{name: Ken}

まず、new演算子でインスタンスが作成されて、そのインスタンスがコンストラクターを呼び出します。
(その時の引数はmemberでは Taro)
thisには呼び出し元のmemberインスタンスが参照されているので

    this.name = name;

    //これはつまり

    member.name = "Taro"

ということで、memberインスタンスのnameプロパティにTaroが入ります。

###メソッドの場合
メソッドの場合は、上記の例通りなので割愛

###イベントリスナーの場合

<div id='checkThis'></div>

↑ の上にマウスが乗ったら、色が黄色く変わるというシンプルなコードです。

let elem = document.getElementById('checkThis');

elem.addEventListener('mouseover', function () {
  this.style.backgroundColor = "Yellow";
}, false);

 この場合、thisはイベント発生元である elem が参照されます。
よって、そのelemのスタイルに背景色黄色を設定し変色させます。

##call/applyメソッドの場合

call/applyメソッドの場合だけ、特殊でthisは呼び出し元が参照されますが、それを
異なるオブジェクトを指定してしまおうというものです。

human2 = { name: "Ken" };

human1 = {
  name: "Taro",
  getName: function () {
    console.log(this.name);
  }
}

human1.getName();

//Taro

human1.getName.call(human2);

//Ken

普通にgetName()を実行すると、当然human1がthisから参照されます。

しかし、callメソッドで引数にhuman2を渡すと、thisの参照先がhuman2となっています。

callメソッドとapllyメソッドの違いは、関数に渡す引数の渡し方の違いだけです。


func.call("thisに指定するオブジェクト", 引数, 引数, 引数)

//callは、funcに渡す引数を列挙

func.aplly("thisに指定するオブジェクト", [引数, 引数, 引数])

//apllyは配列で渡す。

続きはこちら
(【JavaScript】JavaScriptの 「this」とは 2 (thisの問題点と解決策))[https://qiita.com/sho_U/items/e10edd4c6c142fb37ea3]

3
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?