javascript対象シリーズ第二編——作成対象の5パターン

22133 ワード

前の話
どのようにオブジェクトを作成するか、またはよりエレガントにオブジェクトを作成するかは、常に興味深いトピックです.本稿では、オブジェクトを作成する最も簡単な方法から始め、オブジェクトを作成する5つのパターンを紹介します.
 
対象文字数
一般的にオブジェクトを作成すると、対象の字面量の形を使います.
[注意]オブジェクトを作成する3つの方法があります.new構造関数、オブジェクト直接量、Object.create()関数を含めて、詳細はここに移ります.
var person1 = {
    name: "bai",
    age : 29,
    job: "Software Engineer",
    sayName: function(){
        alert(this.name);
    }
};
大量のオブジェクトを作成する場合は、以下のようになります.
var person1 = {
    name: "bai",
    age : 29,
    job: "Software Engineer",
    sayName: function(){
        alert(this.name);
    }
};
var person2 = {
    name: "hu",
    age : 25,
    job: "Software Engineer",
    sayName: function(){
        alert(this.name);
    }
};
/*
var person3 ...
*/
オブジェクトの文字数は、単一のオブジェクトを作成するために使用されますが、複数のオブジェクトを作成するには、多くの重複コードが発生します.
 
工場モード
これらの問題を解決するために、人々は工場モデルを使い始めました.このモードは特定のオブジェクトを作成するプロセスを抽象化し、特定のインターフェースでオブジェクトを作成するための詳細を関数でカプセル化する.
function createPerson(name,age,job){
    var o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayname = function(){
        alert(this.name);
    }
    return o;
}
var person1 = createPerson('bai',29,'software Engineer');
var person2 = createPerson('hu',25,'software Engineer');
工場モードは、類似した複数のオブジェクトを作成する問題を解決しましたが、対象識別の問題は解決されていません.
 
コンストラクタモード
ユーザー定義のコンストラクタを作成することにより、ユーザー定義のオブジェクトタイプの属性と方法を定義できます.カスタムのコンストラクタを作成するということは、そのインスタンスを特定のタイプとして識別することができ、これは工場モードよりもコンストラクタモードの場所である.このモードはオブジェクトを明示的に作成せず、直接に属性と方法をthisオブジェクトに割り当て、return文がありません.
function Person(name,age,job){
    this.name = name;
    this.age = age;
    this.jog = job;
    this.sayName = function(){
        alert(this.name);
    };
}
var person1 = new Person("bai",29,"software Engineer");
var person2 = new Person("hu",25,"software Engineer");
コンストラクタを使用する主な問題は、各方法が各インスタンスで再作成され、同じタスクを複数作成する方法は全く必要なく、メモリ空間を無駄にすることです.
function Person(name,age,job){
    this.name = name;
    this.age = age;
    this.jog = job;
    this.sayName = function(){
        alert(this.name);
    };
}
var person1 = new Person("bai",29,"software Engineer");
var person2 = new Person("hu",25,"software Engineer");
//       sayName()   person1 person2                 
console.log(person1.sayName === person2.sayName);//false
コンストラクタ拡張モード
コンストラクタモードに基づいて,方法定義をコンストラクタの外部に移すと,繰り返し作成された問題を解決できる.
function Person(name,age,job){
    this.name = name;
    this.age = age;
    this.jog = job;
    this.sayName = sayName;
}
function sayName(){
    alert(this.name);
};
var person1 = new Person("bai",29,"software Engineer");
var person2 = new Person("hu",25,"software Engineer");
console.log(person1.sayName === person2.sayName);//true
今、新しい問題がまた来ました.グローバルスコープで定義された関数は、実際にはあるオブジェクトにしか呼び出されません.また、オブジェクトが複数の方法を定義する必要がある場合、グローバル関数を多く定義し、グローバル空間を深刻に汚染します.このカスタム参照のタイプはパッケージ性がありません.
寄生構造関数モード
このモードの基本的な考えは、オブジェクトを作成するコードをパッケージ化しただけの関数を作成し、新規作成したオブジェクトに戻ります.このモードは工場モードと構造関数モードの組み合わせです.
寄生構造関数モードはコンストラクターモードと同じ問題があり、各方法はそれぞれのインスタンスにもう一度作成し、同じタスクを達成するための複数の方法を作成する必要は全くなく、メモリ空間を浪費する.
function Person(name,age,job){
    var o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function(){
        console.log(this.name);
    };
    return o;
}
var person1 = new Person("bai",29,"software Engineer");
var person2 = new Person("hu",25,"software Engineer");
//       sayName()   person1 person2                 
console.log(person1.sayName === person2.sayName);//false
もう一つの問題は、このモードを使って返したオブジェクトと構造関数の間には関係がないということです.そのため、instance of演算子とprototype属性を使うことは意味がありません.ですから、このモードはなるべく使わないようにしてください.
function Person(name,age,job){
    var o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function(){
        console.log(this.name);
    };
    return o;
}
var person1 = new Person("bai",29,"software Engineer");
console.log(person1 instanceof Person);//false
console.log(person1.__proto__ === Person.prototype);//false
コンストラクタモード
妥当な対象とは、公的な属性がなく、その方法もthisの対象を引用しないことをいう.適切なオブジェクトは、いくつかの安全環境(これらの環境はthisとnewの使用を禁止します.)または他のアプリケーションにデータが変更されないようにする時に使用するのに最適です.
安定構造関数は寄生構造関数モードと似ていますが、2つの点があります.1つは新規作成オブジェクトの実例となる方法はthisを引用しません.第二に、newオペレータを使用しないで、コンストラクタを呼び出します.
function Person(name,age,job){
    //        
    var o = new Object();
    //              
    //    
    o.sayName = function(){
        console.log(name);
    };
    //    
    return o;
}
//           ,    sayName()    ,        name  
var friend = Person("bai",29,"Software Engineer");
friend.sayName();//"bai"
寄生構造関数モードと似ています.安定構造関数モードを使って作成されたオブジェクトと構造関数の間にも関係がないので、instance ofオペレータはこのようなオブジェクトに対しても意味がありません.
 
