読者です 読者をやめる 読者になる 読者になる

速習ECMAScript6 良いです

速習ECMAScript6: 次世代の標準JavaScriptを今すぐマスター!

速習ECMAScript6: 次世代の標準JavaScriptを今すぐマスター!

1年前に購入して放置してしまっていました。
 
実例と使い所を整理して記載してくれています。
blogやQitaなどにもES6/2015の記事はありますが、こちらは非常によくまとまっており
とりあえずこれ一冊読んでおけば良いという印象。
ある程度知識はあるので、移動時間の1時間ほどで読めました。
お値段も 250円とお安いです。

目次

Part1は省略していますが、ざっとこんな感じです。
PromiseやProxy、モジュールの説明もわかりやすく書かれています。

Part2:基本構文
 ブロックスコープを有効にする - let命令
 定数を宣言する - const命令
 整数リテラルの表現力を改善する - 2進数/8進数リテラル
 文字列リテラルへの変数/改行の埋め込みを可能にする - テンプレート文字列
  テンプレート文字列をアプリ仕様に加工する - タグ付きテンプレート文字列
 新たなデータ型Symbolとは?
  シンボルの用法
   (1)定数の値として利用する
   (2)非公開なプロパティを定義する
 配列/オブジェクトから個々の要素を抽出する - 分割代入
  分割代入の使い方
   (1)関数(メソッド)から複数の値を返したい
   (2)変数の値を入れ替える
   (3)名前付き引数を指定する
   (4)正規表現でマッチした部分文字列を抽出する
 配列を個々の変数に展開する - 展開演算子
 配列など反復可能なオブジェクトを列挙する - for...of命令

Part3:関数
 引数のデフォルト値を宣言する
  補足:必須パラメーターの表現
 可変長引数を利用する
 関数リテラルをシンプルに記述する - アロー関数
  アロー関数はthisを固定する(レキシカルなthis)
  注意:オブジェクトリテラルを返す時

Part4:組み込みオブジェクト
 非同期処理を簡便に処理する - Promiseオブジェクト
  非同期処理を連結する
  複数の非同期処理を並行して実行する
 オブジェクトの挙動をカスタマイズする - Proxyオブジェクト
 コレクション関連のオブジェクトを標準で提供 - Map/Setなど
  キー/値のセットを管理するマップ
  一意な値の集合を管理するセット
 Unicode対応の改善
  for...of構文でもサロゲートペアを認識
  Unicodeエスケープシーケンスが拡張
  サロゲートペアからコードポイントを取得/設定も可能に
  RegExpオブジェクトにuフラグが追加
 String/Array/Math/Objectなど組み込みオブジェクトのメソッドも拡充
  Stringオブジェクト
  Arrayオブジェクト
  Mathオブジェクト
  Numberオブジェクト
  RegExpオブジェクト
  Objectオブジェクト

Part5:オブジェクト指向構文
 オブジェクトリテラルをよりシンプルに表現する
  変数を同名のプロパティに設定する
  メソッドを定義する
  プロパティ名を動的に生成できる
 クラスを定義する - class命令
  匿名クラス(リテラル表現)も利用できる
  静的メソッドを定義する - static修飾子
  getter/setterも利用できる
  既存のクラスを継承する - extendsキーワード
 列挙可能なオブジェクトを定義する - イテレーター
  イテレーターを実装したクラスの準備
 列挙可能なオブジェクトをより簡単に実装する - ジェネレーター
  カウントダウンするジェネレーター
 アプリを機能単位にまとめる - モジュール
  モジュールの内容をまるごとインポートする
  デフォルトのエクスポートを宣言する
  補足:ブラウザー環境で動作するには?

 
以下、個人的に気になったことなど(主な内容などには触れていないです)。

const を誤解していた

基本constで変更するものはletみたいなノリで書いていましたが
constは、正しくは「再代入できない」であって、「変更できない」です。
なので以下のようなことが可能。

const data = [1, 2, 3];
cata[0] = 10;
console.log(data);

// Array [
//   10,
//   2,
//   3
// ]

2、8進数変換

Number関数で2、8進数変換が可能。
Number#parseIntは、16進数のみの認識なので、Number関数で統一するのが望ましい。

let num = 10;
// 10進数 => 8進数変換
console.log(num.toString(8));
// "12"

// 10進数 => 2進数変換
console.log(num.toString(2));
// "1010"

// 8進数 => 10進数変換
console.log(Number('0o12'));
// 10

// 2進数 => 10進数変換
console.log(Number('0b1010'));
// 10

テンプレート文字列の関数引き渡し

「関数名テンプレート文字列」の形式で関数に引き渡せる。

function _e(str) {
  if (!str) { return ''; }
  // 変換表ESCに従って、文字列を置き換え
  return str.replace(/[<>&"']/g, function(submatch) {
    const ESC = {
      '<': '&lt;',
      '>': '&gt;',
      '&': '&amp;',
      '"': '&quot;',
      "'": '&#39;'
    };
    return ESC[submatch];
  });
}

// 分解されたtemplatesとvaluesを順に連結(valuesは_e関数でエスケープ)
function escape(templates, ...values) {
  let result = '';
  for (let i = 0; i < templates.length; i++) {
    result += templates[i] + _e(values[i]);
  }
  return result;
}

// テンプレート文字列をエスケープ処理
let name = '<TOM & Jerry>';
console.log(escape`こんにちは、${name}さん!`);
// "こんにちは、&lt;TOM &amp; Jerry&gt;さん!"

Symbol

Symbol の使い所が分かっていなかったのですが、以下のような使い道があるようです。

定数の値

従来の定数。

var JAVASCRIPT = 0;
var RUBY = 1;

