JavaScript prototypeの属性を深く紹介します.

4543 ワード

各関数の作成時にデフォルトではプロトタイプの属性が付いています.ここにはconstruct属性とObjectオブジェクトを指す隠し属性の一つが含まれています.proto_constructor属性の値はこの関数のオブジェクトです.一つの関数の前にnewを付けて呼び出しますと、関数プロトタイプのメンバーに接続された新しいオブジェクトを作成します.関数のthisはその新しいオブジェクトに結合されます.
関数は常に値を返します.戻り値が指定されていない場合は、undefinedに戻ります.コンストラクタとして呼び出され、戻り値がオブジェクトでない場合は、thisを返します.戻り値がオブジェクトである場合、構造関数としては意味がありません.
[javascript]
 
  
function A(){
this.p = 'haha';
return {p:'heihei'};
}
var a = new A();
function A(){
this.p = 'haha';
return {p:'heihei'};
}
var a = new A();
alert(a.p);// 'heihei', var a = A();
関数A内部で直接関数Bを呼び出し、Bのthisは外部関数Aではなくグローバルオブジェクトに結合されています.これはJS設計の誤りです.私たちは他の方法でこの問題を解決しなければなりません.例えばAでは一つの変数(通常はthat)を使ってAのthis作用領域の引用を保存します.
JS関数は、関数定義時に指定された参照の個数を表します.
関数のargments属性は、関数の宣言にこれらの参照が定義されているかどうかに関わらず、関数を呼び出した時に入ってくるすべてのパラメータを含んでいます.argmentsは配列ではなく、「類似配列」のオブジェクトだけです.Aray.prototype.slice.applyによってJS配列に変換することができます.
JavaScript関数のプロトタイプに追加する方法は、すべての関数が使えます.例えば、JS関数の構築者Functionのプロトタイプに一つのmethod方法を追加することができると、Object、Numberなどのコンストラクターを含むすべての関数がこの方法を継承することができる.
[javascript]
 
  
Function.prototype.method = function(name, func){
this.prototype[name] = func;
return this;
};
Function.prototype.method = function(name, func){
this.prototype[name] = func;
return this;
};
このようにObject.method方法を呼び出すと、すべてのJSオブジェクト(Functionオブジェクトを含む)に新しい方法を追加することができ、Number.method方法を呼び出すと、すべての数値タイプに新しい方法を追加することができ、次の例がこのようになる.注意Object、Numberなどの対象はこの時点でMethodメソッドを引き継ぎません.このような目的を達成するためには、次のような語句が実行されます.
[javascript]
 
  
Object.method('method',Object.method);
Object.method('method',Object.method);
数値タイプのプロトタイプを修正することにより、数値タイプに新しい方法を追加することができます.ここでは前の条で述べたmethod方法を借りて、Numberのプロトタイプにnegative方法を追加します.
[javascript]
 
  
Number.method(negative,function(){
return 0�Cthis;
})
Number.method(negative,function(){
return 0�Cthis;
})
呼び方はちょっと遠回りします.JavaScriptの文法の中で、数字の後に直接に点号をつけて、それから方法と呼び出される文法は間違いです.つまり、3.negativeはこのように書くのは間違いです.数値の種類を呼び出す方法は、数字の後ろにn個のスペース(n>=1)を入れたり、括弧を使って数字を囲み、強制的に式に変換してから方法を呼び出すか、あるいは単に数値変数を定義しても、直接に方法を呼び出すことができます.つまり、次のような書き方は正しいです.
[javascript]
(3).negative();
3.negative();
var n=3n.negative()
3['negative'();
(3).negative();
3.negative();
var n=3n.negative()
3['negative'();
関数式法を使用して関数を定義すると、関数名は再帰的に自分を呼び出すために使用され、名前は上書きされません.次の例を見てみます.
[javascript]
 
  
function a(n){
if(n>1)
return a(n-1)+1;
else
return 1;
};
function a(n){
if(n>1)
return a(n-1)+1;
else
return 1;
};
上記のコードは関数aを定義し、内部再帰的に自身を呼び出した.今は新しい引用aを使って関数aを指します.そして、元のaを整数1に変えて関数aaを呼び出します.下記のコードのように.
[javascript]
 
  
var aa = a;
a = 1;
aa(3);
var aa = a;
a = 1;
aa(3);
コンソールエラー:TypeError:Property'a'of object[object Window]is not a function;元の再帰関数が破壊されたことは明らかである.この問題に関しては、aの代わりに関数aの内部で、argments.calerを使って、あるいは関数表現を使って関数を定義できます.
[javascript]
 
  
var b = function a(n){
if(n>1)
return a(n-1)+1;
else
return 1;
};
var bb = b;
a = 3;
bb(3);
var b = function a(n){
if(n>1)
return a(n-1)+1;
else
return 1;
};
var bb = b;
a = 3;
bb(3);
この時、bb関数は私達が欲しい結果を正確に返します.
JavaScript関数のパッケージ性を高めるために、関数化されたコンストラクタを定義できます.
 
  
[javascript]
var funcCons = function(spec){
var that = {};
that.getName = function(){
return spec.name;
};
that.says = function(){
return spec.saying || '';
};
return that;
};
var myFunc = funcCons({name:'NearEast'});
var funcCons = function(spec){
var that = {};
that.getName = function(){
return spec.name;
};
that.says = function(){
return spec.saying || '';
};
return that;
};
var myFunc = funcCons({name:'NearEast'});
このように、いくつかの私有変数(辞書表など)と関数をコンストラクタに定義してもいいです.それらを全部外に露出する必要はありません.