ホーム > タグ > JavaScript

JavaScript

JavaScript 第 5 版 9 章まとめ

だいぶ間が空いてしまいましたが、サイ本の続きです。
今回は 9 章。自分がちゃんと身につけたいと思っていたプロトタイプやコンストラクタの内容。
ちゃんと理解して実践に活かしたい。

9 章 クラスとコンストラクタとプロトタイプ

9.1 コンストラクタ

  • new 演算子と一緒に使うための関数をコンストラクタ関数という。
  • コンストラクタ関数が呼び出されるとそのオブジェクトが this キーワードの値になる。

9.2 プロトタイプと継承

  • メソッドとして関数を呼び出すと、関数を呼び出す時に使われたオブジェクトが this キーワードの値になる。
  • すべての JavaScript オブジェクトには、プロトタイプオブジェクトというオブジェクトへの参照が含まれ、プロトタイプオブジェクトからプロパティを継承する。
  • new 演算子を使ってオブジェクトを生成すると、そのオブジェクトに対してプロトタイプを設定する。
  • 継承はプロパティの値を探す処理の一部として自動的に行われる。
  • プロパティはプロトタイプからコピーされるのではなく、オブジェクトのプロパティであるかのように見える。
  • プロトタイプオブジェクトを使用することで、たくさんのオブジェクトがプロパティを継承するので、メモリを節約できる。
  • また、プロパティの値を探す処理でプロトタイプを参照するので、オブジェクトを生成した後にプロトタイプを追加した場合でも継承できる。
  • よって、そのクラスのすべてのオブジェクトに対して同一のプロパティを定義する場合(メソッドなど)に限って使用するのが適切である。

// コンストラクタ関数
function Rectangle(width, height) {
  this.width = width;
  this.height = height;
}

// プロトタイプオブジェクトを生成
Rectangle.prototype.area = function() {
  return this.width * this.height;
}

var r = new Rectangle(2, 3);
r.width;  // 2
r.area();  // 6 が返る。プロトタイプオブジェクトから継承されている。
for(var o in r) {
  alert(o);  // width, height, area。for/in でも調べられる。
}
r.hasOwnProperty("width");  // r 直属のプロパティなので true
r.hasOwnProperty("area");  // r から継承されたプロパティなので false

9.2.1 継承プロパティへのアクセス

  • 1 つのプロトタイププロパティが複数のオブジェクトによって継承される。よってプロパティの値の継承が有効なのは読み出す時に限られる。
  • プロトタイプオブジェクトのプロパティに値を書き込もうとすると、元のオブジェクトに新しいプロパティが生成され、以降はプロトタイプからはそのプロパティは継承しない。

9.2.2 組み込み型の拡張

  • String や Date などの組み込みクラスのプロトタイプオブジェクトにも値を代入できる。
  • Object.prototype にはプロパティを追加してはいけない。追加するとすべての JavaScript オブジェクトで、追加したプロパティやメソッドが for/in ループで調べられるようになるため、オブジェクトを連想配列として利用するとうまく動かなくなる。

9.3 JavaScript の「クラス」

  • JavaScript はオブジェクトと呼ばれるデータ型をサポートしているが、クラスという正式な概念はない(JavaScript 2 ではサポートされるとのこと)。

9.3.1 インスタンスプロパティ

  • オブジェクト毎にそれぞれ異なるプロパティのこと。
  • JavaScript のオブジェクトプロパティは、デフォルトでインスタンスプロパティになる。

9.3.2 インスタンスメソッド

  • 特定のオブジェクトを介して呼び出されるメソッドのこと。
  • ただし、必ずしもすべてのオブジェクトが自分専用のメソッドを保持しているわけではなく、クラスのすべてのインスタンスで共有される。
  • JavaScript の場合、コンストラクタのプロトタイプオブジェクトのプロパティに関数値を設定することで、クラスのインスタンスメソッドを定義する。

