ホームページ >ウェブフロントエンド >jsチュートリアル >JavaScriptのプロトタイプ継承に関する基礎学習チュートリアル_基礎知識

JavaScriptのプロトタイプ継承に関する基礎学習チュートリアル_基礎知識

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

ほとんどのプログラミング言語にはクラスとオブジェクトがあり、あるクラスは他のクラスを継承できます。
JavaScript では、継承はプロトタイプベースです。つまり、JavaScript にはクラスがなく、代わりに 1 つのオブジェクトが別のオブジェクトを継承します。 :)

1. 継承、プロト
JavaScript では、ウサギのオブジェクトが別のオブジェクトの動物を継承すると、ウサギのオブジェクトに特別な属性が存在することになります: Rabbit.__proto__ = Animal;
Rabbit オブジェクトにアクセスするときに、インタープリタが Rabbit で属性を見つけられない場合、__proto__ チェーンに従い、animal オブジェクトで
を探します。 チェストナットの __proto__ 属性は Chrome と FireFox でのみアクセス可能です。チェストナットを参照してください:

var animal = { eats: true }
var rabbit = { jumps: true }

rabbit.__proto__ = animal // inherit

alert(rabbit.eats) // true

eats 属性は、animal オブジェクトからアクセスされます。
プロパティが Rabbit オブジェクトで見つかった場合、proto プロパティはチェックされません。
別の例として、サブクラスにも Eats 属性がある場合、親クラスの属性にはアクセスできません。

var animal = { eats: true }
var fedUpRabbit = { eats: false}

fedUpRabbit.__proto__ = animal 

alert(fedUpRabbit.eats) // false

animal で関数を追加することもでき、rabbit でアクセスすることもできます。

var animal = {
 eat: function() {
  alert( "I'm full" )
  this.full = true
 }
}


var rabbit = {
 jump: function() { /* something */ }
}

rabbit.__proto__ = animal 

(1) Rabbit.eat():
Rabbit.eat() 関数は次の 2 つのステップで実行されます:
まず、インタープリタは、rabbit.eat を探します。rabbit には Eat 関数がないため、rabbit.__proto__ を検索し、animal で見つけます。
この関数は this = Rabbit で実行されます。 this 値は __proto__ 属性とはまったく関係がありません。
したがって、rabbit では this.full = true:
ここでどのような新しい発見があるかを見てみましょう。オブジェクトは親クラスの関数を呼び出しますが、これは依然としてオブジェクト自体を指します。
__proto__ によって参照されるオブジェクトはプロトタイプと呼ばれ、動物はウサギのプロトタイプです (翻訳者注: これは、ウサギの __proto__ 属性が動物のプロトタイプ属性を参照しているためです)
(2) 書き込み時ではなく、読み取り時に検索
this.prop などのオブジェクトを読み取るとき、インタプリタはそのプロトタイプ内でプロパティを探します。
this.prop = value などのプロパティ値を設定する場合、それを探す必要はありません。プロパティ (prop) はオブジェクト (ここでは this) に直接追加されます。 delete obj.prop も同様で、オブジェクト自体のプロパティのみを削除し、プロトタイプ内のプロパティはそのまま残ります。
(3) プロト
について ガイドをお読みの場合、ここで __proto__ と呼ぶものは、ガイド内では [[プロトタイプ]] として表されます。プロトタイプと呼ばれる別の属性があるため、二重括弧は重要です。

2. Object.create、Object.getPrototypeOf
__proto__ は Chrome/FireFox によって提供される非標準属性であり、他のブラウザでは表示されません。
Opera (IE > 9) を除くすべての最新ブラウザは、プロトタイプの問題を処理するための 2 つの標準関数をサポートしています:

Object.ceate(prop[,props])

指定されたプロトで空のオブジェクトを作成します:

var animal = { eats: true }

rabbit = Object.create(animal)

alert(rabbit.eats) // true

上記のコードは空のウサギのオブジェクトを作成し、プロトタイプをanimalに設定します
ウサギ オブジェクトが作成されたら、それに属性を追加できます:

var animal = { eats: true }

rabbit = Object.create(animal)
rabbit.jumps = true

Object.creat 関数の 2 番目のパラメーター props はオプションであり、新しいオブジェクトと同様にプロパティを設定できます。関係の継承のため、ここでは省略します。
(1) Object.getPrototypeOf(obj)
obj.__proto__ の値を返します。この関数は標準であり、__proto__ 属性に直接アクセスできないブラウザで使用できます。

var animal = {
 eats: true
}

rabbit = Object.create(animal)

alert( Object.getPrototypeOf(rabbit) === animal ) // true

最新のブラウザでは、__proto__ 属性値を読み取ることはできますが、設定することはできません。

3. プロトタイプ
__proto__ 属性を設定するには、コンストラクター関数を使用する、ブラウザーを超えた優れた方法がいくつかあります。覚えて!どの関数も new キーワードを使用してオブジェクトを作成します。
栗:

function Rabbit(name) {
 this.name = name
}

var rabbit = new Rabbit('John')

alert(rabbit.name) // John

新しいオペレーションは、プロトタイプの属性を Rabbit オブジェクトの __proto__ 属性に設定します。
たとえば、新しい Rabbit オブジェクトと Rabbit がanimal から継承する様子を見てみましょう。

var animal = { eats: true }

function Rabbit(name) {
 this.name = name
}

Rabbit.prototype = animal

var rabbit = new Rabbit('John')

alert( rabbit.eats ) // true, because rabbit.__proto__ == animal

Rabbit.prototype = Animal リテラルの意味: 新しい Rabbit によって作成されたすべてのオブジェクトに対して __proto__ = Animal

を設定します

4. クロスブラウザー Object.create(proto)
Object.create(prop) 関数は、特定のオブジェクトから直接継承できるため、強力です。次のコードでシミュレートできます:

function inherit(proto) {
 function F() {}
 F.prototype = proto
 return new F
}

inherit(animal) は Object.create(animal) と完全に同等で、空のオブジェクトと object.__proto__ = anime を返します。
栗:

var animal = { eats: true }

var rabbit = inherit(animal)

alert(rabbit.eats) // true
alert(rabbit.hasOwnProperty('eats')) // false, from prototype

それがどのように機能するかを見てみましょう:

function inherit(proto) {
 function F() {}   // (1)
 F.prototype = proto // (2)
 return new F()   // (3)
}

(1) 创建了一个新函数,函数没有向this设置任何属性,以此`new F` 会创建一个空对象。
(2) `F.prototype`被设置为proto
(3) `new` F创建了一个空对象,对象的`__proto__ = F.prototype`
(4) Bingo! 我们得到了一个继承`proto`的空对象
这个函数广泛适用于各种库和框架之中。
你的函数接受了一个带有options 的对象

/* options contains menu settings: width, height etc */
function Menu(options) {
 // ...
}
你想设置某些options
function Menu(options) {
 options.width = options.width || 300 // set default value
 // ...
}

。。。但是改变参数值可能会产生一些错误的结果,因为options可能会在外部代码中使用。一个解决办法就是克隆options对象,复制所有的属性到一个新的对象中,在新对象中修改,
怎样用继承来解决这个问题呢? P.S. options可以添加设设置,但是不能被删除。
Solution
你可以继承options,并且在它的子类的中修改或者添加新的属性。

function inherit(proto) {
 function F() {}
 F.prototype = proto
 return new F
}

function Menu(options) {
 var opts = inherit(options)
 opts.width = opts.width || 300
 // ...
}

所有的操作只在子对象中有效,当Menu方法结束时,外部代码仍然可以使用没有修改的过的options对象。delete操作在这里非常重要,如果width是一个prototype中的属性,delete opts.width不会产生任何作用

5. hasOwnProperty
所有的对象都有hasOwnProperty函数,它可以用来检测一个属性是否对象自身还是属于原型
一个栗子:

function Rabbit(name) {
 this.name = name
}

Rabbit.prototype = { eats: true }

var rabbit = new Rabbit('John')

alert( rabbit.hasOwnProperty('eats') ) // false, in prototype

alert( rabbit.hasOwnProperty('name') ) // true, in object

6. Looping with/without inherited properties
for..in循环输出一个对象的所有属性,包括自身的和原型的。

function Rabbit(name) {
 this.name = name
}

Rabbit.prototype = { eats: true }

var rabbit = new Rabbit('John')

for(var p in rabbit) {
 alert (p + " = " + rabbit[p]) // outputs both "name" and "eats"
}

用hasOwnProperty可以过滤得到属于对象自己的属性:

function Rabbit(name) {
 this.name = name
}

Rabbit.prototype = { eats: true }

var rabbit = new Rabbit('John')

for(var p in rabbit) {
 if (!rabbit.hasOwnProperty(p)) continue // filter out "eats"
 alert (p + " = " + rabbit[p]) // outputs only "name"
}

7. Summary
JavaScript是通过一个特殊的属性proto来实现继承的
当访问一个对象的属性时,如果解释器不能在对象中找到,它就会去对象的原型中继续寻找 对函数属性来说,this指向这个对象,而不是它的原型。
赋值obj.prop = value, 删除delete obj.prop
管理proto:
Chrome和FireFox可以直接访问对象的__proto__属性,大多数现代浏览器支持用Object.getPrototypeOf(obj)只读访问。
Object.create(proto) 可以用给定的proto生成空的子对象,或者通过如下代码达到相同的功能:

function inherit(proto) {
   function F() {}   
   F.prototype = proto
   return new F()  
  }

其他方法:
for..in循环输出一个对象的所有属性(包括自身的和原型的)和对象的原型链。
如果一个属性prop属于对象obj那么obj.hasOwnProperty(prop)返回true,否则返回false。

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