プロトタイプ
プロトタイプオブジェクトを使用して、すべてのインスタンスにその属性と方法を共有することができます.つまり、オブジェクトのインスタンスを構造関数で定義する必要はなく、これらの情報を直接プロトタイプオブジェクトに追加することができます.
function Person(){
    Person.prototype.name = "bai";
    Person.prototype.age = 29;
    Person.prototype.job = "software Engineer";
    Person.prototype.sayName = function(){
        console.log(this.name);
    }
}
var person1 = new Person();
person1.sayName();//"bai"
var person2 = new Person();
person2.sayName();//"bai"
alert(person1.sayName == person2.sayName);//true
より簡単なプロトタイプ
不必要な入力を減らすためにも、原型の機能を視覚的により良くカプセル化するためにも、すべての属性と方法を含むオブジェクトの字面量を使って、原型オブジェクト全体を書き換えます.
しかし、対象の字面量を書き換えて、constructorはPersonを指しなくなりました.この方法は完全にデフォルトのprototypeオブジェクトを書き換えたので、Person.prototypeの固有属性construct属性は存在せず、プロトタイプチェーンからObject.prototypeのconstruct属性を見つけただけです.
function Person(){};
Person.prototype = {
    name: "bai",
    age: 29,
    job: "software Engineer",
    sayName : function(){
        console.log(this.name);
    }
};
var person1 = new Person();
person1.sayName();//"bai"
console.log(person1.constructor === Person);//false
console.log(person1.constructor === Object);//true
原型オブジェクトのconstructor属性を明示的に設定できます.
function Person(){};
Person.prototype = {
    constructor:Person,
    name: "bai",
    age: 29,
    job: "software Engineer",
    sayName : function(){
        console.log(this.name);
    }
};
var person1 = new Person();
person1.sayName();//"bai"
console.log(person1.constructor === Person);//true
console.log(person1.constructor === Object);//false
デフォルトでは、生のconstruct属性は列挙できないので、より適切な解決方法はObject.defineProperty()方法を使用して、その属性記述子のエニュメレーション性enumerableを変更します.
function Person(){};
Person.prototype = {
    name: "bai",
    age: 29,
    job: "software Engineer",
    sayName : function(){
        console.log(this.name);
    }
};
Object.defineProperty(Person.prototype,'constructor',{
    enumerable: false,
    value: Person
});
var person1 = new Person();
person1.sayName();//"bai"
console.log(person1.constructor === Person);//true
console.log(person1.constructor === Object);//false
プロトタイプの問題は、引用タイプの値の属性がすべてのインスタンスオブジェクトに共有され、修正されることであり、プロトタイプのパターンを単独で使用する人が少ないためである.
function Person(){}
Person.prototype = {
    constructor: Person,
    name: "bai",
    age: 29,
    job: "Software Engineer",
    friend : ["shelby","Court"],
    sayName: function(){
        console.log(this.name);
    }
};
var person1 = new Person();
var person2 = new Person();
person1.friends.push("Van");
alert(person1.friends);//["shelby","Court","Van"];
alert(person2.friends);//["shelby","Court","Van"];
alert(person1.friends === person2.friends);//true
 
