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 的对象
크롬에서 새로 생성된 각 객체의 차이점을 확인하세요.
처음 6개 모드를 볼 수 있습니다 일곱 번째 차이점은 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을 사용할 때의 문제점은 명백합니다. 새로운 객체가 생성되면 힙에 새로운 객체가 있어야 합니다. 개선 사항은 다음과 같습니다.
//构造器方法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. 함수 객체를 통해 생성 Object
함수가 선언될 때마다 실제로 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 객체)에 바인딩된 것과 동일합니다. 이 필드에 바인딩된 속성과 메서드는 하나의 버전만 가지며 한 번만 생성됩니다.
클래스의 인스턴스 객체는 다음과 같이 직접 호출할 수 있습니다. 자신의 속성도 클래스의 프로토타입 도메인에 있는 속성과 메서드를 호출할 수 있습니다. 클래스는 프로토타입 속성을 호출하여 프로토타입 도메인의 속성과 메소드를 간접적으로 호출할 수 있습니다.
참고: 객체가 클래스를 통해 인스턴스화되면 객체에 프로토타입 속성이 없습니다. 그러나 객체는 프로토타입의 내용에 직접 액세스할 수 있습니다. 속성에 액세스하는 것과 마찬가지로 클래스의 프로토타입 필드에는 proto 속성이 있고 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 受影响
클래스의 프로토타입 필드에 있는 속성과 메서드가 포함되어 있는 것을 볼 수 있습니다. use 이 방법은 메모리 낭비를 줄여준다고 하지만 여전히 문제가 있습니다. 일단 객체의 속성이 변경되면 클래스에 의해 인스턴스화된 모든 객체의 proto에 있는 속성 값도 그에 따라 변경됩니다( 실제로는 레퍼런스임) 개선 사항은 다음과 같습니다
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
와 같은 강력한 유형의 언어로 클래스 정의를 가능하게 합니다
function Car6(){ var oTempCar = new Object; oTempCar.color = "blue"; oTempCar.doors = 4; oTempCar.showColor = function () { alert(this.color); }; return oTempCar; } var car6 = new Car6();
Car6() 생성자로 인해 new 연산자가 내부적으로 호출되므로 두 번째 new 연산자(생성자 외부에 있음)는 무시됩니다.
저자: Tomson