ホームページ  >  記事  >  ウェブフロントエンド  >  JavaScript の継承とプロトタイプ チェーンの簡単な分析

JavaScript の継承とプロトタイプ チェーンの簡単な分析

WBOY
WBOY転載
2022-02-15 17:44:332064ブラウズ

この記事では、コンストラクター、プロトタイプ、クラス構文シュガーに関連する問題など、javascript の継承とプロトタイプ チェーンに関する知識を提供します。皆様のお役に立てれば幸いです。

JavaScript の継承とプロトタイプ チェーンの簡単な分析

#JavaScript の継承とプロトタイプ チェーンの簡単な分析

1. はじめに

継承とプロトタイプ チェーンJavaScript のフロントエンドを学習する過程で遭遇した、珍しく理解しにくい部分ですが、まだこれで苦労している兄弟たちにヒントを与えられればと思い、私が知っていること、学んだことすべてをここに記録します。私を助けてください、そして私を批判したり修正したりすることも歓迎します。

2. コンストラクター

2.1 コンストラクターのインスタンス メンバーと静的メンバー

コンストラクターは、インスタンス メンバーと静的メンバーの両方で構成されます。

this キーワードを使用して関数内に追加されたメンバーです。後でインスタンス化されたオブジェクトを介してのみアクセスできます。一方、静的メンバーは関数自体に追加されたメンバーであり、コンストラクターを介してのみアクセスできます。

//创造一个构造函数let Father = function(name,age){
    //实例成员
    this.name = name;
    this.age = age;
    this.method = "我是一个实例成员";}
    //静态成员Father.like = "mother";
    //检验实例对象是否能够被构造函数直接访问console.log(Father.method);
    //undefinedconsole.log(Father.like);
    //mother
    //实例化一个对象let father = new Father("小王",27);
    //检验静态对象是否能够被实例化对象访问console.log(father.name);
    //小王console.log(father.age);
    //27console.log(father.like);
    //undefined
2.2 オブジェクトのインスタンス化のプロセス

インスタンス化されたオブジェクトは、

new キーワードを使用してコンストラクターを介して実装できます。では、特定のインスタンス化プロセス中に何が起こるでしょうか? Woolen布?大きく分けて以下の手順になります。

(1) 空のオブジェクトsonを作成する {}

(2) Sonのプロトタイプチェーン接続を準備する

son.__proto__ = Father .prototype

(3) コンストラクターの this が新しいオブジェクト

Father.call(this)

(4) を指すようにこれを再バインドします。新しいオブジェクト属性の割り当て

son.name

(5) これを返します

return this. この時点で、新しいオブジェクトにはコンストラクターのメソッドとプロパティが含まれます

ちょっとした質問: オブジェクトをインスタンス化するメソッドはすべて共有されていますか?
関数を構築する方法は 2 つあります。1 つ目は関数内で直接定義されたメソッドで、2 つ目はプロトタイプを通じて追加されたメソッドです。

//函数内部直接定义的方法let Father = function(){
    this.read = function(){
        console.log("我是内部定义的read方法!");
    }}//通过JavaScript の継承とプロトタイプ チェーンの簡単な分析添加的方法Father.prototype.look = function(){
    console.log("我是通过JavaScript の継承とプロトタイプ チェーンの簡単な分析定义的look方法!");}
    //实例化对象进行检验let father1 = new Father();let father2 = new Father();
    father1.read();
    //我是内部定义的read方法!father2.read();
    //我是内部定义的read方法!console.log(father1.read === father2.read);
    //falsefather1.look();
    //我是通过JavaScript の継承とプロトタイプ チェーンの簡単な分析定义的look方法!father2.look();
    //我是通过JavaScript の継承とプロトタイプ チェーンの簡単な分析定义的look方法!console.log(father1.look === father2.look);
    /true
内部で直接定義されていることがわかります。関数 定義されたメソッドに対して新しいオブジェクトがインスタンス化されるたびに、新しいメモリ空間がこのメソッドに割り当てられ、プロトタイプを通じて追加されたメソッドは同じ空間を共有します。

小さな質問: インスタンス化されたすべてのオブジェクトのプロパティは共有されますか?
メモリ容量の問題はありませんが、判定する際は値が同じかどうかで決まります;

let Father = function(name){
    this.name = name;}let father1 = new Father("小王");
    let father2 = new Father("小红");
    console.log(father1.name === father2.name);
    //falselet father1 = new Father("小王");
    let father2 = new Father("小王");
    console.log(father1.name === father2.name);
    //true
ということで、コンストラクタ定義の基本的なルールをまとめると次のようになります。

public 属性はコンストラクターに定義されます。内部では、プロトタイプ オブジェクトに public メソッドを配置します。

3. プロトタイプ

3.1 プロトタイプとは

Father.prototype はプロトタイプであり、オブジェクトであり、プロトタイプオブジェクトと呼ばれます。

3.2 プロトタイプの役割とは

プロトタイプの役割はメソッドを共有することです。

Father.prototype.method を通じてメソッドを共有できますが、これはスペース ストレージ メソッドを反映しません。

3.3 プロトタイプの this はどこを指しますか?

プロトタイプの this のポイントはインスタンスです。

4. プロトタイプ チェーン

プロトタイプ チェーンは、初心者や一部のフロントエンド初心者 (私など) にとっては特に理解しにくいものだと感じています。以下の部分を理解しやすくするために、ここで次の点を覚えておくことが必須です。

  1. __proto__ はすべてのオブジェクトが持つ属性であり、プロトタイプはオブジェクトに固有です。各関数のメソッド;
  2. 各オブジェクトの
  3. __proto__ 属性は、独自のコンストラクターのプロトタイプを指します。
  4. コンストラクター属性は、常に、関数を作成したコンストラクターを指します。現在のオブジェクト;
  5. Function.__proto__ === Function.prototype;
  6. Object.prototype.__proto__ === null はエンドポイントですプロトタイプ チェーンの;
