コンストラクタ内の方法とコンストラクタprototype属性上の方法の比較


非常に有用な文章です.今日はまた、構造関数についての方法と原型についての質問があります.構造関数の方法は関数の内容を定義しています.プライベートな方法として、公開していません.プロトタイプは対象によって定義されます.
                        JavaScript      ,            prototype   ;        .
読みやすいように、構造関数に方法を書く場合は、私達は単に といいます.方法をprototype属性に書く場合は、私達は単にprototype といいます.
まずこの文章のポイントを理解します.
  • 関数内の方法:関数内の方法を使うと、関数内部のプライベート変数にアクセスできます.構造関数newを通して出てきたオブジェクトが、構造関数内部のプライベート変数を操作する必要があるなら、この時は関数内の方法を考慮します.
  • prototype上の方法:一つの関数を通して大量のオブジェクトを作成する必要があり、これらのオブジェクトはまだ多くの方法がある場合.このとき、私たちは関数のプロトタイプにこれらの方法を追加することを考慮します.この場合、私たちのコードのメモリ占有率は比較的小さいです.
  • は、実際のアプリケーションでは、これらの2つの方法はしばしば組み合わせて使用される.私たちはまず私たちが必要なものを知ってから、どのように使うかを選択します.
    私達はやはり下のコードでこれらのポイントを説明しましょう.以下はコードの部分です.
    //     A
    function A(name) {
        this.name = name || 'a';
        this.sayHello = function() {
            console.log('Hello, my name is: ' + this.name);
        }
    }
    
    //     B
    function B(name) {
        this.name = name || 'b';
    }
    B.prototype.sayHello = function() {
        console.log('Hello, my name is: ' + this.name);
    };
    
    var a1 = new A('a1');
    var a2 = new A('a2');
    a1.sayHello();
    a2.sayHello();
    
    var b1 = new B('b1');
    var b2 = new B('b2');
    b1.sayHello();
    b2.sayHello();
    まず二つのコンストラクタを書きました.第一はAで、このコンストラクタには一つの方法sayHelloが含まれています.第二は、構造関数Bであり、その方法sayHelloを、構造関数Bprototypeの属性の上に書いている.
    この二つの構造関数newを通して出てくるオブジェクトは同じ属性と方法を持っているが、その違いは次の図で説明できる.
    私たちは、構造関数Aを使用して、2つのオブジェクトを作成しました.それぞれa1a2です.構造関数Bによって2つのオブジェクトb1b2が作成された.b1b2の2つのオブジェクトのうちのsayHello方法は、それらの構造関数のprototype属性を指すsayHelloの方法であることが分かります.a1a2は、すべて自分の内部でこの方法を定義しています.
    この方法はコンストラクタ内部で定義されています.各例でクローンされます.構造関数のprototype属性に定義された方法は、この方法をすべての例で共有するが、この方法は各例の内部では再定義されない.もし私たちのアプリケーションが多くの新しいオブジェクトを作成する必要があるならば、メモリを節約するために、これらの方法を構造関数のprototype属性に定義することを提案する.
    もちろん、いくつかの場合には、構造関数にいくつかの方法を定義する必要があります.この場合は、構造関数内部の私有変数にアクセスする必要があります.
    二つの組み合わせの例を挙げます.コードは以下の通りです.
    function Person(name, family) {
        this.name = name;
        this.family = family;
    
        var records = [{type: "in", amount: 0}];
    
        this.addTransaction = function(trans) {
            if(trans.hasOwnProperty("type") && trans.hasOwnProperty("amount")) {
               records.push(trans);
            }
        }
    
        this.balance = function() {
           var total = 0;
    
           records.forEach(function(record) {
               if(record.type === "in") {
                 total += record.amount;
               }
               else {
                 total -= record.amount;
               }
           });
    
            return total;
        };
    };
    
    Person.prototype.getFull = function() {
        return this.name + " " + this.family;
    };
    
    Person.prototype.getProfile = function() {
         return this.getFull() + ", total balance: " + this.balance();
    };
    上記のコードでは、Personコンストラクションを定義しました.この関数には、内部のプライベート変数recordsがあります.この変数は、関数の内部以外の方法でこの変数を操作したくないので、この変数を操作する方法を関数の内部に書いて、公開できる方法をPersonprototype属性に書いています.例えば、方法getFullgetProfile.
    方法をコンストラクタの内部に書いて、コンストラクタを通じて一つのオブジェクトを初期化するコストが増えました.このようなコストはprototype属性に書くと効果的に減少します.オブジェクトを呼び出す方法はプロトタイプチェーンを呼び出す方法よりずっと速いと感じるかもしれません.実はそうではありません.もしあなたのオブジェクトの上に多くのプロトタイプがあるのではないなら、彼らのスピードは同じぐらいです.
    また、注意すべき点は:
  • まず関数のprototype属性で方法を定義するなら、覚えておきたいのですが、方法を変えると、この構造関数によって生成されるすべてのオブジェクトのその方法が変更されます.
  • もう一つのポイントは変数の引き上げの問題です.以下のコードを少し見てもいいです.
    func1(); //      ,          ,func1      . error: func1 is not a function
    var func1 = function() {
       console.log('func1');
    };
    
    func2(); //         ,           .
    function func2() {
       console.log('func2');
    }
  • オブジェクトの順序付けに関する問題.関数のprototype上に定義されている属性は、順序付けされないので、下記のコードを参照してください.
    function A(name) {
       this.name = name;
    }
    A.prototype.sayWhat = 'say what...';
    
    var a = new A('dreamapple');
    console.log(JSON.stringify(a));
    私たちは出力結果を見ることができます.{"name":"dreamapple"}です.