個人的なメモ。ときどき追記していく。
テンプレートリテラル
テンプレートリテラル(`hoge`
)を使用することで、特殊文字のエスケープや連結演算子の記述などが不要になる。
また、テンプレートリテラル内では、${variable}
で変数をそのまま記述することができる。
ES5
var name = "hoge";
var age = 13;
console.log("My name is \"" + name + "\" and I'm " + age + " years old.");
// My name is "hoge" and I'm 13 years old.
ES6
var name = "hoge";
var age = 13;
console.log(`My name is "${name}" and I'm ${age} years old.`);
// My name is "hoge" and I'm 13 years old.
アロー関数
ES5における関数宣言
ES5における関数宣言の方法は3種類存在する。
通常のfunction命令
function str(arg1, arg2) {
console.log('hoge');
}
Functionコンストラクター(あまり使用しない)
var str = new Function("arg1", "arg2", "console.log('hoge')");
関数リテラル(匿名関数を利用)
var str = function(arg1, arg2) {
console.log('hoge');
}
アロー関数の宣言
ES6では、アロー関数を利用することで関数リテラルをシンプルに記述できる。
なお、関数リテラルとは、後述のthis
の挙動が異なる。
var str = (arg1, arg2) => {
console.log('hoge');
}
アロー関数は、引数が1つの場合に限って、
var str = arg1 => console.log(arg1);
のように引数の()
を省略して書くことができる(引数が0個の場合は省略できない)。
また、上記の例のように1行に収まる場合、{}
も省略してよい。
アロー関数がオブジェクトリテラルを返す場合は、
var str = func => ({ id: '8' });
のように、全体を()
で囲う必要がある。
thisの挙動の違い
(1) メソッド呼び出し
var obj = {
value: 10,
show: function() {
console.log(this.value); // 10
}
}
obj.show();
オブジェクトに関連づけられた関数であるメソッドにおいては、this
は呼び出し元となるオブジェクトを意味する。
すなわち、上記の場合のthis
はobj
であり、this.value
はobj.value
を指す。
(2) 関数呼び出し
function func() {
var value = 2;
console.log(this.value) // undefined
}
func();
上記のように通常の関数を呼び出した場合には、(オブジェクト内で宣言した関数だとしても)this
はグローバルを指す。
このため、関数内のthis.value
は関数内のvalue値を参照せず、グローバルのvalue値(未定義)を見る。関数外にvar value = 1;
と書けば、結果は1
となる。
(3) コンストラクタ呼び出し
function Obj(value) {
this.value = value;
}
var obj = new Obj(0);
console.log(obj.value); // 0
コンストラクタでインスタンス化している場合、this
は生成されたインスタンスを指す。
今回の場合は、this
はobj
を指す。
(4) apply, call, bind
var obj = {
value: 1,
show: function() {
console.log(this.value);
}
};
var newObj = {
value: 5
};
obj.show(); // 1
obj.show.call(newObj); // 5
obj.show.apply(newObj); // 5
call``apply
メソッドを用いることで、第1引数の値をthisに束縛することができる。
すなわち、newObj = { value: 5 }
がthis
であるため、this.value
の値は5
に変化する。
第2引数以降は関数に渡される引数。call
は順番通りに、apply
は配列として渡す。また、bind
メソッドを使った場合は以下のように書く(this
を束縛した関数を生成する)。
var newFunc = obj.show.bind(newObj);
newFunc();
(5) アロー関数 [ES6〜]
アロー関数では、関数が宣言されたときのスコープにthis
が自動的に束縛される。
var obj = {
value: 10,
//メソッド呼び出し
show: function() {
console.log(this.value); // 10
// 関数呼び出し
function show_01() {
console.log(this.value); // undefined
}
show_01();
// アロー関数
var show_02 = () => {
console.log(this.value); // 10 thisはobjを参照
}
show_02();
}
}
obj.show();
変数の宣言
var, let, const
ES6では、従来のvar
に加えて新しくlet``const
というシンタックスを使えるようになった。
let
…… 変数の再宣言ができない
const
…… 変数への再宣言と再代入ができない
var
を使った変数宣言では、例えば以下のような場合でもエラーを引き起こさない。
var x = 10;
x = 15;
console.log(x); // 15
var x = 12;
console.log(x); // 12
let
を用いた場合、以下のように一度宣言された変数と同名の変数を再度宣言することができない(変数への再代入はできる)。
let x = 10;
x = 15;
console.log(x); // 15
let x = 12; // Identifier 'x' has already been declared
また、const
は定数のような役割をしており、一度初期化した変数への再代入が認められない。
const x = 10;
console.log(x); // 10
x = 15; // TypeError: Assignment to constant variable.
ただし、const
で参照型(オブジェクトや配列)を宣言した場合、参照自体の差し替えはできないが、参照の中身の変更は可能である。
var ary1 = () => {
const aryFalse = [1, 2, 3];
aryFalse = [4, 5, 6]; // Error
console.log(aryFalse);
}
ary1(); // Error
var ary2 = () => {
const aryTrue = [1, 2, 3];
aryTrue[1] = 10;
console.log(aryTrue);
}
ary2(); // [1, 10, 3]
変数のブロックスコープ
let``const
をifやforなど{}で囲まれたブロック内で宣言した場合、それらの変数をブロックの外側で参照することはできない。
if(true) {
var i = 0;
}
console.log(i); // 0
if(true) {
let j = 10;
}
console.log(j); // ReferenceError
if(true) {
const k = 100;
}
console.log(k); // ReferenceError
なお、ブロック外でlet``const
を用いて宣言した変数(定数)を、ブロック内から参照することはできる。
const i = 5;
if(true) {
sonsole.log(i); // 5
}
モジュール
ES5以前では、機能ごとに各JSファイルに分割して管理・開発することが基本的には出来なかった。しかし、ES6では、別のファイルをインポートすることができる。
(追記)名前空間パターンである
var obj = obj || {}
を利用して出来るらしい。
require
js/ ----- script.js
|
--- slider.js
といったファイル構成である場合、従来であればHTML上で
<script src="slider.js"></script>
<script src="script.js"></script>
と書いていたところを、
var slider = require(./slider.js);
とすることで、slider.js
をインポートできる(./slider
と記述してもよい)。
このように、require
を用いることで、ファイル自体を読み込むことができる。
(追記)requireはES5の頃からCommonJSの仕様として存在していたとのこと。ただし、ブラウザではいまだ(
browserify
等を用いた変換処理なしでは)未対応。
import/export
モジュールはある機能を実現するためのプログラムのかたまりのことで、別ファイルに渡す変数/関数などのまとまりのことを言う。
後述するクラスなど、モジュールを読み込む際は、import
とexport
を利用することで実現できる。
モジュールを1つだけ受け渡しする場合
モジュールの読み込み
import 'import先の名前' from 'ファイルのパス'
モジュールの出力
export default 'モジュール'
import Carousel from './carousel';
const carousel = new Carousel();
export default class Carousel {
constructor() {
this.calc();
}
calc() {
console.log(10);
}
}
モジュールを複数受け渡しする場合
出力側では受け渡ししたいものにexport
を付けておき、import側は
import {受け取り1, 受け取り2, ...} from 'ファイルのパス'
のように記述する。
import {multi, superMulti} from './multiply';
console.log(multi(5)); // 50
console.log(superMulti(6)); // 600
export const i = 10;
export function multi(x) {
return i * x;
}
export function superMulti(x) {
return i * x * 10;
}
なお、すべてのモジュールを受け渡しする場合、import側で
import * as 'オブジェクト名' from 'ファイルのパス'
と書けばよい。
上記の例の場合は、以下のように書く。
import * as lib from './multiply';
console.log(lib.multi(5)); // 50
クラス
クラスの宣言
ES5ではprototypeを利用して実現していたクラス定義を、ES6ではclass命令を導入することで書けるようになった。
ES5
var Add = function(arg1, arg2) {
this.arg1 = arg1;
this.arg2 = arg2;
};
Add.prototype.calc = function() {
return this.arg1 + ' + ' + this.arg2 + ' = ' + (this.arg1 + this.arg2);
};
var num = new Add(5, 8);
console.log(num.calc()); // 5 + 8 = 13
ES6
class Add {
constructor(arg1, arg2) {
this.arg1 = arg1;
this.arg2 = arg2;
}
calc() {
return this.arg1 + ' + ' + this.arg2 + ' = ' + (this.arg1 + this.arg2);
}
}
var num = new Add(5, 8);
console.log(num.calc()); // 5 + 8 = 13
クラスの継承
クラスの継承やオーバーライドは、super
を使って行えるようになった。
ES5(すでにAddを宣言している前提)
var AddSquare = function(arg1, arg2) {
Add.call(this, arg1, arg2);
};
Object.assign(AddSquare.prototype, Add.prototype);
AddSquare.prototype = {
calc : function() { // メソッドの省略不可
Add.prototype.calc.call(this);
},
calcSquare : function() {
this.pow = Math.pow(this.arg1 + this.arg2, 2)
return '(' + this.arg1 + ' + ' + this.arg2 + ')^2 = ' + this.pow;
}
};
var numSquare = new AddSquare(5, 8);
console.log(numSquare.calc()); // 5 + 8 = 13
console.log(numSquare.calcSquare()); // (5 + 8)^2 = 169
ES6(すでにAdd classを宣言している前提)
class AddSquare extends Add {
constructor(arg1, arg2) {
super(arg1, arg2);
}
calc() { // メソッドごと省略可
super.calc();
}
calcSquare() {
this.pow = Math.pow(this.arg1 + this.arg2, 2)
return '(' + this.arg1 + ' + ' + this.arg2 + ')^2 = ' + this.pow;
}
}
var numSquare = new AddSquare(5, 8);
console.log(numSquare.calc()); // 5 + 8 = 13
console.log(numSquare.calcSquare()); // (5 + 8)^2 = 169