ホームページ  >  記事  >  ウェブフロントエンド  >  JavaScript プロトタイプとプロトタイプ チェーン メソッドの概要 (コード例)

JavaScript プロトタイプとプロトタイプ チェーン メソッドの概要 (コード例)

不言
不言転載
2019-01-10 10:59:442671ブラウズ

この記事では、JavaScript プロトタイプとプロトタイプ チェーン メソッド (コード例) について説明します。必要な方は参考にしていただければ幸いです。

1. 質問

変数が配列であるかどうかを正確に判断する方法

プロトタイプ チェーンの継承の例を書く

継承実装の他の方法

es6 継承の基礎となる原理は何ですか

新しいオブジェクトのプロセスについて説明します

zepto および でプロトタイプ チェーンを使用する方法その他のソース コード

2. 知識ポイント

2.1 コンストラクター

特徴: 大文字で始まる

function Foo(name,age){
    //var obj = {}
    //this = {}
    this.name = name;
    this.age = age;
    this.class = 'class1'
    // return this
}

var f1 = new Foo('liming',19);

拡張子

var o = {} は、var o = new Object()の糖衣構文です。

var a = [] は、var a = new Array()

の糖衣構文です。 function Foo(){} は、var Foo = new Function(){}

2.2 プロトタイプのルール

5 つのルール:

1 と同等です。すべての参照型 (オブジェクト、配列、関数) はすべてオブジェクト特性を持っています。つまり、属性は自由に拡張できます。

2. すべての参照型 (オブジェクト、配列、関数) には __proto__ (暗黙のプロトタイプ) 属性があります。これは通常のオブジェクトです。

3. すべての関数はプロトタイプ (明示的なプロトタイプ) 属性を持ち、通常のオブジェクトでもあります。

4. すべての参照型 (オブジェクト、配列、関数) の __proto__ 値は、コンストラクターのプロトタイプ

5。オブジェクトの属性を取得しようとするとき、変数自体にこの属性がない場合、変数はその __proto__ に移動してそれを見つけます

#
for (var key in object) {
    //高级浏览器中已经屏蔽了来自原型的属性
    //建议加上判断保证程序的健壮性
    if (object.hasOwnProperty(key)) {
        console.log(object[key]);
    }
}

#2.3 プロトタイプ チェーン

obj.__ プロト

. プロト . プロト __ ...

Object.prototype === null

instanceof は参照型がどのコンストラクタに属するかを判断するために使用されます

obj instanceob Foo

実際の意味: Foo.prototype が obj# のプロトタイプ チェーン上にあるかどうかを判断します

##3. 質問の回答

3.1 変数が配列であるかどうかを正確に判断する方法

arr instanceof Array

#3.2プロトタイプチェーン継承の例

カプセル化 dom クエリ

function Elem(id){
    this.elem = document.getElementById(id);
};

Elem.prototype.html = function(val){
    var elem = this.elem;
    if (val) {
        elem.innerHTML = val;
        return this;
    }else{
        return elem.innerHTML;
    }
}

Elem.prototype.on = function(type,fun){
    var elem = this.elem;
    elem.addEventListener(type,fun);
    return this;
}

var p1 = new Elem('id1');
p1.html("test").on('click',function(){
    console.log('点击');
})

3.3 他の継承実装方法

3.3.1 プロトタイプ継承

        var obj = {
            0:'a',
            1:'b',
            arr:[1]
        }
        
        function Foo(arr2){
            this.arr2 = [1]
        }

        Foo.prototype = obj;

        var foo1 = new Foo();
        var foo2 = new Foo();

        foo1.arr.push(2);
        foo1.arr2.push(2);

        console.log(foo2.arr);  //[1,2]
        console.log(foo2.arr2); //[1]
利点: 実装が簡単

#欠点:

1. 親クラスのコンストラクターにパラメーターを渡すことができません

2. 新しい 2 つのオブジェクトが同時に使用される場合。 1 つのオブジェクトのプロトタイプ内の参照型属性が変更されると、もう 1 つのオブジェクトの属性も変更されます。プロトタイプ オブジェクトからの参照プロパティはすべてのインスタンスで共有されるためです。

3.3.2 構造継承

        function Super(b){
            this.b = b;
            this.fun = function(){}
        }
        function Foo(a,b){
            this.a = a;
            Super.call(this,b);
        }

        var foo1 = new Foo(1,2);
        console.log(foo1.b);

利点: 親クラスにパラメータを渡すことができますが、サブクラスは親クラスの参照属性を共有しません

欠点:関数の再利用ができない、サブクラスごとに新しい楽しみがある、多すぎるとパフォーマンスに影響する、親クラスのプロトタイプオブジェクトを継承できない。

3.3.3 結合継承

function Super(){
    // 只在此处声明基本属性和引用属性
    this.val = 1;
    this.arr = [1];
}
//  在此处声明函数
Super.prototype.fun1 = function(){};
Super.prototype.fun2 = function(){};
//Super.prototype.fun3...
function Sub(){
    Super.call(this);   // 核心
    // ...
}
Sub.prototype = new Super();

利点: 参照属性の共有の問題がなく、パラメータの受け渡しが可能、関数の再利用が可能

欠点: の属性親クラスがインスタンス化されます 二度変換すると、実際のインスタンスの親クラスが取得できません(親クラスでインスタンスが作成されたかどうか区別できません)

