一般的なパターンとプロトタイプ チェーンを理解する

PHP中文网
リリース: 2017-06-20 09:37:30
オリジナル
1715 人が閲覧しました

内容:

  • オブジェクト作成のいくつかのモードと作成プロセス

  • プロトタイプチェーンプロトタイプ、prototype__proto__ ([ [プロトタイプ]]) 関係prototype与 __proto__[[Prototype]])的关系

  • 继承的几种实现


1.常见模式与原型链的理解

a.构造函数创建

function Test() {// 
}
ログイン後にコピー

流程

  • 创建函数的时候会默认为Test创建一个prototype属性,Test.prototype包含一个指针指向的是Object.prototype

  • prototype默认会有一个constructor,且Test.prototype.constructor = Test

  • prototype里的其它方法都是从Object继承而来


示例
// 调用构造函数创建实例
var instance = new Test()
ログイン後にコピー

此处的instance包含了一个指针指向构造函数的原型,(此处的指针在chrome里叫__proto__,也等于[[Prototype]]


示例

b.原型模式
由上我们可以知道,默认创建的prototype属性只拥有constructor和继承至Object的属性,原型模式就是为prototype添加属性和方法

Test.prototype.getName = ()=> {
    alert('name')
}
ログイン後にコピー

此时的instance实例就拥有了getName方法,因为实例的指针是指向Test.prototype的

instance.__proto__ === Test.prototype
ログイン後にコピー

如下图所示


897RVF]E5@IX$)`IVJ3BOSY.png

这里我们可得知:实例instance与构造函数之间是通过原型prototype来相关联的。

c.组合模式
这种模式我们用的最多,其实也是原型模式的另一种写法,只不过有一点小区别而已

function Test() {}

Test.prototype = {
    getName() {
        alert('name')
    }
}
ログイン後にコピー

我们经常会这么直接重写prototype方法,由上我们可知,prototype会默认自带constructor属性指向构造函数本身,那么重写以后呢?

Test.prototype.constructor === Object 
// 而并不等于Test了// 因为重写以后相当于利用字面量方式创建一个实例对象,这个实例的构造函数是指向Object本身的
ログイン後にコピー

当然我们也可以手动赋值constructor

Test.prototype = {
    constructor: Test,
    getName() {
        alert('name')
    }
}
ログイン後にコピー

那么又会有疑问了constructor要不要有何意义?我觉得constructor意义仅仅是为了来鉴别原型所属的构造函数吧。

当需要获取某个属性的时候,会先从实例中查找,没有就根据指针所指向的原型去查找,依次向上,直到实例的指针__proto__指向为null时停止查找,例如:

// 1 读取nameinstance.name 

// 2 instance.__proto__ === Test.prototypeTest.prototype.name

// 3 Test.prototype.__proto__ === Object.prototypeObject.prototype.name

// 4Object.prototype.__proto__ === null
ログイン後にコピー

当找到了这个属性就会直接返回,而不会继续查找,即使这个属性值为null,想要继续查找,我们可以通过delete操作符来实现。

由这里我们自然可以想到Array, Date, Function, String,都是一个构造函数,他们的原型的指针都是指向Object.prototype,它们就像我这里定义的Test一样,只不过是原生自带而已

d.几个有用的方法

  • Object.getPrototypeOf() 获取某个实例的指针所指向的原型

    Object.getPrototypeOf(instance) === Test.prototype
    ログイン後にコピー
  • hasOwnProperty 判断一个属性是存在于实例中还是存在于原型中,如图所示:


    NY~N}CNR`}8W%4QA$M8LFE4.png
  • in操作符,无论该属性是否可枚举

    'name' in instance  // true
    'getName' in instance // true
    ログイン後にコピー

    无论属性是在实例中,还是在原型中都返回true,所以当我们需要判断一个属性存在与实例中,还是原型中有2种办法

    // 一种就是使用hasOwnProperty判断在实例中
    // 另一种判断在原型中
    instance.hasOwnProperty('getName') === false && 'getName' in instance === true
    ログイン後にコピー
  • for ... in

    継承のいくつかの実装