9.3.3 クラスプロパティ

  • クラスのインスタンスではなくクラスそのものに関連づけられたプロパティのこと。
  • JavaScript ではコンストラクタ関数自身のプロパティを定義することでクラスプロパティになる。

// コンストラクタ
function Rectangle(width, height) {
  this.width = width;
  this.height = height;
}

// クラスプロパティ
Rectangle.UNIT = new Rectangle(1, 1);  // 関数はオブジェクトなのでプロパティを定義できる

9.3.4 クラスメソッド

  • クラスのインスタンスではなくクラス自身に関連したメソッドのこと。
  • JavaScript ではコンストラクタ関数自身に関数を定義する。

// コンストラクタ
function Rectangle(width, height) {
  this.width = width;
  this.height = height;
}

// クラスメソッド
Rectangle.max = function(rect1, rect2) {
  if(rect1.width * rect1.height > rect2.width * rect2.height) {
    return rect1;
  } else {
    return rect2;
  }
}

var r1 = new Rectangle(5, 6);
var r2 = new Rectangle(7, 4);
Rectangle.max(r1, r2);

9.3.7 プライベートメンバ

  • JavaScript ではクロージャを使うことでプロパティをカプセル化できる。

function ImmutableRectangle(width, height) {
  // オブジェクトに対してアクセッサーメソッドを定義する
  this.getWidth = function() { return width; }
  this.getHeight = function() { return height; }
}
var rect = new ImmutableRectangle(2, 3);
rect.getWidth();  // 2
rect.width;  // undefined

9.5 スーパークラスとサブクラス

  • JavaScript の場合、Object クラスはすべての組み込むクラスのスーパークラスであり、その他のクラスは Object クラスのサブクラスと見なせる。
  • プロトタイプオブジェクトは Object.prototype からプロパティを継承する。

9.5.1 コンストラクタチェーン

  • 新しいオブジェクトに対してスーパークラスのコンストラクタを呼び出す処理をコンストラクタチェーンという。
  • 1 レベルのサブクラスしか持たない場合は、サブクラスのプロトタイプオブジェクトに superclass という名前のプロパティを追加することで対応できる。

9.5.2 オーバーライドされたメソッドの呼び出し

  • サブクラスでスーパークラスと同じ名前のメソッドを定義すると、サブクラスはそのメソッドをオーバーライド(上書き)する。
  • オーバーライドしたメソッドから元のメソッドを呼び出すために、メソッドチェーンという方法を利用する。

// スーパークラス Rectangle のコンストラクタ
function Rectangle(width, height) {
  this.width = width;
  this.height = height;
}
// スーパークラスに toString メソッドを定義する
Rectangle.prototype.toString = function() {
  return '[' + this.width + ', ' + this.height + ']';
}

// サブクラス PositionRectangle にも toString メソッドを定義する
PositionRectangle.prototype.toString = function() {
  return "(" + this.x + ", " + this.y + ") " + // このクラスのプロパティ
         Rectangle.prototype.toString.apply(this);  // スーパークラスの toString() を呼び出し
}

JavaScript 第 5 版 8 章まとめ

ようやく 8 章まで来ました。
だいぶ内容が難しくなってきたので、読んでもよく分からないものはちゃんと手を動かして理解するように心がけました。
ですが、最後のクロージャのところは正直理解できませんでした・・・。また後で読んでみます。

8 章 関数

8.1.1 入れ子型の関数

  • 関数を他の関数の中に入れ子で定義できる。
  • ただし入れ子にする関数のトップレベルで定義しなければいけない。if 文の中などでは定義できない。

8.1.2 関数リテラル

var f = function() { return x * x };  // 変数に格納したり
f[0] = function(x) { return x * x };  // 配列要素に格納したり
a.sort(function(a, b) { return a - b; });  // 別の関数に渡したり
var s = (function(x) { return x * x; })(10);  // 定義してすぐに呼び出したり

