ホームページ >ウェブフロントエンド >jsチュートリアル >JavaScriptシリーズを深く理解する (6) 強力なプロトタイプとプロトタイプchain_javascriptスキル

JavaScriptシリーズを深く理解する (6) 強力なプロトタイプとプロトタイプchain_javascriptスキル

WBOY
WBOYオリジナル
2016-05-16 17:57:07844ブラウズ

はじめに
JavaScript には従来のクラス継承モデルは含まれていませんが、プロトタイプのプロトタイプ モデルが使用されています。

これは JavaScript の欠点としてよく指摘されますが、プロトタイプベースの継承モデルは実際には従来のクラス継承よりも強力です。従来のクラス継承モデルの実装は簡単ですが、JavaScript でのプロトタイプ継承の実装ははるかに困難です。

JavaScript はプロトタイプ継承に基づいて広く使用されている唯一の言語であるため、2 つの継承モデルの違いを理解するには時間がかかります。今日はプロトタイプとプロトタイプ チェーンについて学びます。

プロトタイプ
10 年前、初めて JavaScript を学んだとき、私は通常次の方法でコードを書きました:

コードをコピー コードは次のとおりです:

var decmalDigits = 2,
tax = 5;

function add(x, y) {
return x y ;
}

関数subtract(x, y) {
return x - y>}

//alert(add(1, 3));

各関数を実行して結果を取得します。プロトタイプを学習した後、次のメソッドを使用してコードを美しくすることができます。

プロトタイプの使用方法 1:
プロトタイプを使用する前に、コードに小さな変更を加える必要があります:

コードをコピー コードは次のとおりです。
var Calculator = function (decimalDigits, 税) {
this.decmalDigits = decmalDigits;
>};


次に、Calculator オブジェクトのプロトタイプ プロパティにオブジェクト リテラルを代入して、Calculator オブジェクトのプロトタイプを設定します。