最適化:

         function Super(b){
            this.b = b;
            this.fun = function(){}
        }

        Super.prototype.c = function(){console.log(1111)}

        function Foo(a,b){
            this.a = a;
            Super.call(this,b);
        }


        Foo.prototype = Super.prototype;
        //修复构造函数:
        var foo1 = new Foo(1,2);

欠点: インスタンスが親クラスによって作成されたかどうかを区別することができません。 サブクラスの作成

3.3.4 寄生組み合わせ継承

         function Super(b){
            this.b = b;
        }

        Super.prototype.c = function(){console.log(1111)}

        function Foo(a,b){
            this.a = a;
            Super.call(this,b);
        }

        var f = new Function();
        f.prototype = Super.prototype;
        Foo.prototype = new f();
        //等同于 Foo.prototype = Object.create(Super.prototype);
        
        var foo1 = new Foo(1,2);

親クラスのプロトタイプに寄生します。 、それを空のオブジェクトのプロトタイプにラップし、このオブジェクトを子 Class peototype としてインスタンス化します。

欠点: インスタンスが親クラスによって作成されたかサブクラスによって作成されたかを区別することは不可能です。

次のコードを追加できます:

Foo.prototype.constructor = Foo

この解決策は使用できません。上記の組み合わせ最適化手法で使用される場合、サブクラスと親クラスは同じプロトタイプ オブジェクトを参照するため、変更は同時に行われます。

概要:

継承は主に、サブクラスによる親クラスのメソッドと属性の再利用を実現することです。

プロトタイプ オブジェクトからの参照プロパティはすべてのインスタンスで共有されるため、プロトタイプからプロパティを継承することは避けたいと考えています。

コンストラクター内の call 関数を通じて親クラス コンストラクターの属性とメソッドを継承できますが、この方法でインスタンス化されたインスタンスには親クラスのメソッドが複数回格納されるため、パフォーマンスに影響します。

結合継承により、呼び出し継承プロパティとプロトタイプ継承メソッドを使用して上記の 2 つの問題を解決しますが、この方法でインスタンス化されたオブジェクトは、親クラスのコンストラクターにプロパティの 2 つのコピーを格納します。

親クラスのプロトタイプを使用して、サブクラスのプロトタイプとして新しいオブジェクトを構築すると、複数のストレージの問題が解決されるため、最後の寄生組み合わせ継承が最良の継承方法であるという欠点があります。書くのが面倒。

3.3.6 ノードソースコードでの継承実装

function inherits(ctor, superCtor) {
  ctor.super_ = superCtor;
  ctor.prototype = Object.create(superCtor.prototype, {
    constructor: {
      value: ctor,
      enumerable: false,
      writable: true,
      configurable: true
    }
  });
}; 

function Stream(){
    //...
}

function OutgoingMessage() {
  Stream.call(this);
  //...
}

inherits(OutgoingMessage, Stream);

OutgoingMessage.prototype.setTimeout = ...

上記は寄生組み合わせ継承の例です。

1. OutcomingMessage コンストラクターを呼び出して、Stream コンストラクターのプロパティを継承します。

2. Stream プロトタイプのプロパティを継承するには、inherits メソッドを呼び出します。

3. OutcomingMessage 独自のプロトタイプを拡張する関数。

Object.create メソッドは、継承メソッドで使用されます。このメソッドの機能は、指定されたプロトタイプ オブジェクトとプロパティを通じて新しいオブジェクトを作成することです。

ctor.prototype=Object.create(superCtor.prototype,{.....});

このメソッドは、実際に上記の寄生組み合わせ継承の作業を実行します。

var f = new Function();
f.prototype =superCtor.prototype;
return new f();

次のパラメータは、プロトタイプ オブジェクトに属性、オプションの属性 (必須ではありません) を追加するためのものです。つまり、Serves を追加します。それ自体を新しく作成されたオブジェクトのコンストラクターとして使用します。

value: 表示constructor 的属性值;
writable: 表示constructor 的属性值是否可写;[默认为: false]
enumerable: 表示属性constructor 是否可以被枚举;[默认为: false]
configurable: 表示属性constructor 是否可以被配置,例如 对obj.a做 delete操作是否允许;[默认为: false]

3.4 es6 継承の実装方法

私の記事を参照してください: https://segmentfault.com/a/11...

3.5 描述new一个对象的过程

  1. 创建一个对象

  2. {}._proto_ = 构造函数.prototype

  3. this指向这个对象

  4. 执行代码即对this赋值

  5. 返回this

3.6 zepto及其他源码中如何使用原型链

var Zepto = (function(){

    var $,zepto = {}
    
    // ...省略N行代码...
    
    $ = function(selector, context){
        return zepto.init(selector, context)
    }

    zepto.init = function(selector, context) {
        var dom
        
        // 针对参数情况,分别对dom赋值
        
        // 最终调用 zepto.Z 返回的数据
        return zepto.Z(dom, selector)
    }    

   fnction Z(dom, selector) {
      var i, len = dom ? dom.length : 0
     for (i = 0; i < len; i++) this[i] = dom[i]
      this.length = len
      this.selector = selector || ''
    }

   zepto.Z = function(dom, selector) {
     return new Z(dom, selector)
   }
  
    $.fn = {
        // 里面有若干个工具函数
    }
      
  
    zepto.Z.prototype = Z.prototype = $.fn
  
    
    // ...省略N行代码...
    
    return $
})()

window.Zepto = Zepto
window.$ === undefined && (window.$ = Zepto)

以上がJavaScript プロトタイプとプロトタイプ チェーン メソッドの概要 (コード例)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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