Re:Start

いまはディレクターやってます

メンテナブルJavaScript 第II部 プログラミング実践より

この本はどんどん進めるにつれて内容が難しくなって行くのが特徴的でした。
こういう場合はやっぱり一度はちゃんと書きたいということで、ブログに起こしました。

メモ書き程度になってしまってすみませんが、特に見覚えのないものや、こういう風に書けたらなぁというところをピックアップしているので、全てではありません。

9章 設定データをコードから切り離す

9.3 設定データを格納するには

var config = {"MSG_INVALID_VALUE": "Invalid value"};
myFunc({"MSG_INVALID_VALUE": "Invalid value"});
// 呼び出しは、 config.MSG_INVALID_VALUE

10章 エラー処理

10.6 エラーの型

MyError(message) {
    this.message = message;
}
MyError.prototype = new Error();

自分でErrorを継承した型を定義しておけば、 typeof などで判定できるようになる

11章 所有していないオブジェクトを変更しない

パラメータを delete で消したり、メソッドを null で上書きするのは御法度

-> 静的プロパティでアラート出すか、docで回避するようにしよう

11.3.1 オブジェクトベース継承

/*
 Object.create(OBJECT) で、引数に対象のオブジェクトを渡す
 第二引数には、パラメータやオブジェクトを渡すことができる: 機能の追加など
*/

var person = {
    name: "Nicholas",
    sayName: function() {
        alert(this.name);
    }
}

var myPerson = Object.create(person);

myPerson.sayName(); // "Nicolas" が表示される

11.3.2 型ベースの継承

/*
 開発者が定義したコンストラクタ関数を使う時に最適
 instansof での比較もできるようになる
*/

function MyError(message) {
    this.message = message;
}
MyError.prototype = new Error();

// コンストラクタ継承
function Person(name) {
    this.name = name;
}
function Author(name) {
    Person.call(this, name); // コンストラクタを継承
}
Author.prototype = new Person();

11.3.3 Facadeパターン

/*
渡すのは、DOM要素で、
あらかじめ、使用方法を指定しておくインターフェースのような使い方ができる
 -> でも、すごく無理矢理に見えるんだけど、気のせいだろうか...
   最初作った人は想定していない使い方に見えなくもない??
*/

function DOMWrapper(element) {
    this.element = element;
}

DOMWrapper.prototype.addClass = function(className) {
    element.className += " " + className;
};

DOMWrapper.prototype.remove = function() {
    this.element.parentNode.removeChild(this.element);
};

// 使い方
var wrapper = new DOMWrapper(document.getElementById("my-div"));

// CSSクラスを追加
wrapper.addClass("selected");

// 要素を削除
wrapper.remove();

11.4 ポリフィル Polyfill

その他のオブジェクト変更と比べると、わずかばかり安全です。
すでにネイティブ実装が存在し、その実装を使えるからです。

利点:ネイティブ機能を持つブラウザだけをサポートする場合には、
ポリフィルの機能を用意に削除できる点です。
ポリフィルを使う選択をする場合、さまざまな観点から詳細に検討しましょう。
ある機能がネイティブのバージョンと可能なかぎり合致しているか確認し、
さらにその機能を検証するユニットテストがライブラリにあるかどうか、ダブルチェックしましょう。
ポリフィルの欠点は、不足機能が正確に実装されていないかもしれない点です。
メンテナンス生を改善するには、ポリフィルは避け、代わりに
既存のネイティブ機能の上にファサードを作りましょう。最高に柔軟になります。
柔軟性が特に重要になるのは、ネイティブ実装にバグがある場合です。

この場合、実装のバグと無縁ではいられないので、そのネイティブAPIを直接使いたくないはずです。

11.5 変更を妨げる

/*
PreventExtension
 :オブジェクトへのプロパティやメソッドの新規追加 禁止
 :既存の変更や削除 可能
seal
 :オブジェクトへのプロパティやメソッドの新規追加 禁止
 :既存の削除 禁止
freeze
 :オブジェクトへのプロパティやメソッドの新規追加 禁止
 :既存の変更や削除 禁止

isExtensible() 拡張できるかチェックする
*/
ver person = {
    name: "Nicholas"
};
// オブジェクトに鍵をかける
Object.preventExtension(person);
console.log(Object.isExtensible(person)); // false
person.age = 25; // strictモードでなければ落ちる

続いて、シールの場合

// オブジェクトに鍵をかける
Object.seal(person);

console.log(Object.isExtensible(person)); // false
console.log(Object.isSealed(person)); // true

delete person.name; // strictモードでなければ落ちる
person.age = 25; // strictモードでなければ落ちる

最後にフリーズの場合

// オブジェクトに鍵をかける
Object.freeze(person);

console.log(Object.isExtensible(person)); // false
console.log(Object.isSealed(person)); // true
console.log(Object.isFrozen(person)); // true

person.name = "Greg"; // strictモードでなければ落ちる
person.age = 25;      // strictモードでなければ落ちる
delete person.name;   // strictモードでなければ落ちる

12章 ブラウザ判定

12.1 ユーザエージェント判定

  • 必ずしも正確な値を返すわけではないので、極力使わない、頼らないことが望ましい。
  • 使う場合は、IE8よりも前とかそういうレベル
if(isInternetExplorer80rEarlier) {
    // IE8とそれ以前を処理
} else {
    // その他のブラウザを処理
}

12.2 特徴検出

/*
あるメソッドが使えるかどうか = 特徴 で判断する
*/

// Good
if(document.getElementById) {
    // 何か実行
}

// Good getElementById が出たばかりのころによく書かれたコード
function getById(id) {

    var element = null;

    if(document.getElementById) { // DOM
        element = document.getElementById(id);
    } else if (document.all) {    // IE
        element = document.all[id];
    } else if (document.layers) { // Netscape 4以下
        element = document.layers[id];
    }
}

12.3.4 特徴推定&ブラウザ推定

特徴検出で検証したメソッドで勝手にブラウザを判断して、よしとしないこと。
ブラウザは違っても、そのメソッドを持っている可能性はあるし、変更が必要なソースになってしまう!!

これらは極力避ける!最悪のプラクティス
  • 特定のブラウザの古いバージョンをターゲットにする場合のみ有効
  • 最新のブラウザや将来のバージョンをターゲットにしては行けない
  • 可能な限り、特徴検出を使う
    それが不可能なとき、ユーザエージェント判定を代替として使う
    ブラウザ推定はけして使わない

関連エントリ

この本

メンテナブルJavaScript ―読みやすく保守しやすいJavaScriptコードのための作法

メンテナブルJavaScript ―読みやすく保守しやすいJavaScriptコードのための作法