これだと、比較時に値である数値が利用できてしまう。
他の似たような値を持つ定数が出てきたときにわかりにくい。  
そこでSymbolを使うと、以下のように定義することができる。

const JAVASCRIPT = Symobl();
const RUBY = Symbol();

 
従来の定数の場合は値に意味があるので、正直この使い方は微妙な気がします。

非公開なプロパティ

これはなるほどと思いました。

// SECRETプロパティの名前でシンボルで準備
const SECRET = Symbol();
class MyClazz {
  constructor(secret) {
    this.data1 = 1;
    this.data2 = 2;
    // SECRETプロパティに値を設定
    this[SECRET] = secret;
  }

  // SECRETプロパティを利用したメソッド
  checkSecret(secret) {
    return this[SECRET] === secret;
  }
}

let c = new MyClazz(12345);
// メソッド経由ではSECRETプロパティにアクセスできる
console.log(c.checkSecret(12345));
// true

// SECRETプロパティへの直接アクセスは不可
console.log(c.secret);
// undefined

 
正確には非公開ではないです。

let idsym = Object.getOwnPropertySymbols(c)[0];
console.log(c[idsym]);
// 12345

for…of

あれ、これ認識してなかった。欲しかったやつやん。
プロパティ、prototype拡張を考慮しない for…in

let data = [1, 2, 4];
Array.prototype.hoge = function() {};
for (let d of data) {
  console.log(d);
}
// 1 2 4

Proxyオブジェクト

これは全然分かってなかった。
オブジェクトの標準的な操作を差し替えるためのオブジェクト。

let obj = { hoge: 'ほげ', foo: 'ふー' };
let proxy = new Proxy(obj, {
  get(target, prop) {
    return prop in target ? target[prop] : '?';
  }
});

console.log(proxy.hoge);
// ほげ
console.log(proxy.nothing);
// ?

構文

new Proxy(target, handler)

主なhandler methodは以下。
get, set, enumberate, iterate, deleteProperty

プロパティ名の動的生成

こんなことできたんだ。

let i = 0;
let data = {
  ['hoge' + ++i]: 15,
  ['hoge' + ++i]: 20,
  ['hoge' + ++i]: 25
};
console.log(data);
// Object {
//   "hoge1": 15,
//   "hoge2": 20,
//   "hoge3": 25
// }

組み込みオブジェクトの継承

extendsキーワードで継承可能。
独自の例外オブジェクトの実装に便利。

Black Card(CodeEval)

ババ抜きのような海賊ゲーム。

CHALLENGE DESCRIPTION:

You must have heard about pirates, their customs, pirates code, and the “black spot”. If a pirate is presented with a “black spot”, he is officially pronounced guilty, meaning he will soon be expulsed from the pirate brotherhood or even be dead.
We don’t have as strict rules as pirates have, and a person who receives a black spot simply leaves the game.
For example, we have a list of three players: John, Tom, Mary, and a number 5. Starting with the first player (in our case, it’s John), we start to count all players: John – 1, Tom – 2, Mary – 3, and then again starting from the first one John – 4, Tom – 5. As Tom gets number 5, he should leave. Now, we have John and Mary and start counting again. John gets number 5, so he leaves. Thus, the winner is Mary.

INPUT SAMPLE:

The first argument is a path to a file. Each line includes a test case with names of players and a number for a “black spot”. Players and a number are separated by a pipeline ‘|’.

John Sara Tom Susan | 3
John Tom Mary | 5

OUTPUT SAMPLE:

Print the name of a winner.

Sara
Mary

CONSTRAINTS:

  1. Always start counting from the first name in a list.
  2. Number of players can be from 3 to 10.
  3. Number of turns can be from 3 to 15.
  4. The number of test cases is 40.

My Code

#!/usr/bin/env ruby -w

def black_card(names, number)
  while names.size > 1
    names.delete_at((number - 1) % names.size)
  end
  names[0]
end

ARGF.each_line do |line|
  name_str, number_str = line.chomp.split(" | ")
  names = name_str.split
  number = number_str.to_i
  puts black_card(names, number)
end

Trick or Treat(CodeEval)

一定ルールで数値計算して平均値を求める問題。

CHALLENGE DESCRIPTION:

Everyone knows what Halloween is and how children love it. Children in costumes travel from house to house asking for treats with a phrase “Trick or treat”. After that, they divide the treats equally among all. This year, they collected tons of candies, and need your help to share everything equally. You know that children receive different number of candies depending on their costume: vampire gets 3 candies from one house, zombie – 4 candies, and witch – 5 candies. That is, three children in three different costumes get 3+4+5=12 candies from one house.

INPUT SAMPLE:

The first argument is a path to a file. Each line includes a test case with number of vampires, zombies, witches, and houses that they visited.

Vampires: 1, Zombies: 1, Witches: 1, Houses: 1
Vampires: 3, Zombies: 2, Witches: 1, Houses: 10

OUTPUT SAMPLE:

You need to print number of candies that each child will get. If the number is not integer, round it to the lower: for example, if the resulting number is 13.666, round it to 13.

4
36

CONSTRAINTS:

  1. Number of vampires, zombies, witches, and houses can be from 0 to 100.
  2. If the final number of candies is not integer, round it to the lower.
  3. The number of test cases is 40.

My Code

#!/usr/bin/env ruby -w

ARGF.each_line do |line|
  line.chomp.split(",").map { |pair| pair.split(":") }
  v, z, w, h = line.chomp.split(",").map { |pair| pair.split(":")[1].strip.to_i }
  children_number = (v + z + w)
  trick_number = h * (v * 3 + z * 4 + w * 5)
  puts trick_number / children_number
end