kindle本「JavaScriptの理解を深めた人がさらにもう一歩先に進むための本」のまとめ。
点数
85点
感想
前作の「何となくJavaScriptを書いていた人が一歩先に進むための本」に引き続き良書だった。
「thisの振る舞いが関数とメソッドで異なる」は勉強になった。 Object.assign()は使えそう。
「イテレータ」も勉強になったが、IEやchromeでは動作しないメソッドを使っていたのが残念。他にもいろいろ勉強になったが、実際に使うことは少ないかもしれない。
主な内容
Strictモード
StrictモードはECMAScript5(2009年12月)で追加された機能である。
- プログラムの先頭または関数スコープの先頭に記述する
- 変数宣言が強制される
- thisの振る舞いが変わる(後述)
- エラーが黙殺されなくなる
(プロパティ名・引数名の重複禁止、変数や関数へのdelete演算子使用禁止) - 制限済みオブジェクト・プロパティへの操作禁止
- argumentsの独立(後述)
- 8進数リテラルの禁止
- with文の禁止
- evalが独自スコープを持つ
Strictモード:thisの振る舞いが変わる
callメソッドなどでthisが渡された場合の挙動が異なる。
- 非Strictモード
プリミティブ値もオブジェクト型もすべてオブジェクト型となる。
(プリミティブ値はラッパーオブジェクトに変換される。) - Strictモード
暗黙的な変換は発生しない。
function nostrict() {
console.log(typeof this);
}
function strict() {
'use strict';
console.log(typeof this);
}
nostrict.call('foo'); // object
strict.call('foo'); // string
Strictモード:thisの振る舞いが変わる(その2)
非Strictモードではnull, undeinedを渡すと、thisはなぜかGlobalオブジェクトとして扱われる。
function nostrict() {
console.log(this === null);
}
function strict() {
'use strict';
console.log(this === null);
}
nostrict.call(null); // false
strict.call(null); // true
Strictモード:argumentsの独立
非Strictモードではarguments
と引数がお互いに影響し合う。
例えば、最初の引数の値を変更すればarguments[0]
にも反映され、その逆も同じである。
ただし、引数の値がオブジェクトの場合は参照渡しとなるため、arguments
にも同じオブジェクトへの参照が格納される。
function nostrict(val) {
val = 1;
console.log(val);
console.log(arguments[0]);
}
function strict(val) {
'use strict';
val = 1;
console.log(val);
console.log(arguments[0]);
}
nostrict(0); // 1 1
strict(0); // 1 0
関数から呼び出した時のthis
関数から呼び出した時のthisはGlobalオブジェクトを指す。
多くの場合、JavaScriptはブラウザで動作するので、windowオブジェクトを指すことになる。
function checkThis() {
console.log(this);
this.val = 100; // Globalオブジェクトへのメンバ追加
}
checkThis(); // Window
console.log(val); // 100
関数から呼び出した時のthis(その2)
次の例のようになると混乱しやすいが、関数かメソッドかを意識すれば簡単である。
checkThisはメソッドなのでthisはオブジェクト自身、innerCheckThisは関数なのでthisはGlobal、をそれぞれ参照します。
var obj = {
val: 'hoge',
checkThis: function() {
console.log(this.val);
this.val = 'fuga';
function innerCheckThis() {
console.log(this.val);
}
innerCheckThis();
}
};
obj.checkThis(); // hoge undefined
console.log(obj.val); // fuga
※上記の例のinnerCheckThis関数内でvalを参照したい場合は、checkThisメソッド内でvar self =this;
のようにthisを退避してあげる。
アロー関数から呼び出した時のthis
ES6で追加されたアロー関数の場合は、定義された場所のthisを常に参照するようになる。
これを使えばthisの退避をしなくてもすむが、まだ広く認知されていないため使わない方が無難。
var obj = {
val: 'hoge',
checkThis: function() {
var innerCheckThis1= function() {
console.log(this.val);
};
var innerCheckThis2= () => {
console.log(this.val);
};
innerCheckThis1(); // undefined
innerCheckThis2(); // hoge
}
};
obj.checkThis();
ES6で追加されたObjectのクラスメソッド
Object.is(val1, val2)
同一かどうか。
===との違いは、NaN === NaN
はfalseだがObject.is(NaN, NaN)
はtrueObject.assign(target, ...src)
Objectの複製・マージ。var copyObj = Object.assign({}, obj);
// コピーvar mergeObj = Object.assign(obj1, obj2);
// コピー
ES6で追加されたNumberのクラスメソッド
Number.isNaN(val)
NaNの場合のみtrue。
GlobalのisNaNは文字列やundefinedなどNaN以外でも数値でなければtrueを返すので注意。
Number.isInteger(val)
整数かどうか。少数はfalse。
ES6で追加されたArrayのクラスメソッド
Array.prototype.fill(val[, start[, end]])
arr.fill('A', 1, 3);
// 1,2番目に’A’をセット
ES6で追加されたSymbol
- SymbolはES6で追加された特殊な「値」
- typeofの結果はsymbolとなる
- 生成したシンボルはユニークな存在である(===で比較したら必ずfalseになる)
- オブジェクトのプロパティのキーに利用される(for…inでは列挙できない)
我々が日ごろコーディングするうえでは出番はないかもしれない。
イテレータとは
イテレータとはオブジェクトの中身を列挙するためのオブジェクトで、以下の2つの条件を満たしている必要がある。
- nextメソッドを持っている
- nextメソッドを実行するとdone, valueの2つのプロパティを持つオブジェクト(イテレータリザルト)を返却する
自前でイテラブルなオブジェクトを定義することは、ほとんどないはず。
ES6より配列がイテレータを持つようになったので、それを利用(for..of文)することはあるかもしれない。
イテレータの使い方
イテレータを持つオブジェクトは、[Symbol.iterator]()
メソッドを実行するとイテレータを返却する。
※本文ではvalues, keys, entriesの各メソッドを使用していたが、IEで動作しないため非推奨になっていた
※valuesメソッドに関してはchromeでも動作しない
var arr = [1, 2];
var itr = arr[Symbol.iterator]();
console.log(itr.next().value); // 1
console.log(itr.next().value); // 2
console.log(itr.next().value); // undefined
※ただし、普通はこんな使い方をすることはなく、for…of文を使うことがほとんどである