1. 共通パターンとプロトタイプ構築関数の作成について理解する。

Object.keys(instance)// ["name"]
ログイン後にコピー
ログイン後にコピー
プロセス🎜🎜🎜🎜 関数を作成すると、デフォルトで Test.prototypeObject.prototype を指すポインターが含まれるプロトタイプ属性が作成されます。 🎜🎜🎜プロトタイプにはデフォルトでコンストラクターがあり、Test.prototype.constructor = Test🎜🎜🎜🎜プロトタイプ内の他のメソッドは Object から継承されます🎜🎜🎜🎜🎜例🎜🎜
// 定义父类function Parent() {}Parent.prototype.getName = ()=> {
    console.log('parent')
}// 实例化父类let parent = new Parent()// 定义子类function Child() {}
Child.prototype = parent 
// 实例化子类let child = new Child()

child.getName() // parent// 此时
child.constructor === parent.constructor === Parent
ログイン後にコピー
ログイン後にコピー
🎜ここのインスタンスには、次のプロトタイプを指すポインターが含まれています。コンストラクター (ここでのポインターは、Chrome では __proto__ と呼ばれます。これは [[Prototype]] とも同じです)🎜🎜🎜🎜例🎜🎜🎜b. プロトタイプモード🎜 上記から、prototype 属性が作成されたことがわかります。デフォルトではObjectから継承したコンストラクターとプロパティのみを持ちます。プロトタイプモードはプロトタイプにプロパティとメソッドを追加することです🎜
function Parent(name) {this.name = namethis.colors = ['red']
}
Parent.prototype.getName = function() {console.log(this.name)
}// 实例化父类let parent = new Parent()function Child(age, name) {
    Parent.call(this, name)this.age = age
}
Child.prototype = parent 
// 实例化子类let child = new Child(1, 'aaa')
child.getName() // parent
ログイン後にコピー
ログイン後にコピー
🎜このとき、インスタンスのポインタがTestを指しているため、インスタンスにはgetNameメソッドが存在します。 .prototype🎜
class Parent {
    constructor(name) {this.name = namethis.colors = ['red']
    }
    getName() {
        console.log(this.name)
    }
}class Child extends Parent {
    constructor(age, name) {super(name)
    }
}