8.2.1 省略可能な引数

  • 関数を定義した時よりも少ない数の引数でその関数を呼び出した場合、省略された引数には undefined が設定される。
  • この特徴を利用して、省略可能な引数を持つ関数を定義できる。
  • ただしその際には、関数内で引数が省略された場合にデフォルト値が設定されるように処理する必要がある。
  • また、省略可能な引数は引数リストの最後に記述する必要がある。

function f(o, a) {  // a は省略可能とする
  a = a || [];  // a が省略されている場合は空の配列を生成
  for(var p in o) a.push(p);
  return a;
}

8.2.2 可変長の引数リスト(Arguments オブジェクト)

  • Arguments オブジェクトは配列のようなオブジェクトである。
  • 関数に渡された引数値は、関数定義値の引数に関わらず arguments[] 配列の要素に格納される。
  • function f(x, y, z) {
    	return arguments.length;
    }
    f(1, 2, 3);  // 3
    f(1);  // 1
    f(1, 2, 3, 4, 5);  // 5。関数定義時の引数の個数に関わらず、任意の数の引数値を渡せる。
    
    function max() {  // 引数を定義しない
      var m = Number.NEGATIVE_INFINITY;
      for(var i = 0; i < arguments.length; i++) {
      	if(arguments[i] > m) m = arguments[i];
      }
      return m;
    }
    max(1, 10, 2, 3000, 400);

  • 関数の引数を格納するローカル変数と Arguments オブジェクトの配列の要素は同じ値を保持する。
  • function f(x) {
      alert(x);  // 渡された引数値を表示
      arguments[0] = null;
      alert(x);  // null
    }

8.2.2.1 callee プロパティ

  • Arguments オブジェクトの callee プロパティは、現在実行中の関数を参照する。
  • 再帰処理を行う関数などで使用される。

function f(x) {
  if(x < = 1) return 1;
  return x * arguments.callee(x - 1);
}
f(5);

8.2.4 引数の型

  • JavaScript は弱い型付き言語で、関数定義時に引数の型を宣言することはできないので、型を限定する場合は関数内で型のチェックを行う必要がある。

8.4 メソッドとしての関数

  • 関数がメソッドとして呼び出された場合、this キーワードは呼び出されたオブジェクトを参照する。
  • 関数がメソッドではなく関数として呼び出された場合、this キーワードはグローバルオブジェクトを参照する。

var f = function() { return this; };
f();  // 関数として呼び出し。Window オブジェクトが返る。

var o = { f: function() { return this; }};
o.f();  // メソッドとして呼び出し。o オブジェクトが返る。

var a = [];
var o = {
  f: function() {
    function g() { a.push(this); }
    g();
    a.push(this);
  }
}
o.f();
alert(a[0]);  // メソッドとして呼び出された関数内の入れ子関数として呼び出し。Window オブジェクトが表示される。
alert(a[1]);  // メソッドとして呼び出し。o オブジェクトが表示される。

8.6 関数のプロパティとメソッド

  • 関数は、実際には特殊なオブジェクトであるため、プロパティやメソッドを持つ。

8.6.1 length プロパティ

  • Function オブジェクトの length プロパティには引数リストで宣言された引数の個数が設定される。
  • arguments.length プロパティと異なり、関数の外でも使用できる。

// 宣言時の引数の個数と呼び出し時の引数の個数が一致していれば true を返す
// arguments.callee.length は check.length でも可
function check(a) {
  return (arguments.length == arguments.callee.length);
}
check(1);  // true
check(1, 2);  // false
check();  // false

8.6.3 自分専用の関数プロパティの定義

  • Function オブジェクトのプロパティであれば関数の実行を終了した後も値を保持し、次に関数が呼び出された時に使うことができる。

uniqueInteger.counter = 0;
function uniqueInteger() {
  return uniqueInteger++;
}
uniqueInteger();  // 0
uniqueInteger();  // 1

