ホームページ >ウェブフロントエンド >jsチュートリアル >js でオブジェクトを作成する 8 つのモードについての簡単な説明

js でオブジェクトを作成する 8 つのモードについての簡単な説明

伊谢尔伦
伊谢尔伦オリジナル
2016-12-01 10:33:44845ブラウズ

1.オブジェクトモード

var o1 = {};//字面量的表现形式
var o2 = new Object;
var o3 = new Object();
var o4 = new Object(null);
var o5 = new Object(undefined);
var o6 = Object.create(Object.prototype);//等价于 var o = {};//即以 Object.prototype 对象为一个原型模板,新建一个以这个原型模板为原型的对象
//区别
var o7 = Object.create(null);//创建一个原型为 null 的对象

Chromeで新しく作成された各オブジェクトの違いを確認してください:

js でオブジェクトを作成する 8 つのモードについての簡単な説明

最初の6つのモードで作成されたオブジェクトは同じであることがわかります。7番目の違いは、 Object オブジェクトでもありますが、属性はありません (作成時にプロトタイプが指定されていないため、継承できる属性もありません)

2. ファクトリ パターン

//工厂方法1 通过一个方法来创建对象 利用 arguments 对象获取参数设置属性(参数不直观,容易出现问题)
function createCar(){
    var oTemp = new Object();
    oTemp.name = arguments[0];//直接给对象添加属性,每个对象都有直接的属性
    oTemp.age = arguments[1];
    oTemp.showName = function () {
        alert(this.name);
    };//每个对象都有一个 showName 方法版本
    return oTemp;
}
createCar("tom").showName();//在 JS 中没有传递的实参,实际形参值为 undefined(这里的 age 为 undefined)
createCar("tim",80).showName();
alert(createCar("tom") instanceof Object);//true 判断对象是否 Object 类或子类
//工厂方法2 通过传参设置属性(参数直观明了)
function createCar(name,age){
    var oTemp = new Object();
    oTemp.name = name;//直接给对象添加属性,每个对象都有直接的属性
    oTemp.age = age;
    oTemp.showName = function () {
        alert(this.name);
    };//每个对象都有一个 showName 方法版本
    return oTemp;
}
createCar("tom").showName();
createCar("tim",80).showName();
alert(createCar("tom") instanceof Object);//true 判断对象是否 Object 类或子类

3. コンストラクター パターン

//构造器方法1
function Car(sColor,iDoors){  //声明为构造器时需要将函数名首字母大写
    this.color = sColor;      //构造器内直接声明属性
    this.doors = iDoors;
    this.showColor = function(){
        return this.color;
    };//每个 Car 对象都有自己的 showColor方法版本
    this.showDoor = function () {
        return this.doors;
    }
}

メソッド 1 を使用する場合の問題点は、当然のことですが、方法はありません。 showDoor メソッドを再利用することで、新しいオブジェクトが作成されるたびに、ヒープ内に新しいスペースが開かれます。改善点は次のとおりです

//构造器方法2
function showDoor(){      //定义一个全局的 Function 对象
    return this.doors;
}
function Car(sColor,iDoors){//构造器
    this.color = sColor;      //构造器内直接声明属性
    this.doors = iDoors;
    this.showColor = function(){
        return this.color;
    };
    this.showDoor = showDoor();//每个 Car 对象共享同一个 showDoor 方法版本(方法有自己的作用域,不用担心变量被共享)
}
alert(new Car("red",2).showColor());//通过构造器创建一个对象并调用其对象方法

上記の問題は、セマンティクスが正しくないことです。十分に明確であり、クラスのカプセル化が反映されません。プロトタイプ モードに改善されました

4 .Function オブジェクトを通じてオブジェクトを作成します

関数の各宣言が実際に Function インスタンスの JS 関数を作成することがわかります

function function_name(param1,param2){alert(param1);}
//等价于
var function_name = new Function("param1","pram2","alert(param1);");
var Car2 = new Function("sColor","iDoors",
         "this.color = sColor;"+
         "this.doors = iDoors;"+
         "this.showColor = function(){ return this.color; }"
);
alert(new Car2("blue",3).showColor());

5。プロトタイプ モード

プロトタイプ属性を通じてクラスによって追加されたプロパティとメソッドは、このクラスにバインドされます。 プロトタイプ フィールド (実際には Prototype オブジェクト) では、このフィールドにバインドされたプロパティとメソッドは 1 つのバージョンのみを持ち、一度だけ作成されます。
クラスのインスタンス オブジェクトは、プロトタイプ ドメイン内の属性とメソッドを呼び出すのと同じように、クラスのプロトタイプ フィールドを直接呼び出すことができます。
注: オブジェクトがクラスを通じてインスタンス化された後、オブジェクトにはプロトタイプ属性はありませんが、オブジェクトは属性にアクセスする場合と同様にクラスに直接アクセスできます。インスタンス オブジェクトのコンテンツにはプライベート属性があります。 proto 属性には、クラスのプロトタイプ フィールドのプロパティとメソッドが含まれています