let child = new Child(1, 'aaa')
child.getName() // parent
ログイン後にコピー
ログイン後にコピー
🎜下図の通り🎜🎜 🎜🎜897RVF]E5@IX$)`IVJ3BOSY .png🎜🎜🎜ここで、インスタンスとコンストラクターがプロトタイプ prototype を通じて関連付けられていることがわかります。 🎜🎜c. 組み合わせモード🎜 これは実際にはプロトタイプ モードを記述する別の方法ですが、わずかな違いがあります🎜rrreee🎜 上記のことから、次のことがわかります。プロトタイプには、デフォルトでコンストラクター自体を指すコンストラクター プロパティが含まれますが、書き換えられた後はどうなるでしょうか? 🎜rrreee🎜もちろん、コンストラクターを手動で割り当てることもできます🎜rrreee🎜それでは、constructor の意味は何でしょうか?という質問がまた出てきます。コンストラクターの意味は、プロトタイプが属するコンストラクターを識別することだけだと思います。 🎜🎜特定の属性を取得する必要がある場合、まずインスタンスから検索します。取得できない場合は、ポインタが指すプロトタイプに従って検索し、インスタンス ポインタ __proto__</ まで進みます。 code> は null を指し、検索を停止します。例: 🎜rrreee🎜 この属性が見つかった場合は、検索を続行せずに直接返されます。属性値が null であっても、検索を続行したい場合は、を使用できます。 <code>delete 演算子。 🎜🎜 ここから、Array、Date、Function、String はすべてコンストラクターであり、それらのプロトタイプ ポインターは Object.prototype を指しており、それらは に似ていると自然に考えることができます。 >Test ここで定義したものは単なるネイティブです 🎜🎜d。インスタンス ポインタが指す特定のプロトタイプを取得するためのいくつかの便利なメソッド 🎜🎜🎜🎜 rrreee🎜🎜🎜hasOwnProperty は、次の図に示すように、プロパティがインスタンスに存在するかプロトタイプに存在するかを判断します。 🎜🎜🎜🎜🎜NY~N}CNR`}8W%4QA$M8LFE4.png🎜🎜🎜🎜🎜 in演算子、プロパティが列挙可能かどうか 🎜rrreee🎜 はプロパティがインスタンスにあるかプロトタイプにあるかに関係なく true を返すため、プロパティがインスタンスに存在するかプロトタイプに存在するかを判断する必要がある場合 🎜rrreee🎜🎜 には 2 つのメソッドがあります🎜for...in 演算子は同じですが、列挙可能なプロパティのみがリストされます。IE8 バージョンのバグは、プロパティが列挙可能かどうかです。たとえば、リストされます🎜🎜🎜。 🎜🎜D(%S__GN8404{H9X6PW$DVK.png🎜🎜


name是在实例中定义的,getName是在原型中定义的

  • Object.keys()则不一样,它返回一个对象上所有可枚举的属性,仅仅是该实例中的

    Object.keys(instance)// ["name"]
    ログイン後にコピー
    ログイン後にコピー
  • e.总结
    以上讨论了构造函数,原型和实例的关系:

    • 每个构造函数都有原型对象

    • 每个原型对象都有一个constructor指针指向构造函数

    • 每个实例都有一个__proto__指针指向原型

    2.继承

    其实是一个道理,这里我们不难想到,将Child.prototype指向parent实例,就是利用原型实现的继承,而为了每个实例都拥有各自的colors和name,也就是基础属性,在Child的构造函数中call调用了Parent的构造函数,相当于每次实例化的时候都初始化一遍colors和name,而不是所有实例共享原型链中的colors和name。

    继承的实质是利用构造函数的原型 = 某个构造函数的实例,以此来形成原型链。例如

    // 定义父类function Parent() {}Parent.prototype.getName = ()=> {
        console.log(&#39;parent&#39;)
    }// 实例化父类let parent = new Parent()// 定义子类function Child() {}
    Child.prototype = parent 
    // 实例化子类let child = new Child()
    
    child.getName() // parent// 此时
    child.constructor === parent.constructor === Parent
    ログイン後にコピー
    ログイン後にコピー

    a.最经典的继承模式

    function Parent(name) {this.name = namethis.colors = [&#39;red&#39;]
    }
    Parent.prototype.getName = function() {console.log(this.name)
    }// 实例化父类let parent = new Parent()function Child(age, name) {
        Parent.call(this, name)this.age = age
    }
    Child.prototype = parent 
    // 实例化子类let child = new Child(1, &#39;aaa&#39;)
    child.getName() // parent
    ログイン後にコピー
    ログイン後にコピー

    这里会让我想到ES6中的class继承

    class Parent {
        constructor(name) {this.name = namethis.colors = [&#39;red&#39;]
        }
        getName() {
            console.log(this.name)
        }
    }class Child extends Parent {
        constructor(age, name) {super(name)
        }
    }
    
    let child = new Child(1, &#39;aaa&#39;)
    child.getName() // parent
    ログイン後にコピー
    ログイン後にコピー

    以上が一般的なパターンとプロトタイプ チェーンを理解するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

    ソース:php.cn
    前の記事:Angularjs ドロップダウン ボックスの空のソリューション 次の記事:関連するルールに関するある程度の知識
    このウェブサイトの声明
    この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
    著者別の最新記事
    最新の問題
    関連トピック
    詳細>
    人気のおすすめ
    人気のチュートリアル
    詳細>
    最新のダウンロード
    詳細>
    ウェブエフェクト
    公式サイト
    サイト素材
    フロントエンドテンプレート
    私たちについて 免責事項 Sitemap
    PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!