ホームページ > 記事 > ウェブフロントエンド > JavaScript の継承とプロトタイプ チェーンの簡単な分析
この記事では、コンストラクター、プロトタイプ、クラス構文シュガーに関連する問題など、javascript の継承とプロトタイプ チェーンに関する知識を提供します。皆様のお役に立てれば幸いです。
#JavaScript の継承とプロトタイプ チェーンの簡単な分析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); //undefined2.2 オブジェクトのインスタンス化のプロセスインスタンス化されたオブジェクトは、
new キーワードを使用してコンストラクターを介して実装できます。では、特定のインスタンス化プロセス中に何が起こるでしょうか? Woolen布?大きく分けて以下の手順になります。
(1) 空のオブジェクトsonを作成する {}(2) Sonのプロトタイプチェーン接続を準備するson.__proto__ = Father .prototype
Father.call(this)
son.name
return this. この時点で、新しいオブジェクトにはコンストラクターのメソッドとプロパティが含まれます
//函数内部直接定义的方法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 メソッドを配置します。
Father.prototype.method を通じてメソッドを共有できますが、これはスペース ストレージ メソッドを反映しません。
はすべてのオブジェクトが持つ属性であり、プロトタイプはオブジェクトに固有です。各関数のメソッド;
属性は、独自のコンストラクターのプロトタイプを指します。
=== Function.prototype;
=== null はエンドポイントですプロトタイプ チェーンの;
__proto__ があるため、オブジェクトはコンストラクター プロトタイプ プロトタイプ オブジェクトのプロパティとメソッドを使用できます。プロトタイプの存在は #各オブジェクト ##__proto__
プロトタイプの存在<pre class="brush:php;toolbar:false">let Father = function(name){
this.name = name;}let father = new Father("老王");console.log(father.__proto__ === Father.prototype);
//true
//验证上述说法中的第二条</pre>
4.3 プロトタイプチェーン図
先頭に書いた点と合わせると、プロトタイプは存在しないはずです。上の図を理解する上で問題があります。もっと大きくて、図の丸で囲まれた部分が恐ろしいプロトタイプチェーンです。
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();
(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: ƒ}
对于以前了解过面向对象编程的程序员来讲,上述关于继承的写法属实让人有些难以接受,因此在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 サイトの他の関連記事を参照してください。