方法1
function Car3(){}//用空构造函数设置类名
Car3.prototype.color = "blue";//每个对象都共享相同属性
Car3.prototype.doors = 3;
Car3.prototype.drivers = new Array("Mike","John");
Car3.prototype.showColor = function(){
    alert(this.color);
};//每个对象共享一个方法版本,省内存。
var car3_1 = new Car3();
var car3_2 = new Car3();
alert(car3_1.color);//blue
alert(car3_2.color);//blue
alert(Car3.prototype.color);//blue
car3_1.drivers.push("Bill");
alert(car3_1.drivers);//"Mike","John","Bill"
alert(car3_2.drivers);//"Mike","John","Bill"
alert(Car3.prototype.drivers);//"Mike","John","Bill"
//直接修改实例对象的属性,解析器会先去找实例对象是否有这个属性(不会去找实例对象的 _proto_ 属性内的那些类的 prototype 属性,而是直接查看这个实例是否有对应的属性(与_proto_同级))
//如果没有则直接给这个实例对象添加该属性,但不会修改类的prototype域的同名属性,既实例对象的_proto_属性内的那些类 prototype 域属性不会被修改
car3_1.color = "red";//car3_1对象内无名为 color 的对象属性,故将该属性添加到该对象上
//解析器对实例对象读取属性值的时候会先查找该实例有无同名的直接属性
//如果没有,则查找__proto__属性内保存的那些 当前类的 prototype 域的属性
//有就返回,无则继续查找是否有原型链中的对应的方法属性
//有就返回,无则返回undefined
alert(car3_1.color);//red
alert(car3_2.color);//blue
alert(car3_2.color2);//undefined
//直接修改类的 prototype 域内的属性,不会影响该类的实例对象的对象属性,但会影响实例对象的_proto_属性(_proto_属性内存放的是类的 prototype 域的内容)
Car3.prototype.color = "black";
alert(car3_1.color);//red 该对象有同名的直接属性,故不会去_proto_属性内查找类的 prototype 域的属性
alert(car3_2.color);//black 受影响
//直接修改实例对象的方法,解析器会先去找实例对象是否有这个方法(不会去找实例对象的 _proto_ 属性内的那些类的 prototype 域的方法,而是直接查看这个实例是否有对应的方法(与_proto_同级))
//如果没有则直接给这个实例对象添加该方法,但不会修改类的prototype域的同名方法,既实例对象的_proto_属性内的那些类 prototype 域方法不会被修改
//car3_1对象内无名为 showColor 的对象方法属性,故将该方法属性添加到该对象上
car3_1.showColor = function () {
    alert("new function");
}
//解析器对实例对象调用方法属性的时候会先查找该实例有无同名的直接方法属性
//如果没有,则查找_proto_属性内保存的那些 当前类的 prototype 域的方法属性
//有就返回,无则继续查找是否有原型链中的对应的方法属性
//找到就返回,无则报错
car3_1.showColor();//new function
car3_2.showColor();//blue
car3_1.abcd();//直接报错
//直接修改类的 prototype 域内的方法属性,不会影响该类的实例对象的方法属性,但会影响实例对象的_proto_属性(_proto_属性内存放的是类的 prototype 域的内容)
Car3.prototype.showColor = function () {
    alert("second function");
}
car3_1.showColor();//new function 该对象有同名的方法属性,故不会去_proto_属性内查找类的 prototype 域的方法属性
car3_2.showColor();//second function 受影响

このメソッドを使用すると、メモリの無駄が削減されますが、オブジェクトの属性が変更されると、依然として問題が発生することがわかります。このクラスでインスタンス化されたすべてのオブジェクトのプロト内の属性値も変更されます(実際には参照されます)、改善点は以下の通りです

6. コンストラクターメソッドとプロトタイプメソッドの混合モード

//每个对象有专属的属性不会与其他对象共享
function Car4(sColor,iDoors){
    this._color = sColor;//私有属性变量名称头加下划线标识
    this._doors = iDoors;
    this.drivers = new Array("Mike","John");//公有属性标识
}
//所有对象共享一个方法版本,减少内存浪费
Car4.prototype.showColor = function () {
    alert(this._color);
};
var car4_1 = new Car4("red",4);
var car4_2 = new Car4("blue",3);
car4_1.drivers.push("Bill");
alert(car4_1.drivers);//"Mike","John","Bill"
alert(car4_2.drivers);//"Mike","John"

これも一つです。オブジェクトを作成するために一般的に使用される方法

7. 動的プロトタイプ モード

function Car5(sColor,iDoors,iMpg){
    this.color = sColor;
    this.doors = iDoors;
    this.mpg = iMpg;
    this.drivers = new Array("Mike","John");
    //使用标志(_initialized)来判断是否已给原型赋予了任何方法,保证方法永远只被创建并赋值一次
    if(typeof Car5._initialized == "undefined"){//因为这里的标记是附加在类上,故如果后期直接对其进行修改,还是有可能出现再次创建的情况
        Car5.prototype.showColor = function () {//为Car5添加一个存放在 prototype 域的方法
            alert(this.color);
        };
        Car5._initialized = true;//设置一个静态属性
    }
}
var car5_1 = new Car5("red",3,25);
var car5_2 = new Car5("red",3,25);

このモードでは、java

8 などの厳密に型指定された言語でのクラスの定義が可能になります。 to Car6() new 演算子はコンストラクター内で呼び出されるため、2 番目の new 演算子 (コンストラクターの外にある) は無視され、コンストラクター内で作成されたオブジェクトは変数 car6 に返されます。このメソッドは内部管理で使用されます。オブジェクトメソッドの場合は、古典的なメソッド(ファクトリーメソッド)と同じ問題がありますので、できるだけ避けるべきです

作者: Tomson
元のアドレス: http://segmentfault.com/a/1190000003862596


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