コンビネーションモード
コンストラクタモードとプロトタイプパターンを組み合わせることは、ユーザー定義のタイプを作成する最も一般的な方法である.構造関数モードはインスタンス属性を定義するために使用され、プロトタイプモードは方法と共有の属性を定義するために使用され、この組み合わせモードはまた構造関数へのパラメータの伝達をサポートする.インスタンスオブジェクトは、自分のインスタンス属性のコピーを持っています.同時に、方法の参照を共有し、メモリを最大限に節約しました.このモードは、現在最も広く認知度の高いユーザー定義オブジェクトを作成するモードです.
function Person(name,age,job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.friends = ["shelby","Court"];
}
Person.prototype = {
    constructor: Person,
    sayName : function(){
        console.log(this.name);
    }    
}
var person1 = new Person("bai",29,"Software Engineer");
var person2 = new Person("hu",25,"Software Engineer");
person1.friends.push("Van");
alert(person1.friends);// ["shelby","Court","Van"];
alert(person2.friends);// ["shelby","Court"];
alert(person1.friends === person2.friends);//false
alert(person1.sayName === person2.sayName);//true
ダイナミックプロトタイプ
動的プロトタイプモードは、合成モードで別々に使用されるコンストラクタとプロトタイプオブジェクトをコンストラクタにパッケージ化し、方法が作成されているかを確認することにより、プロトタイプオブジェクトを初期化するかどうかを決定します.
この方法を用いて,分離した構造関数とプロトタイプオブジェクトを統合し,コードをより整然とし,大域空間の汚染も低減した.
[注意]原型オブジェクトに複数の語句が含まれている場合、その中の一つの語句を検出するだけでいいです.
function Person(name,age,job){
    //  
    this.name = name;
    this.age = age;
    this.job = job;
    //  
    if(typeof this.sayName != "function"){
        Person.prototype.sayName = function(){
            console.log(this.name);
        };
    }
}
var friend = new Person("bai",29,"Software Engineer");
friend.sayName();//'bai'
 
最後に
本論文では、使用対象の字面量形式からオブジェクトを作成すると、複数のオブジェクトを作成するとコード冗長性が発生します.工場モードを使ってこの問題を解決できますが、対象認識の問題があります.次に,オブジェクト識別の問題を解決する構造関数モードを紹介したが,方法の繰り返し作成に関する問題が存在した.次に、モデルパターンの特徴は共有にあるが、参照タイプの値属性がすべてのインスタンスオブジェクトに共有され、修正されるという問題を引き出した.最後に,構造関数とプロトタイプの組合せモードを提案し,構造関数モードは実例的な属性を定義するために用いられ,プロトタイプモードは方法と共有の属性を定義するために用いられ,この組合せモードはまた,構造関数へのパラメータの伝達をサポートしている.
また、いくつかのモデルには特別な需要を解決するための拡張モデルがあります.
以上