Reactのチュートリアルで紹介されていた比較的新しいJavaScriptの構文を学ぶ

皆さん、Reactやってますか? 自分も今の会社に入って初めて Reactを..というより新しいJavaScriptの構文に触れています。

新しいJavaScriptというのをもう少し説明すると、letとかconstとかからがもう新しいJavaScriptと位置づけています。(自分の中で)

自分がそもそもjQueryでDOM調整 みたいなぐらいのJavaScriptしか書いてきていなくて、大体Backend層より後ろ担当だったので、だいたい全てが物珍しかったりします。

ja.reactjs.org

という事で、今回は React のチュートリアルの中で紹介されている この3点 という所を紹介しつつ、自分の中の備忘録として記録しておきたいと思います。

このガイドでは時折比較的新しい JavaScript の構文を例の中で使用しています。ここ数年 JavaScript を使った仕事をしていなかったという場合は、この 3 点を理解すればだいたい理解したことになるでしょう。

Modern JS

gist.github.com

原文は上記のリンクからたどる事ができます。 以下に紹介する 3点を押さえると、Reactのチュートリアルを快適に読み進める知識が得られる、とあります。

1: let と const

We define variables with let and const statements. For the purposes of the React documentation, you can consider them equivalent to var.

変数をletconstで定義する。 Reactのドキュメントでは、varと同等と考えてよい。 みたいな感じですね。

では、Reactのドキュメント外では一般的にどうなのか調べてみたいと思います。

let

developer.mozilla.org

let 文はブロックスコープのローカル変数を宣言する。任意で値を代入して初期化できる、とあります。

特に varでの宣言と異なる点として 『let を使用することで、それが使用されたブロック、文または式にスコープを限定した変数を宣言することができます。これは var キーワードのように、変数をブロックスコープに関係なく、グローバルや関数全体のローカルに定義するようなことはありません。』 というのが明記されています。

上記をコードの具体例で説明すると、以下のような感じです。

function varTest() {
  var x = 1;
  {
    var x = 2;  // 同じ変数です!
    console.log(x);  // 2
  }
  console.log(x);  // 2
}

function letTest() {
  let x = 1;
  {
    let x = 2;  // 異なる変数
    console.log(x);  // 2
  }
  console.log(x);  // 1
}

let は ブロックスコープのローカル変数 という事から上記のような挙動になります。

また、グローバルオブジェクト上にプロパティを生成しません。 という点では以下の例を見る事で腹落ちの助けになりました。

var x = 'global';
let y = 'global';
console.log(this.x); // "global"
console.log(this.y); // undefined

その他にも、letとvarの違いとしては、もう一点あり、同じ関数やブロックのスコープ内で同じ変数を再宣言すると SyntaxError が発生する、というのがそれです。

if (x) {
  let foo;
  let foo; // SyntaxError が発生します。
}

他にも、var と let は、後者はパーサーが評価したときのみ値の初期化が行われる点が異なります。 この説明は上記リファレンスにあって以下のように解説されています。

var で宣言された変数が undefined の値で始まるのとは異なり、let の変数は定義が評価されるまで初期化されません。変数を宣言より前で参照すると ReferenceError が発生します。変数はブロックの先頭から初期化が行われるまで、「一時的なデッドゾーン」にあるのです。

function do_something() {
  console.log(bar); // undefined
  console.log(foo); // ReferenceError
  var bar = 1;
  let foo = 2;
}

しっかし、letとvarの違いを知れば知るほど、varの事知らずに使ってた・・! ってなりますね。

const

developer.mozilla.org

続いて const です。 これも、本当リファレンスをそのまま引用すると以下のような記述となります。

定数 (const) は、let キーワードを使って定義する変数と同じ、ブロックスコープを持ちます。定数の値は、再代入による変更はできず、再宣言もできません。

ブロックスコープと書いてあるものの、letとスコープは同一ではなくて 宣言された場所に応じて、グローバルまたはブロック内にローカルなスコープを持った定数を作成 という方針になるようです。

また const 宣言は必ず初期化が必要で、それをしないと SyntaxError が発生します。

また、const は 同じスコープ内の関数や変数と同じ名前にすることはできない、という制約があります。

2: JavaScript Class

We use the class keyword to define JavaScript classes. There are two things worth remembering about them. Firstly, unlike with objects, you don't need to put commas between class method definitions. Secondly, unlike many other languages with classes, in JavaScript the value of this in a method depends on how it is called.

class キーワードを使って、JavaScriptのクラスを定義します。 覚えておくべき事は2つあって、第一にオブジェクトとは異なり、クラスのメソッド定義の間にカンマを入れる必要が無いこと、もうひとつはクラスを持つ他の多くの言語と異なり、メソッド内のthisが、そのメソッドがどのように呼び出されるかに依存する事。 ってのが原文の内容ですね。

メソッド内のthisが、そのメソッドがどのように呼び出されるかに依存する事

PHPとかPythonって多分、呼び出され方に依存されないので、こういうの注意して見る必要がありそー。

3: arrow functions

We sometimes use => to define "arrow functions". They're like regular functions, but shorter. For example, x => x * 2 is roughly equivalent to function(x) { return x * 2; }. Importantly, arrow functions don't have their own this value so they're handy when you want to preserve the this value from an outer method definition.

⇒を使って「矢印関数」を定義することがあります。これは通常の関数に似ていますが、短いものです。たとえば、 x => x * 2 は、 function(x) { return x * 2; } とほぼ同じです。重要なのは、矢印関数は独自のthis値を持たないので、外部のメソッド定義からthis値を保持したい場合に便利です。 ってのが原文の内容。

矢印関数は独自のthis値を持たないので、外部のメソッド定義からthis値を保持したい場合に便利です

ここの説明が腹落ちしないので、もう少し掘り下げてみます。

アロー関数 ( arrow functions )

developer.mozilla.org

アロー関数式は、より短く記述できる、通常の function 式の代替構文です。とあります。

this, arguments, super, new.target を束縛しません。

とあるのでこれが今回の記述の意味なのでしょう。

まず、一口にアロー関数といっても省略を含めて記述方法が多岐にわたるようです。 これは、そもそも アロー関数ができた経緯として、関数を短く書きたい というのが発端の一つである為のようで、より短く書けるように発展してきた、という意味なのかなという気持ちですね。

後、これ見て「あー・・あのときのこれこういう意図で記述されてたのか」みたいな学びがありますね。

(param1, param2, …, paramN) => { statements }
(param1, param2, …, paramN) => expression
// 上記の式は、次の式と同等です: => { return expression; }

// 引数が 1 つしかない場合、丸括弧 () の使用は任意です:
(singleParam) => { statements }
singleParam => { statements }

// 引数がない場合、丸括弧を書かねばいけません:
() => { statements }

さて、アロー関数の導入の理由としては先程の話ともう一つあって、それが thisを束縛しない という所です。

もっと説明すると アロー関数自身は this を持たない、という事です。

公式ドキュメントには以下のように記載があります。

レキシカルスコープの this 値を使います。つまり、アロー関数内の this 値は通常の変数検索ルールに従います。このためスコープに this 値がない場合、その一つ外側のスコープで this 値を探します。

これによって、これまで 呼び出し方に依存していた thisの値がオブジェクト指向プログラミングをする上で煩わしくないようになっていきます。

所感

~いかがでしたか~ 取り敢えず雑にまとめてみました。

読めないが読める、みたいな感じになってきた感はあるのでまた階段を登った感があるぞ!!!!

という事で引き続きインプットと雑なアウトプットを続けていきたいと思います。