Help us understand the problem. What is going on with this article?

ES6を少しだけモミモミしてみる

More than 3 years have passed since last update.

はじめに

先日勉強会に参加したところES6の話題が多かった印象を受けたので、勉強会で出てきた言葉を元に少し調べました。

js自体がまだちゃんと書けていない私としては、ES6を学ぶのはしんどいですが、いつか輝く為に少しずつ学ぼうと思います。

Template literal

Template literalを使うと、文字列の連結をスッキリかけるようになります。
+join()を使わなくてもいいのです!

やり方は、${}`(バッククオート)を利用して文字列の連結を行います。

バッククオート内の${}の中が評価され、その結果が置き換わります。

ES5
var str1 = 'スーパー';
var str2 = '合体';

var str = 'Template literalで文字列の' + str1 + 'の' + str2 + '!';

console.log(str);//Template literalで文字列のスーパーの合体!
ES6
var str1 = 'スーパー';
var str2 = '合体';

var str = `Template literalで文字列の${str1}の${str2}!`;

console.log(str); //Template literalで文字列のスーパーの合体!

式を評価して表示

${}の中には変数だけでなく式をいれることができます。

ES5
var str = 5 * 5 + "は" + (5 + 5 + 5 + 5 + 5) + "!";
ES6
var str = `${5*5}は${5+5+5+5+5}!`;

Default parameters

JavaScriptでの、関数の引数は、undefinedが初期値となります。

ES5では、引数の初期値を自由に設定することができなかった為、関数内で引数をチェックして、
undefinedなら初期値を設定するようなことをやってました。

ES6からは、下記例のように引数の初期値を設定できます。

ES5
function defaultParameters(a) {
  var b = arguments.length <= 1 || arguments[1] === undefined ? 'あるとうれしい!' : arguments[1];

  return a + b;
}

var str = defaultParameters('初期値が'); 
console.log(str); //初期値があるとうれしい!
ES6
function defaultParameters(a, b = 'あるとうれしい!') {
  return a + b;
}

var str = defaultParameters('初期値が'); 
console.log(str);//初期値があるとうれしい!

Rest parameters

今まで引数が可変の(いくつ渡ってくるかわからない)場合、argumentsを使用してやりくりしていましたが、Rest parametersを使用すれば、引数を可変長で受け取ることができます。

ES5
function rest() {
  for (var _len = arguments.length, values = Array(_len), _key = 0; _key < _len; _key++) {
    values[_key] = arguments[_key];
  }

  console.log(values);
}

rest(1, 2, 3);//[1,2,3]
ES6
function rest(...values) {
  console.log(values);
}

rest(1,2,3);//[1,2,3]

Rest Parametersのルールとして、引数の最後で渡す必要があります。
下記の場合、可変長引数の...valuesが第1引数として設定されている為、エラーとなります。

function rest(...values,value) {
  console.log(values);
}

下記ばOK。

function rest(value,...values) {
  console.log(values);
}

Spread operator

Spread operatorを使うと配列同士を結合したりする場合に便利です。

ES5
var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
var arr3 = [].concat(arr1, arr2);

arr1.push.apply(arr1, arr2);

console.log(arr1); // [0, 1, 2, 3, 4, 5]
console.log(arr3); // [0, 1, 2, 3, 4, 5]

ES6
var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
var arr3 = [...arr1,...arr2];

arr1.push(...arr2);

console.log(arr1); // [0, 1, 2, 3, 4, 5]
console.log(arr3); // [0, 1, 2, 3, 4, 5]

Destructuring

Destructuringは分割代入という、新しい変数代入の方法です。

配列で受け取る
var [a,b] = [1,2];
console.log(a,b)//1 2

var [a, b, ...rest] = [1, 2, 3, 4, 5];
console.log(a,b,rest)//1 2 [3,4,5]

関数の戻り値で受け取る
var [a,b] = (function(){return [1,2];})();
console.log(a,b)//1 2

一部省略や、デフォルト値を設定する
var [a,,[b,c],d=5] = [1,2,[3,4],5];
console.log(a,b,c,d);//1,3,4,5

オブジェクトで受け取る

var obj = {name:'太郎',sex:'男',age:30};
//必要なプロパティだけ代入
var {name:n,age:a} = obj;

console.log(n,a)//太郎 30

上記をES5で書くとこんな感じ。こっちのほうがわかりやすいような気がするのは、私が未熟なせいでしょう。。。

ES5
var obj = { name: '太郎', sex: '男', age: 30 };
var n = obj.name;
var a = obj.age;

console.log(n, a); //太郎 30

Blockscope

let

letを使うことで、関数スコープでなく、ブロックスコープを使用することができます。

letを使った場合
if(true){
  let a = 1;
  console.log(a);//1
}

console.log(a);//error

varを使った場合
if(true){
  var a = 1;
  console.log(a);//1
}

console.log(a);//1

ES5の場合は即時関数を利用してスコープをつくってました。

var a = 0;
(function(){
    var a = 1;
    console.log(a);//1
})();
console.log(a);//0

ES6はletを使うことでスコープの範囲がわかりやすくなりました。

var a = 0;
{
  let a =1;
  console.log(a);//1
}
console.log(a);//0

関数宣言をブロックスコープ内に定義

関数宣言もブロックスコープ内に定義することができます。

{
  function block(){return 1;}
  console.log(block());//1
  {
    function block(){return 0;}
    console.log(block());//0
  }
  console.log(block());//1
}

const

定数を定義することができます。

const a = 1;
console.log(a);//1

//再定義はエラーとなる
const a = 1;//error

//代入は無視される
a = 0;
console.log(a);//1

Arrow Function

アロー関数を使用することで、関数の定義が短くかける。

ES5
[1, 2, 3].map(function (v) {
  console.log(v);
});
ES6
//引数が一つの時には「(v)の()」を省略できる
[1,2,3].map(v=>{console.log(v);});

//下記でもOK
//[1,2,3].map((v)=>{console.log(v);});

Arrow Functionのthis

アロー関数のthisは、関数が実行されれたときに決まるのではなく、関数が定義されたときに決まる。

アロー関数を使うことで、selfとか_thisとかを使わないくて済むようになる。

function Myfunc(){  
  this.name = '太郎';
  setTimeout(()=>{
    console.log(this.name);//太郎
  })
}

new Myfunc();

従来のfunctionで定義した場合

function Myfunc(){

  this.name = '太郎';

  setTimeout(function(){
    //thisはwindowを参照する
    console.log(this.name);//undefined
  },100)
}

new Myfunc();

Async関数(ES7)

async、awaitを使うと非同期処理を、まるで同期処理を書いているように書けます。

下記の例のように、awaitを追加した関数は、その処理が終わるまで次の処理に移りません。

awaitを使う場合は、awaitを使う関数をasync functionをにする必要があります。

※このあたりまだちゃんと理解できていない為、記載の表現に誤りがあるかも。。。

function asyncGet(req, wait){ 
  return new Promise(
    resolve => setTimeout(function(){resolve(req)}, wait)
  );
}

async function test(){
    console.log(await asyncGet("リクエスト1", 1000));
    console.log(await asyncGet("リクエスト2", 100));
    console.log(await asyncGet("リクエスト3", 3000));
    console.log(await asyncGet("リクエスト4", 200));

    //リクエスト1
    //リクエスト2
    //リクエスト3
    //リクエスト4
};

test();

いままでは下記のように書いてました。
上記にくらべると冗長な感じがしますし、
async、awaitを使ったほうがコードの見通し良くなった気がします。

function asyncGet(wait){ 
  return new Promise(
    resolve => setTimeout(function(){resolve()}, wait)
  );
}

function test(){
   asyncGet(1000)
   .then(function(){
    console.log("リクエスト1");
     return asyncGet(1000);
   })
   .then(function(){
      console.log("リクエスト2");
     return asyncGet(100);
   })
    .then(function(){
      console.log("リクエスト3");
     return asyncGet(3000);
   })
    .then(function(){
      console.log("リクエスト4");
     return asyncGet(200);
   });
};

test();

終わり

ES6からはClassも使えるようになり、色々やれることが増えるようです。
記載の内容以外にも沢山便利な機能があるようなので、今後も調べていこうと思います。

nogson
へっぽこデザイナーです。
https://satofaction.net/
willgroup
個と組織をポジティブに変革する「チェンジエージェントグループ」
https://willgroup.co.jp
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away