8.6.4 apply() メソッドと call() メソッド

  • あるオブジェクトのメソッドであるかのように関数を呼び出すことができる。
  • 最初の引数に呼び出す関数の対象となるオブジェクトを指定する。
  • call() メソッドの 2 番目以降の引数は、これから呼び出される関数に引数として渡される。
  • apply() メソッドの場合は、第 2 引数に関数に渡す引数を配列形式で指定する。

var f = function(a, b) { alert(a * b); return this; };
f(1, 2);  // Window オブジェクトが返る
var o = {};
f.call(o, 1, 2);  // o オブジェクトが返る。メソッドとして実行されている。
f.apply(o, [1, 2]);  //       〃

8.8.1 静的なスコープ

  • JavaScript 関数のスコープは、実行時のスコープではなく定義時のスコープという意味で、静的である。
  • 関数が定義されると、定義された関数の内部状態に、現在のスコープチェーンが保存される。
  • 関数を入れ子で定義する場合は、スコープチェーンには入れ子関数の外側の関数が含まれる。

8.8.2 Call オブジェクト

  • JavaScript インタプリタは関数が呼び出されると、関数のスコープにまず関数定義時のスコープチェーンを設定し、次に Call オブジェクトをスコープチェーンの先頭に追加する。
  • arguments やローカル変数、仮引数は Call オブジェクトのプロパティになる。

8.8.3 名前空間としての Call オブジェクト

  • Call オブジェクトを一時的な名前空間として使えば、グローバルな名前空間での変数名やプロパティ名の衝突を避けることができる。

8.9 Function() コンストラクタ

  • Function() コンストラクタを使うと、JavaScript のコードを実行時に動的に生成してコンパイルできる。
  • Function() コンストラクタを使うたびに、関数の本体が解釈され新しい関数オブジェクトが生成される。
  • そのため、頻繁に呼び出される関数やループで使用すると、効率が悪くなる。

function f(x, y) { return x * y; }
var f = new Function("x", "y", "return x * y;");  // 上記関数文を Function() コンストラクタを使用した形で記述

JavaScript 第 5 版 7 章まとめ

今回はボリューム多め。
この章で、今まであまり馴染みがなかった Object クラスのメソッドと、しっかり把握できていなかった配列のメソッドを抑えられたと思います。

7 章 オブジェクトと配列

7.1 オブジェクトの生成

  • {}(オブジェクトリテラル)と new 演算子を使ってコンストラクタ関数を呼び出して生成する方法がある。
  • {} と new Object() は同じ意味となる。
  • {} の中に、プロパティ名と値のペアをカンマ区切りで記述する。
  • プロパティ名には識別子または文字列が使用できる。

var obj1 = {};
var obj2 = new Array();  // Array オブジェクトを生成する
var obj3 = {
  "name": "hoge",
  'value': 1,
  obj: {x: 0, y: 0}
};

7.2 オブジェクトのプロパティ

  • var の宣言は不要で、オブジェクトのプロパティに値を代入することでプロパティを生成できる。

7.2.1 オブジェクトプロパティの調査

  • for/in ループでユーザ定義のプロパティを調べられる。

var obj = {
  name: "hoge",
  value: 1
};
var s = "";
for(var o in obj) {
  s += o + " : " + obj[o] + "¥n";
}
alert(s);

7.2.2 プロパティの存在確認

  • in 演算子を使ってプロパティが存在するかどうかを調べられる。
  • var o = {x: 0};
    if("x" in o) o.x = 1;
    alert(o.x);  // 1

  • in 演算子を使わなくても実現できる。ただし o.x = undefined (プロパティ自体は存在していて値が未定義値)の場合は正しい結果にならないので注意する。
  • var o = {x: 0};
    if(o.x !== undefined) o.x = 1;
    alert(o.x);

  • undefined でも null でもない場合は以下の記述で実現できる。
  • var o = {x: 0};
    if(o.x) alert("hoge");

7.2.3 プロパティの削除

  • delete 演算子で削除できる。
  • undefined が設定されるのではなくプロパティが削除されるので、for/in ループでも調べられなくなる。

