ホームページ  >  記事  >  ウェブフロントエンド  >  JavaScriptプログラミングにおけるプロトタイプの概念を深く理解する_基礎知識

JavaScriptプログラミングにおけるプロトタイプの概念を深く理解する_基礎知識

WBOY
WBOYオリジナル
2016-05-16 15:53:051087ブラウズ

JavaScript のプロトタイプ オブジェクトは常に混乱を招きます。経験豊富な JavaScript の専門家やその作成者でさえ、この概念についての説明が非常に限られていることがよくあります。この問題は、プロトタイプに対する私たちの初期の理解に起因すると思います。プロトタイプは、常に new、コンストラクター、および混乱を招くプロトタイプ プロパティと密接に関連付けられています。実際、プロトタイピングは非常に単純な概念です。それをよりよく理解するには、私たちが「学んだ」建築の原型を忘れて、そのルーツに戻る必要があります。

プロトタイプとは何ですか?

プロトタイプは、他のオブジェクトからプロパティを継承するオブジェクトです。

どんなオブジェクトでもプロトタイプになれますか?

はい

それらのオブジェクトにはプロトタイプがありますか?

すべてのオブジェクトにはデフォルトのプロトタイプがあります。プロトタイプ自体はオブジェクトであり、各プロトタイプ自体にプロトタイプがあります。 (1 つの例外を除いて、デフォルトのオブジェクト プロトタイプは各プロトタイプ チェーンの先頭にあり、他のプロトタイプはプロトタイプ チェーンの最後にあります)

一歩下がって、オブジェクトとは何でしょうか?

JavaScript では、オブジェクトはキーと値のペアとして保存された任意の順序付けされていないコレクションです。プリミティブ クラス (未定義、null、boolean.nuber、または文字列) でない場合、それはオブジェクトです。

各オブジェクトにはプロトタイプがあると考えることができますが、({}).prototype を書いたとき、unknown になってしまいました。

プロトタイプ プロパティについて知っていることはすべて忘れてください。これはおそらく混乱の原因です。ECMA 5 では、標準のアクセス メソッド Object.getPrototypeOf(object ) が導入されています。 。この最新の実装は、Firefox、Safari、Chrome、および IE9 でサポートされています。さらに、IE を除くすべてのブラウザーは、非標準のアクセス メソッド __proto__ をサポートしています。それ以外の場合、オブジェクトのコンストラクターはそのプロトタイプのプロパティであるとしか言えません。 >

var a = {};
 
//Opera 或 IE<=8下失败
Object.getPrototypeOf(a); //[object Object]
 
//IE下失败
a.__proto__; //[object Object]
 
//所有浏览器
//(but only if constructor.prototype has not been replaced and fails with Object.create)
a.constructor.prototype; //[object Object]


いいですね。false はプリミティブ型ですが、なぜ false.__proto__ が値を返すのですか?

プリミティブ型のプロトタイプにアクセスすると、強制的にオブジェクトに組み込まれます。



//(works in IE<=8 too, due to double-negative)
false.__proto__ === Boolean(false).__proto__; //true

プロトタイプを使用して継承を実装したいのですが、どうすればよいですか?

何らかの状況がない限り、プロトタイプ プロパティをインスタンスに追加することはほとんど意味がありません。つまり、すでにオブジェクトがあり、既存のオブジェクトを共有したいとします。 . 関数。たとえば、これを実行できます



//fails in IE<=8
var a = {};
a.__proto_ = Array.prototype;
a.length; //0
しかし、プロトタイプの真の力は、同じプロトタイプを共有する複数のインスタンスにあることがわかります。プロトタイプ オブジェクトのプロパティは一度定義されると、それが参照するすべてのインスタンスに継承されます。プロトタイプを使用すると、パフォーマンスとプログラムの保守性が向上することは明らかです。これがコンストラクターの理由ですか?はい、コンストラクターは、インスタンス作成時に共通のプロトタイプを割り当てるための便利なクロスブラウザー メカニズムを提供します。 。


例を示す前に、constructor.prototype プロパティが何をするのかを知る必要があります?

まず第一に、JavaScript はコンストラクターと他のメソッドを区別しないため、すべてのメソッドにはプロトタイプ属性があります。逆に、メソッド以外のものにはそのような属性はありません。



//永远不是构造函数的方法,无论如何都是有prototype属性的
Math.max.prototype; //[object Object]
 
//构造函数也有prototype属性
var A = function(name) {
  this.name = name;
}
A.prototype; //[object Object]
 
//Math不是一个方法,所以没有prototype属性
Math.prototype; //null
これで次のことを定義できます。 メソッドのプロトタイプ属性は、このメソッドがインスタンスを作成するコンストラクターとして使用されるときにインスタンスに割り当てられるプロトタイプ オブジェクトです。