4.1 プロトタイプ チェーンとは

#プロトタイプをレイヤーごとにリンクするプロセスがプロトタイプ チェーンです。

4.2 プロトタイプ チェーンの適用

オブジェクトには

__proto__ があるため、オブジェクトはコンストラクター プロトタイプ プロトタイプ オブジェクトのプロパティとメソッドを使用できます。プロトタイプの存在は #各オブジェクト ##__proto__プロトタイプの存在<pre class="brush:php;toolbar:false">let Father = function(name){     this.name = name;}let father = new Father(&quot;老王&quot;);console.log(father.__proto__ === Father.prototype);     //true     //验证上述说法中的第二条</pre>4.3 プロトタイプチェーン図

JavaScript の継承とプロトタイプ チェーンの簡単な分析先頭に書いた点と合わせると、プロトタイプは存在しないはずです。上の図を理解する上で問題があります。もっと大きくて、図の丸で囲まれた部分が恐ろしいプロトタイプチェーンです。

4.4 プロトタイプチェーンの検索方法

function Star(name) {
	this.name = name;
	//(1)首先看obj对象身上是否有dance方法,如果有,则执行对象身上的方法
	this.dance = function () {
		console.log(this.name + '1');
	}}//(2)如果没有dance方法,就去构造函数原型对象prototype身上去查找dance这个方法。Star.prototype.dance = function () {
	console.log(this.name + '2');};
	//(3)如果再没有dance方法,就去Object原型对象prototype身上去查找dance这个方法。Object.prototype.dance = function () {
	console.log(this.name + '3');};
	//(4)如果再没有,则会报错。let obj = new Star('小红');obj.dance();

(1) まず、obj オブジェクトにダンスメソッドがあるかどうかを確認し、存在する場合はそのオブジェクトに対してメソッドを実行します。

(2) ダンス メソッドがない場合は、コンストラクター プロトタイプ オブジェクト プロトタイプに移動してダンス メソッドを見つけます。

(3) ダンス メソッドがない場合は、オブジェクト プロトタイプ オブジェクト プロトタイプに移動してダンス メソッドを見つけます。

(4) それ以上ない場合は、エラーが報告されます。

一个小问题:在原型上添加方法需要注意的地方

有两种添加方法,第一种为上面的写法,直接通过 构造函数.prototype.方法名 进行添加;第二种为重定义构造函数的prototype,但是此种情况会丢失掉原有的constructor构造器,所以一定要再连接回去,例子如下:

function Star(name) {
	this.name = name;}Star.prototype = {
    dance:function(){
    	console.log("重定义prototype");
	}}Star.prototype.constructor = Star;

另外,类似于Array、String这些内置的类是不能这么处理的。

五、继承

这里就长话短说,首先我们要明确继承需要继承哪些东西,在前文中我们提到了定义构造函数的基本规则,即**公共属性定义到构造函数里面,公共方法我们放到原型对象身上。**我们所需要继承的东西也不外乎就这二者,公共属性的继承可以通过call()或者apply()进行this的指向定义,而公共方法可以通过原型对象的赋值进行处理,因此我们很容易想到如下的方法:

//定义一个父类function Father(name) {
	this.name = name;}Father.prototype.dance = function () {
	console.log('I am dancing');};//定义一个子类function Son(name, age) {
	Father.call(this, name);
	this.age = age;}//通过赋值的方法连接Son.prototype = Father.prototype;//为子类添加方法Son.prototype.sing = function () {
	console.log('I am singing');};
	let son = new Son('小红', 100);
	//此时父类也被影响了console.log(Father.prototype) 
	//{dance: ƒ, sing: ƒ, constructor: ƒ}

很显然,当我们只想修改子类里面的方法时,显然上述方法不太合适;因此 我们可以尝试new一个新的父类出来,代码如下:

function Father(name) {
	this.name = name;}Father.prototype.dance = function () {
	console.log('I am dancing');};function Son(name, age) {
	Father.call(this, name);
	this.age = age;}Son.prototype = new Father();Son.prototype.sing = function () {
	console.log('I am singing');};let son = new Son('小红', 100);console.log(Father.prototype) 
	//{dance: ƒ, constructor: ƒ}

六、class语法糖

对于以前了解过面向对象编程的程序员来讲,上述关于继承的写法属实让人有些难以接受,因此在es6里面新增了一个语法糖来更方便更便捷地书写继承,这里就直接上代码了;

class Father {
	constructor(name) {
		this.name = name;
	}
	dance() {
		console.log("我是" + this.name + ",我今年" + this.age + "岁," + "我在跳舞");
	}}class Son extends Father {
	constructor(name, age) {
		super(name);
		this.age = age;
	}
	sing() {
		console.log("我是" + this.name + ",我今年" + this.age + "岁," + "我在唱歌");
	}}let obj = new Son('小红', 19);
	obj.sing();obj.dance();

分析一下上面代码,首先一个类(构造函数)里面依旧为两部分,即公共属性和公共方法,constructor() 里面存放了该构造函数的公共属性,后面接着的便是公共方法,extends 关键字表示继承的是哪个类,super() 便是将里面父类里面相应的公共属性拿出来,这样看下来便可以将代码规整许多。

相关推荐:javascript学习教程

以上がJavaScript の継承とプロトタイプ チェーンの簡単な分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はcsdn.netで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。