var o = {x: 0, y: 0};
delete o.x;
var s = "";
for(var i in o) {
  s += i + "¥n";
}
alert(s);  // y¥n

7.3 連想配列としてのオブジェクト

  • オブジェクトのプロパティにアクセスするには、ドット演算子の他に “[]“(配列演算子)を使ってアクセスできる(連想配列とも呼ばれる)。
  • 配列演算子を使用した場合、実行中に生成することができる。

var addr = "";
for(var i = 0; i < 4; i++) {
  addr += customer["address" + i] + "¥n";  // customer オブジェクトの address0 〜 3 プロパティの値を読み出せる
}

7.4 Object のプロパティとメソッド

  • 全てのオブジェクト(Array() や Date() も含めて)は Object クラスのプロパティやメソッドを継承する。

7.4.1 constructor プロパティ

  • オブジェクトの初期化で使用されたコンストラクタ関数を参照する。
  • instanceof 演算子で constructor プロパティの値を調べられる。
  • ※Safari(というか Webkit)ではバグがあるらしく、false になりました。

var d = new Date();
alert(d.constructor == Date);  // true
alert(d instanceof Date);  // true

7.4.2 toString() メソッド

  • 呼び出したオブジェクトの値を表す文字列を返す。

7.4.3 toLocaleString() メソッド

  • オブジェクトを表すローカライズされた文字列を返す。

7.4.4 valueOf() メソッド

  • オブジェクトを文字列以外の基本型(数値型が多い)に変換する。

7.4.5 hasOwnProperty() メソッド

  • 継承したものではないプロパティを持つ場合に true を返す。

7.4.6 propertyIsEnumerable() メソッド

  • 継承したものではないプロパティを持ち、かつそのプロパティが for/in ループで調べられる場合に true を返す。
  • hasOwnProperty() メソッドと同じ値を返す。

Continue reading

JavaScript 第 5 版 6 章まとめ

6 章 文

6.5 switch 文

  • switch 文は式の値と同値演算子 (===) で比較し、値が一致する case ラベルを上から順に探す。
  • case 句は実行するコードの開始点を示すだけなので、その後ろの case ラベルのコードブロックを実行したくない場合(ほとんどですが)は break 文を記述する必要がある。

6.11 break 文

  • 最も内側のループまたは switch 文を直ちに終了する。
  • break キーワードの後にラベル名を指定すると、ラベルで指定された文の最後に処理が移動される。

6.12 continue 文

  • ループ中で使用し、次の繰り返しからループの処理を再開する。
  • while ループの場合は、条件式を再テストし、その結果が true であればループを実行する。
  • for ループの場合は、インクリメント式を評価してから条件式を再テストし、次の繰り返し処理へ進むかどうかが判定される。
  • for/in ループの場合は、指定された変数に代入された次のプロパティ名から処理が再開される。

6.14 function 文

  • function 文による関数定義は、関数を定義するだけであり、コンパイルされた時点で関数文が実行されるわけではない。

alert(f(4));  // 16 が表示される。この文が実行される時点では f 関数が定義済。
var f = 0;  // プロパティ f の値を上書きする
function f(x) {  // 関数 f の定義は上記文より先に行われる
  return x * x;
}
alert(f);  // f は 0 に上書きされているので 0 が表示される

6.16 throw 文

  • throw 文を記述すると例外がスローされる。
  • 例外がスローされると、最も近い例外ハンドラに処理を移動する。
  • 例外ハンドラは try/catch/finally 文を使って catch 句に記述する。
  • 例外がスローされたコードブロックに catch 句がない場合は、さらに上位のコードブロックに catch 句がないかを調べる。
  • 例外ハンドラが見つからなかった場合は、例外はエラーとしてユーザに報告される。

