JavaScriptシリーズ5:強力なプロトタイプとプロトタイプチェーンを深く理解する
8681 ワード
前言
これはしばしば
JavaScriptは、プロトタイプ継承に基づいて広く使用されている唯一の言語であるため、2つの継承パターンの違いを理解するには時間がかかるので、今日はプロトタイプとプロトタイプチェーンについて理解してみましょう.
プロトタイプ
14年前、私(TOMおじさん)がJavaScriptを習ったばかりの頃は、一般的に次のようにコードを書きました.
各functionを実行することで結果が得られ,プロトタイプを学習した後,コードを美化するために以下の方法を用いることができる.
プロトタイプ使用方法1
プロトタイプを使用する前に、コードを小さな変更する必要があります.
次に、Calculatorオブジェクトのprototypeプロパティにオブジェクトのフォント量を割り当てることで、Calculatorオブジェクトのプロトタイプを設定します.
これにより、
プロトタイプ使用方式2
2つ目の方法は、プロトタイプ
その利点は前の文章ですでに知っていて、私有の
同様に、
もうちょっと
ステップ宣言
上記のプロトタイプを使用する場合、一度にプロトタイプオブジェクトを設定するという制限がありますが、プロトタイプの各属性をどのように分けて設定するかについてお話ししましょう.
まず、
上記のコードを作成したら、次のようにします.
上のコードは、実行後、CalculatorのプロトタイプがBaseCalculatorのインスタンスを指しているため、彼のdecimalDigits属性値にアクセスできることがわかります.では、BaseCalculatorの構造関数で宣言された属性値にCalculatorをアクセスさせたくない場合は、どうすればいいですか.次のようにします.
BaseCalculatorのプロトタイプをCalculatorのプロトタイプに割り当てることで、CalculatorのインスタンスではそのdecimalDigits値にアクセスできません.次のコードにアクセスすると、エラーが表示されます.
プロトタイプの書き換え
サードパーティJSクラスライブラリを使用する場合、彼らが定義したプロトタイプメソッドは私たちのニーズを満たすことができないことがよくありますが、このクラスライブラリから離れられないので、プロトタイプの1つ以上の属性やfunctionを書き換える必要があります.同じaddコードを宣言し続けることで、前のadd機能を上書きすることができます.コードは次のとおりです.
このように,計算した結果は従来より1つのtaxの値が多くなったが,書き換えたコードを最後に置く必要があり,前のコードを上書きすることができる点に注意する必要がある.
プロトタイプチェーン
プロトタイプチェーンを作成する前に、次のコードを行います.
上記の例では、
属性の検索
オブジェクトのプロパティを検索すると、
コード実行によって、
もう1つ注意しなければならないのは、任意のタイプのオブジェクトをプロトタイプに割り当てることができますが、次のコードが無効であるなど、元のタイプの値を割り当てることはできません.
义齿
hasOwnPropertyだけが正確で望ましい結果を与えることができ、これはオブジェクトのプロパティを巡るときに役立ちます.オブジェクト自体のプロパティを定義するのではなく、プロトタイプチェーンのプロパティを除外する方法はありません.
しかし、JavaScriptはhasOwnPropertyが不正に占有されることを保護しないため、オブジェクトにたまたまこの属性が存在する場合は、外部のhasOwnProperty関数を使用して正しい結果を得る必要があります.
オブジェクトのプロパティが存在するかどうかを確認する場合、hasOwnPropertyは唯一の方法です.また、
for in文の動作を変更することはできませんので、結果をフィルタするにはhasOwnPropertyメソッドしか使用できません.コードは次のとおりです.
このバージョンのコードは唯一正しい書き方です.
まとめ:
まとめ
プロトタイプは私たちの開発コードを大きく豊富にしていますが、普段使用している過程で上記の注意点に注意しなければなりません.
参考内容:http://bonsaiden.github.com/JavaScript-Garden/zh/
本文について
本文はTOMおじさんの深く理解するJavaScriptシリーズから転じます
【JavaScriptシリーズを深く理解する】オリジナル、翻訳、転載、整理などの各タイプの文章を含む文章で、原文はTOMおじさんの非常に良いテーマで、今それを再整理して発表します.おじさん、ありがとう.もしあなたが本文がいいと思ったら、推薦してください.支持してください.感謝しています.
もっと優秀な文章は私のコラムに注目してください.
JavaScript
は、従来のクラス継承モデルではなく、prototypal
プロトタイプモデルを使用する.これはしばしば
JavaScript
の欠点として言及されるが,プロトタイプベースの継承モデルは従来のクラス継承よりも強い.従来のクラス継承モデルを実現するのは簡単ですが、JavaScriptでのプロトタイプ継承を実現するのは難しいことが多いです.JavaScriptは、プロトタイプ継承に基づいて広く使用されている唯一の言語であるため、2つの継承パターンの違いを理解するには時間がかかるので、今日はプロトタイプとプロトタイプチェーンについて理解してみましょう.
プロトタイプ
14年前、私(TOMおじさん)がJavaScriptを習ったばかりの頃は、一般的に次のようにコードを書きました.
var decimalDigits = 2,
tax = 5;
function add(x, y) {
return x + y;
}
function subtract(x, y) {
return x - y;
}
//alert(add(1, 3));
各functionを実行することで結果が得られ,プロトタイプを学習した後,コードを美化するために以下の方法を用いることができる.
プロトタイプ使用方法1
プロトタイプを使用する前に、コードを小さな変更する必要があります.
var Calculator = function (decimalDigits, tax) {
this.decimalDigits = decimalDigits;
this.tax = tax;
};
次に、Calculatorオブジェクトのprototypeプロパティにオブジェクトのフォント量を割り当てることで、Calculatorオブジェクトのプロトタイプを設定します.
Calculator.prototype = {
add: function (x, y) {
return x + y;
},
subtract: function (x, y) {
return x - y;
}
};
//alert((new Calculator()).add(1, 3));
これにより、
new Calculator
オブジェクト以降、add
メソッドを呼び出して結果を計算することができます.プロトタイプ使用方式2
2つ目の方法は、プロトタイプ
prototype
を付与するときに、function
が直ちに実行する式を使用して、以下のフォーマットで値を付与することである.Calculator.prototype = function () { } ();
その利点は前の文章ですでに知っていて、私有の
function
をカプセル化することができて、return
の形式を通じて簡単な使用名を暴露して、public/private
の効果を達成して、修正したコードは以下の通りです:Calculator.prototype = function () {
add = function (x, y) {
return x + y;
},
subtract = function (x, y) {
return x - y;
}
return {
add: add,
subtract: subtract
}
}();
//alert((new Calculator()).add(11, 3));
同様に、
new Calculator
オブジェクトは、add
メソッドを呼び出して結果を計算することができる.もうちょっと
ステップ宣言
上記のプロトタイプを使用する場合、一度にプロトタイプオブジェクトを設定するという制限がありますが、プロトタイプの各属性をどのように分けて設定するかについてお話ししましょう.
var BaseCalculator = function () {
//
this.decimalDigits = 2;
};
// BaseCalculator 2
BaseCalculator.prototype.add = function (x, y) {
return x + y;
};
BaseCalculator.prototype.subtract = function (x, y) {
return x - y;
};
まず、
BaseCalculator
オブジェクトが宣言され、コンストラクション関数には小数点以下の属性decimalDigits
が初期化され、プロトタイプ属性によってfunction
が2つ設定されます.それぞれadd(x,y)
とsubtract(x,y)
です.もちろん、前述の2つの方法のいずれかを使用することもできます.我々の主な目的は,kオブジェクトを真のCalculator
のプロトタイプにどのように設定するかを見ることである.var BaseCalculator = function() {
this.decimalDigits = 2;
};
BaseCalculator.prototype = {
add: function(x, y) {
return x + y;
},
subtract: function(x, y) {
return x - y;
}
};
上記のコードを作成したら、次のようにします.
var Calculator = function () {
//
this.tax = 5;
};
Calculator.prototype = new BaseCalculator();
Calculator
のプロトタイプはBaseCalculator
のインスタンスに指向されていることがわかります.Calculator
をadd(x,y)
とsubtract(x,y)
の2つのfunction
に統合することを目的としています.また、そのプロトタイプはBaseCalculator
のインスタンスであるため、Calculator
のオブジェクトインスタンスをいくつ作成しても、彼らのプロトタイプは同じインスタンスを指しています.var calc = new Calculator();
alert(calc.add(1, 1));
//BaseCalculator decimalDigits , Calculator
alert(calc.decimalDigits);
上のコードは、実行後、CalculatorのプロトタイプがBaseCalculatorのインスタンスを指しているため、彼のdecimalDigits属性値にアクセスできることがわかります.では、BaseCalculatorの構造関数で宣言された属性値にCalculatorをアクセスさせたくない場合は、どうすればいいですか.次のようにします.
var Calculator = function () {
this.tax= 5;
};
Calculator.prototype = BaseCalculator.prototype;
BaseCalculatorのプロトタイプをCalculatorのプロトタイプに割り当てることで、CalculatorのインスタンスではそのdecimalDigits値にアクセスできません.次のコードにアクセスすると、エラーが表示されます.
var calc = new Calculator();
alert(calc.add(1, 1)); //2
alert(calc.decimalDigits); //undefined
プロトタイプの書き換え
サードパーティJSクラスライブラリを使用する場合、彼らが定義したプロトタイプメソッドは私たちのニーズを満たすことができないことがよくありますが、このクラスライブラリから離れられないので、プロトタイプの1つ以上の属性やfunctionを書き換える必要があります.同じaddコードを宣言し続けることで、前のadd機能を上書きすることができます.コードは次のとおりです.
// Calculator add() function
Calculator.prototype.add = function (x, y) {
return x + y + this.tax;
};
var calc = new Calculator();
alert(calc.add(1, 1));
このように,計算した結果は従来より1つのtaxの値が多くなったが,書き換えたコードを最後に置く必要があり,前のコードを上書きすることができる点に注意する必要がある.
プロトタイプチェーン
プロトタイプチェーンを作成する前に、次のコードを行います.
function Foo() {
this.value = 42;
}
Foo.prototype = {
method: function() {}
};
function Bar() {}
// Bar prototype Foo
Bar.prototype = new Foo();
Bar.prototype.foo = 'Hello World';
// Bar.prototype.constructor Bar
Bar.prototype.constructor = Bar;
var test = new Bar() // Bar
//
test [Bar ]
Bar.prototype [Foo ]
{ foo: 'Hello World' }
Foo.prototype
{method: ...};
Object.prototype
{toString: ... /* etc. */};
上記の例では、
test
のオブジェクトはBar.prototype
およびFoo.prototype
から継承される.したがって、Foo
のプロトタイプ方法method
にアクセスすることができる.同時に、そのプロトタイプに定義されたFoo
インスタンス属性value
にもアクセスすることができる.new Bar()
は、新しいFoo
のインスタンスを作成するのではなく、そのプロトタイプ上のインスタンスを繰り返し使用することに注意してください.したがって、すべてのBar
インスタンスは、同じvalue
属性を共有する.属性の検索
オブジェクトのプロパティを検索すると、
JavaScript
は、指定された名前のプロパティが見つかるまでプロトタイプチェーンを上に移動し、プロトタイプチェーンの上部、つまりObject.prototype
に到達するまで検索しますが、指定されたプロパティが見つからない場合は、undefined
に戻ります.例を見てみましょう.function foo() {
this.add = function (x, y) {
return x + y;
}
}
foo.prototype.add = function (x, y) {
return x + y + 10;
}
Object.prototype.subtract = function (x, y) {
return x - y;
}
var f = new foo();
alert(f.add(1, 2)); // 3, 13
alert(f.subtract(1, 2)); // -1
コード実行によって、
subtract
は私たちが言ったように上を向いて検索して結果を得たことを発見しましたが、add
の方法は少し違います.これも強調したいのですが、属性は検索するときにまず自分の属性を探して、もしプロトタイプを探していなければ、二度となくて、上を歩いて、Objectのプロトタイプをずっと調べています.だから、あるレベルでは、for in
文で属性を巡回する場合、効率も問題です.もう1つ注意しなければならないのは、任意のタイプのオブジェクトをプロトタイプに割り当てることができますが、次のコードが無効であるなど、元のタイプの値を割り当てることはできません.
function Foo() {}
Foo.prototype = 1; //
义齿
hasOwnProperty
はObject.prototype
の1つの方法で、それは良いもので、彼は1つのオブジェクトがプロトタイプチェーン上の属性ではなくカスタム属性を含むかどうかを判断することができます.hasOwnProperty
はJavaScript
の中で唯一の処理属性ですが、プロトタイプチェーンを検索しない関数です.// Object.prototype
Object.prototype.bar = 1;
var foo = {goo: undefined};
foo.bar; // 1
'bar' in foo; // true
foo.hasOwnProperty('bar'); // false
foo.hasOwnProperty('goo'); // true
hasOwnPropertyだけが正確で望ましい結果を与えることができ、これはオブジェクトのプロパティを巡るときに役立ちます.オブジェクト自体のプロパティを定義するのではなく、プロトタイプチェーンのプロパティを除外する方法はありません.
しかし、JavaScriptはhasOwnPropertyが不正に占有されることを保護しないため、オブジェクトにたまたまこの属性が存在する場合は、外部のhasOwnProperty関数を使用して正しい結果を得る必要があります.
var foo = {
hasOwnProperty: function() {
return false;
},
bar: 'Here be dragons'
};
foo.hasOwnProperty('bar'); // false
// {} hasOwnProperty, foo
{}.hasOwnProperty.call(foo, 'bar'); // true
オブジェクトのプロパティが存在するかどうかを確認する場合、hasOwnPropertyは唯一の方法です.また、
for in loop
を使用してオブジェクトを巡回する場合は、常にhasOwnPropertyメソッドを使用することをお勧めします.これにより、プロトタイプオブジェクトの拡張による干渉を回避できます.例を見てみましょう.// Object.prototype
Object.prototype.bar = 1;
var foo = {moo: 2};
for(var i in foo) {
console.log(i); // :bar moo
}
for in文の動作を変更することはできませんので、結果をフィルタするにはhasOwnPropertyメソッドしか使用できません.コードは次のとおりです.
// foo
for(var i in foo) {
if (foo.hasOwnProperty(i)) {
console.log(i);
}
}
このバージョンのコードは唯一正しい書き方です.
hasOwnProperty
を使用しているので、今回はmoo
しか出力されません.hasOwnProperty
を使用しない場合、このコードは、Object.prototypeなどのオリジナルオブジェクトプロトタイプが拡張されたときにエラーが発生する可能性があります.まとめ:
hasOwnProperty
を推奨し、コードが実行されている環境を仮定しないで、オリジナルオブジェクトが拡張されているかどうかを仮定しないでください.まとめ
プロトタイプは私たちの開発コードを大きく豊富にしていますが、普段使用している過程で上記の注意点に注意しなければなりません.
参考内容:http://bonsaiden.github.com/JavaScript-Garden/zh/
本文について
本文はTOMおじさんの深く理解するJavaScriptシリーズから転じます
【JavaScriptシリーズを深く理解する】オリジナル、翻訳、転載、整理などの各タイプの文章を含む文章で、原文はTOMおじさんの非常に良いテーマで、今それを再整理して発表します.おじさん、ありがとう.もしあなたが本文がいいと思ったら、推薦してください.支持してください.感謝しています.
もっと優秀な文章は私のコラムに注目してください.