JavaScript

ES2015っぽいjsのメモ

More than 1 year has passed since last update.

const, let

let

変数の重複を許可しない

let msg;
let msg; // error

ブロックスコープを意識する

今まで

if(hoge) {
  var i = 5;
}

console.log(i); // => 5

これから

if(hoge) {
  let i = 5;
}

console.log(i); // => undefined

ES2015ではブロックスコープが使えるので

{
  let i = 5;
}

console.log(i); // => undefined

Switchでは注意が必要

switch(x) {
  case 0:
    let value = 'x:0'; // ここでvalueを宣言
  case 1;
    let value = 'x:1'; // => スコープはないのでここでエラー
}

const

再代入を許さない

class

class命令による指定

class double {
  // コンストラクタ
  constructor(a, b) {
    this.a = a;
    this.b = b;
  }

  // メソッド
  getSum() {
    return this.a + this.b;
  }
}

class式による定義

// 名前無し
var double = class {
  constructor(a, b) {
    this.a = a;
    this.b = b;
  }

  getSum() {
    return this.a + this.b;
  }
}

// 名前付き
var double = class double {
  constructor(a, b) {
    this.a = a;
    this.b = b;
  }

  getSum() {
    return this.a + this.b;
  }
}

注意

宣言した後のみに使える

巻き上げはできない、必ず宣言してから出ないとエラーになる

var p = new Polygon(); // => error
class Polygon{};

class内はstrictモードで実行される

constructor命令は二回以上できない

プロトタイプメソッド == プロパティ

get, setが使える

class double {
  constructor(a, b) {
    this.a = a;
    this.b = b;
  }

  get a() {
    return this.a;
  }

  set b(value) {
    value = this.b;
  }

  getSum() {
    return this.a + this.b;
  }
}

静的メソッド

インスタンス化されない。ユーティリティメソッドを作るときによく使う。

class double {
  constructor(a, b) {
    this.a = a;
    this.b = b;
  }

  static distance(a, b) {
    return Math.abs(a = b);
  }

  getArea() {
    return Math.pow(distance(this.a, this.b));
  }
}

let some = new double(2, 4);
some.getArea();  // 4
some.distance(2, 4); // => error
Area.distance(2, 4); // => 2

継承

class double {
  constructor(a, b) {
    this.a = a;
    this.b = b;
  }

  getArea() {
    return this.a * this.b;
  }
}

class doublex extends double {
  getGrid() {
    return this.a;
  }
}

superキーワード

constructorやメソッドに何か上書きしたいときに親クラスの変数や関数を呼び出す

class double {
  constructor(a, b) {
    this.a = a;
    this.b = b;
  }
  getArea() {
    return this.a * this.b;
  }
}

class doublex extends double {
  constructor(a, b, c) {
    super(a, b);  // a, b を親クラスを上書き
    this.c = c;
  }
  getArea() {
    return super.getArea() * this.c;
  }
}

classのexport, import

file-a.js
class double {
  constructor(a, b) {
    this.a = a;
    this.b = b;
  }
  getArea() {
    return this.a * this.b;
  }
}
file-b.js
import * from "./file-a.js";
// import double from "./file-a.js"; もOK
// import { sugoi as double } from "./file-a.js" だと
// let d = new sugoi(2, 3); で使える
let d = new double(3, 4);

復習

thisの参照先(復習)

  • トップレベル(関数の外) => global
  • function関数 => global(use strictではundefined)
  • call/applyメソッド => 引数にとったオブジェクト
  • イベントリスナー => イベントの発生元
  • コンストラクタ => 生成したインスタンス
  • メソッド => 呼び出し元のオブジェクト

call, applyメソッド(復習)

func.call(that, arg1, arg2...);
func.apply(that, args);

関数のthisをthatで置き換える. arg1, arg2, ... は引数、 argsは配列

オブジェクト内が参照できない

var data = {
  name: "takashi",
  kansu: function() {
    console.log(this.name); // takashiを期待
  }
}
data.kansu(); // => undefined!!

こういうときに bindが使える

data.kansu.bind(data);
data.kansu.call(data);

とするとうまくいく。

Arrow Function

アロー関数 - JavaScript | MDN