メソッドのプロトタイプ属性は実際のプロトタイプとは何の関係もないことを理解することが非常に重要です。



//(在IE中会失败)
var A = function(name) {
  this.name = name;
}
 
A.prototype == A.__proto__; //false
A.__proto__ == Function.prototype; //true - A的prototype是它的构造函数的prototype属性

例を挙げてもらえますか?

次のコードは何百回も見たり使用したりしたことがあるかもしれませんが、ここでももう一度示しますが、何か新しいことがあるかもしれません。



//构造器. <em>this</em> 作为新对象返回并且它内部的[[prototype]]属性将被设置为构造器默认的prototype属性
var Circle = function(radius) {
  this.radius = radius;
  //next line is implicit, added for illustration only
  //this.__proto__ = Circle.prototype;
}
 
//扩充 Circle默认的prototype对象的属性因此扩充了每个由它新建实例的prototype对象的属性
Circle.prototype.area = function() {
  return Math.PI*this.radius*this.radius;
}
 
//创建Circle的两个示例,每个都会使用相同的prototype属性
var a = new Circle(3), b = new Circle(4);
a.area().toFixed(2); //28.27
b.area().toFixed(2); //50.27
これは素晴らしいですね。コンストラクターのプロトタイプ プロパティを変更すると、既存のインスタンス オブジェクトでも新しいプロトタイプ バージョンにすぐにアクセスできますか?

うーん...そうではありません。既存のプロトタイプの属性を変更すると、a.__proto__ はオブジェクトの作成時に A.prototype によって定義されたオブジェクトを参照するため、これは実際に当てはまります。



var A = function(name) {
  this.name = name;
}
 
var a = new A('alpha');
a.name; //'alpha'
 
A.prototype.x = 23;
 
a.x; //23

しかし、prototype 属性を新しいオブジェクトに置き換えても、a.__proto__ は依然として元のオブジェクトを指します。


var A = function(name) {
  this.name = name;
}
 
var a = new A('alpha');
a.name; //'alpha'
 
A.prototype = {x:23};
 
a.x; //null

デフォルトのプロトタイプはどのようなものですか?

コンストラクタープロパティを持つオブジェクト。



var A = function() {};
A.prototype.constructor == A; //true
 
var a = new A();
a.constructor == A; //true (a 的constructor属性继承自它的原型)


instanceof とプロトタイプの関係は何ですか?
A のプロトタイプ属性が a のプロトタイプ チェーンに出現する場合、式 a instanceof A は true を返します。これは、instanceof を騙して失敗させることができることを意味します。


var A = function() {}
 
var a = new A();
a.__proto__ == A.prototype; //true - so instanceof A will return true
a instanceof A; //true;
 
//mess around with a's prototype
a.__proto__ = Function.prototype;
 
//a's prototype no longer in same prototype chain as A's prototype property
a instanceof A; //false


那么我还能利用原型干些其它的什么事儿?

记得我曾经说过每一个构造器都拥有一个prototype属性,利用该属性可以将原型赋值给所有由构造器产生的实例?其实这同样适用于本地构造器,例如Function和String。通过扩展(而不是替换)这个属性,我们可以更新每个指定类型对象的prototype。 

String.prototype.times = function(count) {
  return count < 1 &#63; '' : new Array(count + 1).join(this);
}
 
"hello!".times(3); //"hello!hello!hello!";
"please...".times(6); //"please...please...please...please...please...please..."

告诉我更多关于继承与原型是怎么工作的。原型链又是什么东东?


因为每个对象和每个原型(本身)都有一个原型,我们可以想象, 一个接一个的对象连接在一起形成一个原型链。 原型链的终端总是默认对象(object)的原型。
 

a.__proto__ = b;
b.__proto__ = c;
c.__proto__ = {}; //默认对象
{}.__proto__.__proto__; //null


原型继承机制是内在且隐式实现的。当对象a要访问属性foo时,Javascript会遍历a的原型链(首先从a自身开始),检查原型链的每一个环节中存在的foo属性。如果找到了foo属性就会将其返回,否则返回undefined值。

直接赋值会咋样?

当直接为对象属性赋值时,原型继承机制就玩不转了。a.foo='bar'会直接赋值给a的foo属性。要想为原型对象的属性赋值,你需要直接定位原型对象的该属性。
关于javascript原型就讲全了。我觉得对于原型概念的理解,我把握的还是比较准确的,但是我的观点无论如何也不是最后的结果。请随便告之我的错误之处或提出和我不一致的观点。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。