「JavaScriptの理解を深めた人がさらにもう一歩先に進むための本」の感想・備忘録1

スポンサーリンク

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のクラスメソッド

  1. Object.is(val1, val2)
    同一かどうか。
    ===との違いは、NaN === NaNはfalseだがObject.is(NaN, NaN)はtrue
  2. Object.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文を使うことがほとんどである

コメント