[初心者] 最近のJavaScriptの文法をおさらいする

※この記事は専門学校の講義用に書いたものです

JavaScriptはもともとWebブラウザの上で動作するちょっとした処理を行うために登場しました。その後JavaScritの重要性が高まるにつれ、最近の言語に搭載されている機能が無いことに開発者の不満が募ります。そこで満を持して登場したのが新しいJavaScriptの仕様であるES6(ES2015)です。

今回はこのES6(ES2015)から登場した機能の一部をご紹介します。

変数

暗黒のvar時代

過去JavaScriptで変数を宣言する際にはvarが用いられてきました。しかしvarは取り扱いが非常に難しい…というよりは一般的なプログラミング言語のような宣言を行っていたわけではないためバグの温床となっていました。

次のコードを実行してみてください。

var foo = 100;

{
  var foo = 200;
}

alert(foo);
// console.log(foo);

この実行結果は200になります。

一般的なプログラミング言語の感覚で言えば、最終的な出力は100を予想しますよね。なぜなら4行目で変数fooを定義していますが、この場所は括弧内にあるため、ローカル変数として新たに定義されていると考えられるためです。つまりvarはローカル変数を定義するためのものではありません。また1行目と4行目の変数は全く同じ物を指し示しているため、変数を新たに定義しているとも言い難い物です。

letで変数を宣言しよう

そんな問題を解決するために登場したのがletです。先ほどのコードのvarの部分をletに変えて実行してみましょう。今度は一般的なプログラミング言語のような動作をしてくれたでしょうか。

let foo = 100;

{
  let foo = 200;
}

alert(foo);
// console.log(foo);

letは一般的な言語と同様に、同じ名前の変数を定義することはできません。実際に以下のコードを実行すると実行時エラーとなります。

let foo = 100;
let foo = 200;
VM171:2 Uncaught SyntaxError: Identifier 'foo' has already been declared

varでは新しく宣言したつもりが既存の変数を書き換えていたといった自体に陥りがちですが、letではそういった心配はなく非常に安全な状態でコーディングが行なえます。

constで定数を使おう

近年のJavaScriptでは、後から変更が不可能な変数(定数)の利用が可能になりました。定数を定義する際にconstを付けるだけです。次のように変更を行おうとすると実行時エラーとなります。

const foo = 100;
foo++;
VM86:2 Uncaught TypeError: Assignment to constant variable.

constは後から変更が不可能な点以外は、letと同じ動作をします。先ほどのコードを実行し挙動を確認してみましょう。

const foo = 100;

{
  const foo = 200;
}

alert(foo);
// console.log(foo);

constだけど書き換えできる!?

以下のようなクラスを用意し、インスタンスをconstで定義した変数に代入します。その後にメンバー変数を変更するメソッド(set())を実行しますが、これはエラーになりません

class Foo{
  constructor(name){
    this.name = name;
  }
  set(name){
    this.name = name;
  }
}

const foo = new Foo("たま");
foo.set("ぽち");

これはconstの仕様で、一度代入したオブジェクトの中身が変化してもエラーにはなりません。以下の例のように別のオブジェクト(ないし数値や文字列)などに置き換わった場合にはエラーとなります。

const foo = new Foo("たま");
foo = 100;
VM731:2 Uncaught TypeError: Assignment to constant variable.

letとconstの使い分け

ここまでを踏まえ変数を定義する場合には、以下の原則に従うことでより安全にコーディングを行うことができると言えます。

  1. 基本的にconstにする
  2. constではどうしようもない部分だけletにする

以下の記事も参照してください。 blog.katsubemakito.net

関数

アロー関数

以下のような無名関数(クロージャー)があったとします。「アロー関数式」を用いて書き換えることができます。こちらの方がタイプ数が少なくすっきりしますね。

// 以前からの書き方
const max = function (a, b){
  return( (a>b)?  a:b );
}

// 新しい書き方
const max = (a, b)=>{
  return( (a>b)?  a:b );
}

さらに引数が1つだけの場合は次のように省略することができます。

// 以前からの書き方
const add1 = function(a){
  return( a + 1 );
}

// 新しい書き方
const add2 = (a)=>{
  return( a + 1 );
}

さらにさらに、関数内の処理がreturn()だけの場合は最終的に次のようにすることもできます。

// 新しい書き方
const add3 = a => a + 1;

アロー関数式は必ずしも利用しなければならないわけではありません。自分に取って使いやすい書き方を行っていただければ大丈夫です。またアロー関数式はthisの扱いが異なるという注意点もあります。 developer.mozilla.org

引数のデフォルト値

他の言語では当たり前のようにあるこの機能ですが、JavaScriptでも現在は利用可能です。

function add(x, y=0){
  return(x+y);
}

console.log( add(10, 20) );
console.log( add(10) );

クラス

基本的な利用方法

過去のJavaScriptは変態的な方法でクラスを作成していましたが、現在では正式にclassが利用できます。

class Animal{
  constructor(name=null){
    this.name = name;
  }
  get(){
    return(this.name);
  }
}

const tama = new Animal("たま");
alert( tama.get() );
// console.log( tama.get() );
  • コンストラクタはconstructorメソッドで定義
  • プロパティを事前に宣言しておくことはできません
    • 例のようにconstructor内で初期化する
  • 現状メソッドやプロパティでpublic/private的な機能は用意されていません
    • public扱いになります

static

メソッド名の前に static をつけると、インスタンスを生成することなくメソッドの実行が可能になります。

class Util{
  static add(x, y){
    return(x+y);
  }
}

console.log(Util.add(30, 20));

getterとsetter

get, set構文を使ってgetterとsetterを定義することもできます。オブジェクト外からはプロパティで静的な値を操作しているように見えて、実際にはメソッドが動いているヤツです。

class Animal{
  constructor(name=null){
    this.name = name;
  }
  set name(name){
    this.name = name;
  }
  get name(){
    return(this.name);
  }
}

const tama = new Animal();
tama.name = "たま";   // setterが呼ばれる
alert( tama.name );  // getterが呼ばれる

継承

extendsで継承することができます。

class Animal{
  constructor(name=null){
    this.name = name;
  }
  get(){
    return(this.name);
  }
}

class Cat extends Animal{
  mynameis(){
    alert( this.name + "にゃー" );
  }
}

const tama = new Cat("たま");
tama.mynameis();

そのほかの新機能

テンプレート文字列

これまで文字列を結合する際には演算子(+)でがんばっていましたが、テンプレート文字列を使うことで簡単になりました。シングルコーテーションではなく、バッククォートな点に注意。

const str1 = 'Hello';
const str2 = 'World';

// これまでの書き方
alert(str1 + " " + str2);

// 新しい書き方
alert(`${str1} ${str2}`);

分割代入

例えば関数などから配列が返されるときに、各要素をそれぞれ別の変数に代入することができます。

function swap(a, b){
  return([b, a]);
}

const [a, b] = swap(10, 20);

alert(`${a} / ${b}`);
// console.log(`${a} / ${b}`);

参考ページ