Calculator.prototype = {
add : function (x, y) {
return x y;
},

subtract: function (x, y) {
return x - y; ;
//alert((new Calculator()).add(1, 3));


このようにして、新しい Calculator オブジェクトの後に add メソッドを呼び出して結果を計算できます。 。

プロトタイプの使用方法 2:
2 つ目の方法は、プロトタイプのプロトタイプを割り当てるときに関数がすぐに実行される式を使用する方法です。これは次の形式です。

Calculator.prototype = function () { } ();
その利点は、前の投稿ですでに知られています。つまり、プライベート関数をカプセル化し、単純な使用名を return の形式で公開して、パブリック/プライベート効果を実現できます。




コードをコピー
コードは次のとおりです: Calculator.prototype = function () { add = function (x, y) {
return x y;
},

subtract = function (x, y) {
return x - y
}
return {
add: 加算、
subtract: 減算
}
} ();

//alert((new Calculator()).add (11 , 3));


同様に、新しい Calculator オブジェクトを作成し、後で add メソッドを呼び出して結果を計算できます。

もう 1 つのポイント
ステップバイステップのステートメント:
上記のプロトタイプを使用する場合、プロトタイプ オブジェクトを一度に設定するという制限があります。各属性を設定する方法について説明します。プロトタイプは別途。




コードをコピー
コードは次のとおりです。 var BaseCalculator = function () { // 各インスタンスの 10 進数を宣言します
this.decmalDigits = 2;
}

// プロトタイプを使用して BaseCalculator の 2 つのオブジェクト メソッドを拡張します
BaseCalculator.prototype.add = 関数 (x, y) {
戻り x y;
};

BaseCalculator.prototype.subtract = 関数 (x, y) {
戻り x - y; ;


まず、コンストラクターで BaseCalculator オブジェクトを宣言し、10 進数属性 decmalDigits を初期化してから、プロトタイプ属性を通じて add(x,y) とsubtract という 2 つの関数を設定します。 ( x, y)、もちろん、上記の 2 つのメソッドのいずれかを使用することもできます。私たちの主な目的は、BaseCalculator オブジェクトを実際の Calculator のプロトタイプに設定する方法を確認することです。



コードをコピー
コードは次のとおりです。 var BaseCalculator = function() { this. 10 進数 = 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 が 2 つの関数 add(x,y) とsubtract(x,y) を統合できるようにするために、Calculator のプロトタイプが BaseCalculator のインスタンスを指していることがわかります。そしてもう 1 つ言っておきたいのは、そのプロトタイプは BaseCalculator のインスタンスであるため、作成した Calculator オブジェクトのインスタンスの数に関係なく、それらのプロトタイプは同じインスタンスを指すということです。


コードをコピーします コードは次のとおりです。
var calc = new Calculator(); 🎜>alert (calc.add(1, 1));
//BaseCalculator で宣言された 10 進数属性は、電卓でアクセスできます。上記のコードを実行すると、Calculator のプロトタイプが BaseCalculator のインスタンスを指しているため、BaseCalculator のコンストラクターで宣言された属性値に Calculator がアクセスしたくない場合は、その DecimalDigits 属性値にアクセスできることがわかります。するの?これを実行します:




コードをコピーします


コードは次のとおりです:
var Calculator = function ( ) { this.tax= 5; }; Calculator.prototype = BaseCalculator.prototype;

Calculator のプロトタイプに代入する次のコードにアクセスすると、インスタンスで 10 進数の値にアクセスできません。エラーが発生します。




コードをコピーします


コードは次のとおりです。
var calc = new Calculator(); 🎜>alert (calc.add(1, 1)); alert(calc.decmalDigits); サードパーティの JS ライブラリを使用する場合、彼らが定義したプロトタイプ メソッドは私たちのニーズを満たすことはできませんが、これらはこのクラス ライブラリから分離できないため、現時点ではプロトタイプ内の 1 つ以上のプロパティまたは関数を書き直す必要があります。同じものを宣言し続けることができます。追加コードの形式は次のとおりです。前の追加関数を上書きして書き換えます。 コードは次のとおりです。



コードをコピーします。

コードは次のとおりです。

//前の電卓の add() 関数をオーバーライドします。
Calculator.prototype.add = function (x, y) { return x y this.tax; var calc = new Calculator(); alert(calc.add(1, 1));
このようにして、計算結果には元の税金より 1 つ多くの税金が含まれます。値は 1 つですが、注意すべき点が 1 つあります。書き換えられたコードは、前のコードを上書きできるように最後に配置する必要があります。

プロトタイプ チェーン
プロトタイプをチェーンする前に、最初に次のコードを追加します。




コードをコピー

コードは次のとおりです:


function Foo() {
this.value = 42;
} Foo.prototype = { method: function() {} }; function Bar() {}
// Bar のプロトタイプ属性を Foo のインスタンス オブジェクトに設定します
Bar.prototype = new Foo(); >Bar.prototype .foo = 'Hello World';

// Bar.prototype.constructor を Bar 自体に修正します
Bar.prototype.constructor = Bar test = new Bar() // Bar の新しいインスタンスを作成します

// プロトタイプ チェーン
test [Bar のインスタンス]
Bar.prototype [Foo のインスタンス]
{ foo: 'Hello World ' }
Foo.prototype
{メソッド: ...};
Object.prototype
{toString: ... /* など */};
上記の例では、テスト オブジェクトは Bar.prototype と Foo.prototype を継承しているため、Foo のプロトタイプ メソッドにアクセスできます。同時に、プロトタイプで定義された Foo インスタンスのプロパティ値にもアクセスできます。 new Bar() は新しい Foo インスタンスを作成するのではなく、そのプロトタイプ上のインスタンスを再利用するため、すべての Bar インスタンスは同じ value プロパティを共有することに注意してください。

プロパティ検索:
オブジェクトのプロパティを探すとき、JavaScript は指定された名前のプロパティが見つかるまで、検索がプロトタイプ チェーンの先頭に到達するまで、プロトタイプ チェーンを上方向に走査します。は、Object.prototype - ただし、指定された属性がまだ見つからない場合は、unknown が返されます。例を見てみましょう:
コードをコピー コードは次のとおりです。

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)); // 結果は 13 ではなく 3 です。
alert(f.subtract(1, 2)); //結果は -1

コードを実行すると、結果を取得するために、いわゆる上向き検索がインストールされることがわかります。 、ただし、追加方法は少し異なります。私が強調しているのは、属性を検索するときに、最初に自分の属性を検索し、プロトタイプがない場合は、プロトタイプを検索するということです。次に、それを Object のプロトタイプに挿入します。そのため、特定のレベルでは、for in ステートメントを使用してプロパティを走査する場合、効率も問題になります。

もう 1 つ注意する必要があるのは、プロトタイプには任意のタイプのオブジェクトを割り当てることができますが、アトミック タイプの値を割り当てることはできないということです。たとえば、次のコードは無効です。 >

コードをコピーします
コードは次のとおりです。 function Foo() {} Foo.prototype = 1;無効な

hasOwnProperty 関数:
hasOwnProperty は Object.prototype のメソッドです。hasOwnProperty があるため、オブジェクトにプロトタイプ チェーンのプロパティの代わりにカスタム プロパティが含まれているかどうかを判断できます。プロトタイプチェーンを検索せずにプロパティを処理する唯一の関数です。



コードをコピー
コードは次のとおりです: // Object.prototype を変更 Object.prototype .bar = 1;
var foo = {goo: unknown};

foo.bar; // 1
'bar' // true

foo.hasOwnProperty('bar'); // false
foo.hasOwnProperty('goo'); // true


オブジェクトを走査するときに正しい結果を与えることができるのは hasOwnProperty だけですプロパティが役立つ場合があります。 プロトタイプ チェーン上のプロパティを除外するには、オブジェクト自体に定義されたプロパティ以外に方法はありません。

しかし、嫌なことがあります。JavaScript は hasOwnProperty が不法に占有されることを保護しないため、オブジェクトがたまたまこのプロパティを持っている場合、正しい結果を得るには外部の hasOwnProperty 関数を使用する必要があります。




コードをコピー
コードは次のとおりです: var foo = { hasOwnProperty: function() {
return false;
bar: 'Here be Dragons'
} // 常に false を返します。

// {} オブジェクトの hasOwnProperty を使用し、その上部と下部を foo に設定します
{}.hasOwnProperty.call(foo, 'bar') // true

;
hasOwnProperty は、オブジェクトにプロパティが存在するかどうかを確認するときに使用できる唯一のメソッドです。同時に、for in ループを使用してオブジェクトを走査する場合は、常に hasOwnProperty メソッドを使用することをお勧めします。これにより、プロトタイプ オブジェクトの展開による干渉が回避されます。



コードをコピーします

コードは次のとおりです:
// Object.prototype を変更 Object.prototype.bar = 1 ; var foo = { moo: 2}; for(var i in foo) { console.log(i); // 2 つの属性を出力します: bar と moo
}


us for in ステートメントの動作を変更する方法はないため、結果をフィルターしたい場合は、hasOwnProperty メソッドのみを使用できます。コードは次のとおりです。



コードをコピー

コードは次のとおりです:

// foo 変数は上記の例の変数です。
for(var i in foo) {
if (foo.hasOwnProperty(i)) {
console.log(i) );
}
}

このバージョンのコードが唯一の正しい書き方です。 hasOwnPropertyを使用したので、今回はmooのみが出力されます。 hasOwnProperty が使用されていない場合、ネイティブ オブジェクト プロトタイプ (Object.prototype など) が拡張されるときにこのコードが壊れる可能性があります。

要約: hasOwnProperty を使用し、コードが実行される環境についていかなる仮定も立てず、ネイティブ オブジェクトが拡張されているかどうかも仮定しないことをお勧めします。

まとめ
プロトタイプによって開発コードは大幅に充実しましたが、日常の使用では上記の注意事項のいくつかに注意する必要があります。
声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。