6.17 try/catch/finally 文

  • try 句には例外処理の対象となるコードブロックを記述する。
  • catch 句には try ブロック内で例外が発生した時に呼び出される文を記述する。
  • finally 句に記述したコードは、try 句の処理が終了した後に必ず実行される。
  • try ブロックのコードが一部でも実行されれば、finally ブロックのコードも必ず実行される。
  • try ブロック中で例外が発生した場合も、catch ブロックのコードが実行された後 finally ブロックのコードが実行される。

6.18 with 文

  • with 文が実行されると指定されたオブジェクトがスコープチェーンに追加される。
  • 実行後には、スコープチェーンは元の状態に戻る。
  • ただし、実行速度が遅くなったり、with 文の本体に関数定義と変数の初期値設定がある場合、思いがけない振る舞いが起きることがあるため、使用は控えた方が良い。
  • 以下のコードの場合、o のプロパティ p を表示することを想定しているが、もしそのプロパティが存在しなかった場合、エラーにならずに f 関数の仮引数である p が使用されてしまうからという意味?

function f(o, p) {
  with(o) {
    alert(p);
  }
}
var o = {p: 0};
f(o, 1);  // o のプロパティ p の値 0 が表示される
delete o.p;
f(o, 1);  // o には p プロパティが存在しないため f 関数の仮引数 p の値 1 が表示される

参考リンク

JavaScript 第 5 版 5 章まとめ

引き続きサイ本のまとめ。5 章の前半は基礎的なものなので斜め読み。

5 章 式と演算子

5.5.1 比較演算子

  • 比較は数値と文字列のどちらかで行われる。数値でも文字列でもないものはそのどちらかに変換される。
  • 文字列の比較は Unicode の文字コード値を使って、アルファベット順で比較される。

5.5.2 in 演算子

  • 左側の値が右側のオブジェクトのプロパティ名であれば true を返す。
  • なお、左側の値は文字列か文字列に変換されるものでなければならないので注意。

var o = { x : 1, y : 1 };
alert("x" in o);  // true
alert(x in o);  // false
alert("z" in o);  // false

5.5.3 instanceof 演算子

  • 左側のオブジェクトが右側のクラスのインスタンスであれば true を返す。

var d = new Date();
alert(d instanceof Date);  // true(Safari では false。なぜ?)

5.7.1 論理積演算子(&&)

  • 左側のオペランドと右側のオペランドの両方が true の場合に true を返す。
  • ただし内部的には、まず左側のオペランドを評価して false に変換できる場合は左側の式の評価結果を返し、それ以外の場合は右側のオペランドの評価結果を返す。
  • よって、右側の式は必ず評価されるわけではないので、代入やインクリメンタルを右側のオペランドで使うと意図しない動作になることがある。

var a = 0, b = 1;
(a == b) && alert("equal");  // alert は表示されず、false が返される
(a != b) && alert("not equal");  // alert が表示される

5.7.2 論理和演算子(||)

  • 左側のオペランドと右側のオペランドのどちらか一方または両方が true の場合に true を返す。
  • 内部的には論理積演算子と同じような振る舞いをする。

5.10.3 オブジェクト生成演算子(new)

  • まず、プロパティを定義せずに新しいオブジェクトを生成する。
  • 次に、指定されたコンストラクタ関数を呼び出し、指定された引数を渡す。
  • 新たに生成されたオブジェクトを this キーワードの値に代入する。

5.10.4 delete 演算子

  • オペランドに指定されたオブジェクトのプロパティや配列の要素、変数を削除する。
  • コアに組み込まれたプロパティやクライアントサイドのプロパティの一部には削除できないものがある。
  • var 文で宣言された変数は削除できない。
  • プロパティや変数、配列の要素を削除した場合、未定義値が代入されるわけではなくプロパティは存在しなくなる。

5.10.5 void 演算子

  • オペランド値を破棄し未定義値を返す。
 Page 2 of 5 « 1  2  3  4  5 »

Home > Tags > JavaScript

Search
Feeds
Meta
あわせて読みたい
あわせて読みたいブログパーツ
Others...
フィードメーター - sukechan.net
track feed

Return to page top