忍者ブログ
[1] [2] [3] [4]

DATE : 2024/04/20 (Sat)
×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。


DATE : 2006/08/08 (Tue)

以前の記事では、this キーワードの指すオブジェクトは、関数の呼び出しを行うオブジェクトによって異なるということを書きました。

しかし、Protptyoe.js にある bind メソッドを使用すると、this キーワードが指すオブジェクトを指定することができます。

例えば、次のコードは、printMthod 関数内では this キーワードの指すオブジェクトがないために undefined と画面に表示されます。

function MyObject {
    this._field = 1;
}

MyObject.prototpye.printField = function() {
    document.write(this._field);
}

var myObject = new MyObject();
var printMethod = myObject.printField;

printMethod();

しかし、Prototype.js によって、Function オブジェクトに追加された bind メソッドを使用すると、this の指すオブジェクトを指定することができます。

function MyObject {
    this._field = 1;
}

MyObject.prototpye.printField = function() {
    document.write(this._field);
}

var myObject = new MyObject();
var printMethod = myObject.printField.bind(myObject);

printMethod();

結果は、「1」と表示されます。

bind メソッドのソースコードを覗くと、次のようになっています。

Function.prototype.bind = function() {
  var __method = this, args = $A(arguments), object = args.shift();
  return function() {
    return __method.apply(object, args.concat($A(arguments)));
  }
}

これは、Prototype.js 1.4 の bind メソッドです。

この中で、$A 関数は引数を配列に変換する関数、shift メソッドは、配列の初めの要素を取り出す(その後、空いた部分を詰める)メソッドです。

__method 引数には、bind メソッドを呼び出したオブジェクト(つまり、上の例では printField 関数)が格納されます。そして、object には、bind メソッドの第1引数(上の例では、myObject)が渡されます。

そして戻り値として、bind メソッドを呼び出した関数オブジェクトを実行する関数を生成しています。この関数の中では、Function オブジェクトの apply メソッドが使用されています。apply メソッドは、呼ばれた関数オブジェクトを実行するメソッドで、第1引数に this キーワードの指すオブジェクト、第2引数に引数を格納した配列を格納することになっています。

こうすることで、this キーワードが指し示すオブジェクトを指定できるようになっています。

なお、Function オブジェクトの apply メソッドは、ECMAScript の仕様に定義されています。つまり、Prototype.js を使わずに、apply メソッドを使うという手もあります。

参考文献

PR

DATE : 2006/08/05 (Sat)

忘れたときのために、JavaScript で DOM オブジェクトを取得する方法をメモしておきます。

スクリプトが埋め込まれている HTML(XHTML) を表す DOM オブジェクト

document オブジェクトが HTMLDocument インタフェースを実装しているので、document オブジェクトを使えば DOM オブジェクトを取得できます。

HTMLDocumen インタフェースは Document インタフェースを継承しているので、ここからルート要素を取得することもできます(ルート要素は<html>になります)。

// HTMLDocument
var htmlDocument = document;
// ルート要素
var rootElement = document.documentElement;

XML を表す DOM オブジェクト

XMLHttpRequest オブジェクトを使って XML ファイルを読み込んだ後に、responseXML プロパティを取得することで Document オブジェクトを取得できます。

// xmlHttpRequest は、XML をロード済みの XMLHttpRequest オブジェクト
var rootElement = xmlHttpRequest.responseXML;

なんとなく、「responseXML」という名前からメソッドのように見えますが、プロパティなので注意が必要です。

参考文献


DATE : 2006/08/01 (Tue)

JavaScript には、名前空間がありません。例えば、HTML の script 要素で読み込んだライブラリの中で 「func」という関数があった場合で自作のスクリプトの中でも func という関数を定義するとします。この場合、自分のスクリプトの中で func 関数を呼び出した場合でも、ライブラリの中で func 関数を呼び出した場合でも、自作スクリプト中の func 関数が呼び出されてしまいます。

この程度の場合は、ライブラリ中にある関数と同名のものを作らないように気をつければ良いだけの話となります。しかし、ライブラリを2つ以上読み込む場合はどうでしょうか。場合によっては、ライブラリ中の関数が後に読み込まれたライブラリの関数に上書きされて、ライブラリの動作がおかしくなる場合があります。