Arrow Functionは常に匿名関数

基本構文

(param1, param2, ... , paramN) => { statemantes }

// returnのみのときは{}を省略できる
(param1, param2, ... , paramN) => { return hoge }
(param1, param2, ... , paramN) =>  hoge


// paramが一つのときは()を省略できる
param => { statement };

// paramが0つのときは()は省略できない
() => { statement }

高等構文

// object リテラルを返すときは()で囲む
(param1, ... , paramN) => ({name: "takashi", age: 23});

// 残りの引数(...hoge), デフォルト引数がサポート
(params1 = defaultValue1, ...rest) => { statement };

// 分割代入
var f = ([a, b] = [1, 2], {x: c} = {x: a + b}) => a + b + c;
f(); // => 6

面倒なthisの扱いが良くなった

今まで

function Person() {
  // Person() のコンストラクタは、自身のインスタンスを `this` として定義します。
  this.age = 0;

  setInterval(function growUp() {
    // 非 strict モードでは、growUp() 関数は `this` をグローバルオブジェクトとして定義します。
    // これは、 Person() コンストラクタで定義された `this` とは異なります。
    this.age++;
  }, 1000);
}

var p = new Person();

だから、こうする必要があった

function Person() {
  var self = this; // `self` の代わりに `that` を選ぶこともあります。
                   // どちらかに統一するようにしましょう。
  self.age = 0;

  setInterval(function growUp() {
    // このコールバックは、期待されるオブジェクトの値を
    // `self` 変数で参照します。
    self.age++;
  }, 1000);
}

これから

function Person(){
  this.age = 0;

  setInterval(() => {
    this.age++; // |this| は person オブジェクトを適切に参照します。
  }, 1000);
}

var p = new Person();

解決したので…

  • strictモードを使ってもglobalを参照する
  • call, applyから呼び出しても無視する

他の特徴

argumentsを束縛しない

var argument = 42;

function foo() {
  var f = (i) => argument[0] + i; // argumentsはfooの引数。varで定義したものにならない
}

// ちなみに、...を使うと引数を受け取れる
var f = (...args) => args[0];

Promiseコンストラクタと thenメソッド

Promise, thenの基本

let asyncProcess = (value) => {
  // Promiseは resolve: 処理の成功を通知する関数とreject: 処理の失敗を通知する関数で
  return new Promise((resolve, reject) => {  
    setTimeout(() => {
     {value
       && resolve(value)
       || reject("入力が空")
     }
    }, 5000);
  });
}  

// 関数を実行してみる
// Promise.then(sucsess: function, resoluveで呼び出される, failure: function, rejectで呼び出される
asyncProcess('hoge').then(
  responce => {
    console.log(responce);
  },
  error => {
    console.log(error);
  }
});

Promiseの連結

asyncProcess('hoge').then(
    response => {
      console.log(response);
      return asyncProcess('hoge');
    }
)
.then(
    response => {
      console.log(response);
    }
);

一回読んで、その後またthenで呼び続けられる. Promiseを返す必要がある

すべての非同期処理が成功した場合にコールバック => Promise.all(関数の配列)

配列で入れる

Promise.all([
  asyncProcess('hoge'),
  asyncProcess('foo'),
  asyncProcess('bar')
]).then(
  response => {
    console.log(response);
  },
  error => {
    console.log(error);
  }
);

一つが完了したらコールバックする => Promise.race

Promise.race([
  asyncProcess('hoge'),
  asyncProcess('foo'),
  asyncProcess('bar')
]).then(
  response => {
    console.log(response);
  },
  error => {
    console.log(error);
  }
);

文字列処理

オブジェクト

変更点1: オブジェクト内でもthisが使えるようになった

let Area = {
  a: 1;
  b: 2;
  getArea(): {
    return this.a * this.b;  // ここでthisが使えるようになった
  }
}

今まではglobalになってた?(あとで検証)

変更点2: もう名前割り当ててたら省略できる

let name = "takashi";
let family = "kita";
let truename = { family, name };

変更点3: プロパティの動的生成

let i = 0;
let office = {
  name: "takashi-social-company",
  birth: new Date(2008, 2, 26),


}