例えば、jQueryというライブラリがあります。このライブラリは、$関数を利用して DOM オブジェクトを簡単に取得できます。例えば、次のコードでページ中の全ての画像を非表示にできます。

$("img").hide();

$関数の引数には、CSS セレクタの表記や XPath を使用することもできます。

$(".target").hide();    // target クラスの要素を非表示にする
$("p:last").hide();     // 最後の p 要素を非表示にする

しかし、prototype.js というライブラリでも、$関数は利用されています。prototype.js では、引数に指定された ID を持つ DOM オブジェクトを返します。

そのため、prototype.js と jQuery を併用すると、問題が発生する場合があります。一応、対処法は「Prototype and jQuety」に書かれています。

しかし、これは prototype.js と jQuety のみをライブラリとして使用し、他のライブラリは使用しないという条件を基に書かれています。prototype.js に依存したライブラリや jQuery に依存したライブラリも追加した場合の保証はありません。

そのため、ライブラリを採用する際には、用意されている関数やオブジェクトが重複していないか注意を払わなければなりません。


DATE : 2006/07/24 (Mon)

いつも、型制限の強い言語を使っているので、次のようなミスをしてしまいました orz

まず、次のように、特定の整数が入った変数(num)を2で割るとします。

var result = num / 2;

型制限の強い言語を使っていると、num に整数が入っている場合、2で割った結果も整数となるように期待してしまいます。例えば、Javaで int 型変数 num の値を2で割れば、結果も int 型となります。

int result = num / 2;

JavaScript は型制限のゆるい言語なので、num の中が整数であっても、2で割った結果が整数になるとは限りません。

むしろ JavaScript では、全ての数(Number 型)が浮動小数点数で扱われているので、結果は全て浮動小数点になると考えなければなりません。

例えば、次の計算の結果は、0.5になります。

var result = 1 / 2;

整数値を強制するには、Math.ceil 関数や Math.floor 関数を使います。簡単に言えば、前者は小数点第1位で切り上げ、後者は切り捨てで整数値に変換します。

例えば、Java の int 型同士の計算を JavaScript で行うには、次のようにします。

var result = Math.floor(num / 2);

DATE : 2006/07/23 (Sun)

今日やってしまったミスをメモしておきます orz

例えば、次のようなオブジェクトを定義したとします。

function MyObject() {
    this.a = 100;
}

MyObject.prototype = {
    call : function() {
        alert(this.a);
    }
}

このコードでは、メソッドとして call 関数(引数なし)をもつ MyObject を定義しています。

そして、次のコードを実行すると、「100」と書かれたダイアログが表示されます。

var myObject = new MyObject();

myObject.call();

これは、call 関数の中の「this」キーワードが、生成された MyObject を表しているためです。

ここで、次のような関数を用意します。この関数は、他の関数(Function オブジェクト)を受け取って呼び出す関数です。

function callFunction(callback) {
    callback();
}

次のコードを実行すれば、myObject の call 関数が呼び出されるはずです。

var myObject = new MyObject();

callFunction(myObject.call);

しかし、表示されるダイアログには「undefined」と出てしまいます。つまり、call 関数の中にある「this.a」が定義されていないということになります。

実際には、JavaScript の「this」は、呼び出し元を表します。つまり、「myObject.call()」で call 関数を呼び出した場合には、myObject 経由で call 関数が呼び出されるので「this」は myObject を指します。しかし、「callFunction(myObject.call)」(実際の呼び出しは「callback()」)では、myObject を経由せずに直接 call 関数が呼び出されるので、「this」は myObject を指しません(Firefox での実行では、Window オブジェクトを指しました)。そのため、「undefined」となったわけです。

ついつい Java と同じつもりでコードを書いていて、見事に失敗してしまいました orz

(;^ω^)まあ、言語の使い初めにはよくあることですね。

忍者ブログ [PR]
ブログ内検索
最近の状況
リンク
カレンダー
03 2024/04 05
S M T W T F S
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
使用許諾
最新コメント
(08/15)
(05/04)
(03/06)
(03/04)
(09/25)
最新トラックバック
ブログ内検索
最近の状況
リンク
カレンダー
03 2024/04 05
S M T W T F S
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
使用許諾
最新コメント
(08/15)
(05/04)
(03/06)
(03/04)
(09/25)
最新トラックバック