>웹 프론트엔드 >JS 튜토리얼 >JavaScript_javascript 팁에서 객체 생성 패턴 요약

JavaScript_javascript 팁에서 객체 생성 패턴 요약

WBOY
WBOY원래의
2016-05-16 15:04:471143검색

JavaScript로 객체를 생성하는 패턴 요약

**JavaScript 생성 객체 모드:

객체 리터럴
공장모드
생성자 패턴
프로토타입 모드
생성자와 프로토타입 패턴 결합
프로토타입 동적 모드
**

대부분의 객체지향 언어에는 클래스라는 개념이 있는데, 이를 통해 동일한 메소드와 속성을 가진 여러 객체를 생성할 수 있습니다. 기술적으로 말하면 JavaScript는 객체 지향 언어이지만 JavaScript에는 클래스 개념이 없으며 모든 것이 객체입니다. 모든 객체는 기존 참조 유형을 통해 생성된 특정 참조 유형의 인스턴스입니다. 참조 유형은 기본 유형이거나 사용자 정의될 수 있습니다.

1. 객체 리터럴

var person = {
    name : 'Nicholas';
    age : '22';
    job :"software Engineer"
    sayName: function() {
      alter(this.name);
  }
}

이 예에서는 person이라는 개체가 생성되고 여기에 세 가지 속성(name, age, job)과 메서드(sayName())가 추가됩니다. sayName() 메서드는 this.name( is)을 표시하는 데 사용됩니다. person.name의 값으로 구문 분석됨).

객체 리터럴을 사용하여 단일 객체를 생성할 수 있지만 이 방법에는 분명한 단점이 있습니다. 동일한 인터페이스를 사용하여 많은 객체를 생성하면 중복 코드가 많이 생성됩니다.

2. 공장모드

팩토리 패턴은 소프트웨어 공학 분야에서 잘 알려진 디자인 패턴입니다. 팩토리 패턴은 특정 객체를 생성하는 과정을 추상화하고 객체 생성의 세부 사항을 특정 인터페이스로 캡슐화하는 기능을 사용합니다.

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=creatPerson("Nicholas",22,"software Engineer");
var person2=creatPerson("Greg",24,"student");

creatPerson{} 함수는 허용된 매개변수를 기반으로 필요한 모든 정보를 포함하는 Person 객체를 생성할 수 있습니다. 이 함수는 셀 수 없이 호출될 수 있으며, 매번 호출할 때마다 세 가지 속성과 한 가지 메서드가 포함된 개체를 반환합니다.

공장 모델은 유사한 객체를 여러 개 만드는 문제는 해결하지만 객체 인식(즉, 객체의 유형을 아는 방법) 문제는 해결하지 못합니다.

3. 생성자 패턴

function Person(name,age,job) {
  this.name = name;
  this.age = age;
  this.job = job;
  this.sayName = function() {
    alert(this.name);
  }
}
//通过new操作符创建Person的实例
var person1 = new Person("Nicholas",22,"software Engineer");
var person2 = new Person("Greg",24,"student");
person1.sayName(); //Nicholas
person2.sayName(); //Greg

공장모드와의 차이점은

생성된 개체가 표시되지 않습니다

이 개체에 속성과 메서드를 직접 할당

반품문의 불가

Person의 새 인스턴스를 생성하려면 new 연산자를 사용해야 합니다. 생성자를 호출하는 4단계:

새 개체 만들기

새 개체에 생성자의 범위를 할당합니다(이는 새 개체를 가리킵니다).

생성자에서 코드 실행

새 개체 반환

이 예에서 생성된 모든 객체는 Object 인스턴스와 Person 인스턴스입니다. instanceof 연산자를 통해 확인할 수 있습니다.

alert(person1 instanceof Object);//true

생성자 패턴에도 자체적인 문제가 있습니다. 실제로 sayName 메서드는 각 인스턴스에서 한 번씩 다시 생성됩니다. 다음 코드에서 알 수 있듯이 인스턴스화로 생성된 메서드는 동일하지 않습니다.

alert(person1.sayName == person2.sayName);//false

이 문제는 메소드를 전역 함수로 생성자 외부로 이동하여 해결할 수 있습니다.

function Person(name,age,job) {
  this.name = name;
  this.age = age;
  this.job = job;  
}
function sayName() {
    alert(this.name);
  }

세계화 하에 생성된 전역 함수는 실제로 Person을 통해 생성된 인스턴스에 의해서만 호출될 수 있습니다. 이는 이름이 약간 잘못되었습니다. 객체가 많은 메서드를 정의해야 하는 경우 캡슐화가 부족하여 많은 전역 함수를 정의해야 합니다.

4. 프로토타입 모드

JavaScript에서 생성된 모든 함수에는 특정 유형의 모든 인스턴스에서 공유할 수 있는 속성과 메서드가 포함된 개체에 대한 포인터인 프로토타입 속성이 있습니다(모든 개체 인스턴스에서 속성과 메서드를 공유하도록 함).

function Person() {}
  Person.prototype.name ="Nicholas";
  Person.prototype.age = 22;
  Person.prototype.job = "software Engineer";  
  Person.prototype.sayName(){
    alert(this.name);
  };
 var person1 = new Person();
 person1.sayName(); //Nicholas
alert(person1.sayName == person2.sayName);//true

以上代码做了这几件事情:

定义了一个构造函数Person,Person函数自动获得一个prototype属性,该属性默认只包含一个指向Person的constructor属性
通过Person.prototype添加三个属性,和一个方法

创建一个Person的实例,随后在实例上调用了sayName()方法

JavaScript_javascript 팁에서 객체 생성 패턴 요약

JavaScript_javascript 팁에서 객체 생성 패턴 요약

JavaScript_javascript 팁에서 객체 생성 패턴 요약 

图中展示了Person构造函数、Person的原型属性以及Person的两个实例,之间的关系。Person.prototype指向了原型对象,Person.prototype.constructor有指回了Person。原型对象中除了包含constructor属性,还包含后来添加的其他属性和方法,Person的两个实例person1和person2都包含一个内部属性,该属性仅指向Person.prototype。

sayName()方法的调用过程:

在person1实例上查找logName()方法,发现没有这个方法,于是追溯到person1的原型

在person1的原型上查找sayame()方法,有这个方法,于是调用该方法

基于这样一个查找过程,我们可以通过在实例上定义原型中的同名属性,来阻止该实例访问原型上的同名属性,需要注意的是,这样做并不会删除原型上的同名属性,仅仅是阻止实例访问。

function Person() {}
  Person.prototype.name ="Nicholas";
  Person.prototype.age = 22;
  Person.prototype.job = "software Engineer";  
  Person.prototype.sayName(){
    alert(this.name);
  };
 var person1 = new Person();
 var person2 = new Person();
 person1.name="Greg"
alert(person1.name) //Greg 来自实例
alert(person2.name) //Nicholas 来自原型

使用delete操作符可以完全删除实例属性

delete person1.name;
alert(person1.name) //Nicholas 来自原型

使用hasOwnProperty()方法可以检测一个属性是存在于实例还是原型中

function Person() {}
  Person.prototype.name ="Nicholas";
  Person.prototype.age = 22;
  Person.prototype.job = "software Engineer";  
  Person.prototype.sayName(){
    alert(this.name);
  };
 var person1 = new Person();
 var person2 = new Person();
 alert(person1,hasOwnProperty("name"));//false
 person1.name="Greg"
alert(person1.name) //Greg 来自实例
 alert(person1,hasOwnProperty("name"));//true
alert(person2.name) //Nicholas 来自原型
 alert(person2,hasOwnProperty("name"));//false
 delete person1.name;
alert(person1.name) //Nicholas 来自原型
 alert(person1,hasOwnProperty("name"));//false

下图展示了在不同情况下实例与原型之间的关系

JavaScript_javascript 팁에서 객체 생성 패턴 요약

简单的原型语法

function Person() {}
 Person.prototype={
 name :"Nicholas",
 age : 22,
 job : "software Engineer", 
 sayName:function(){
    alert(this.name);
    }
  };

在上面的代码中constructor属性不再指向Person了,通过constructor无法确定对象的类型了。可以像下面这样特意将他设置回适当的值

function Person() {}
 Person.prototype={
 constructor:Person,
 name :"Nicholas",
 age : 22,
 job : "software Engineer",  
 sayName:function(){
    alert(this.name);
    }
  };

重设constructor属性会导致它的[[Enumerable]]特性被设置为true,默认情况,原生的constructor属性是不可枚举的,可以使用Object.defineProperty()方法来改变

Object.defineProperty(Person.prototype,"constructor",{
  enumerable:false,
  value:Person
});

原型中查找值的过程是一次搜索,原型对象所做的任何修改都能从实例上立即反应出来

var friend=new Person();
Person.prototype.sayHi=function(){
  alert("hi);
}
friend,sayHi();//"hi"(没有问题)

person实例是在添加新方法之前创建的,但仍可以访问新添加的方法,原因是实例与原型之间的松散连接关系
重写原型对象后的情况

function Person() {}
var friend=new Person();
 Person.prototype={
 name :"Nicholas",
 age : 22,
 job : "software Engineer", 
 sayName:function(){
    alert(this.name);
    }
  };
  friend.sayName();//error

调用friend.sayName()时发生错误的原因是,friend指向的原型中不包含以该字段命名的属性,如下图。

JavaScript_javascript 팁에서 객체 생성 패턴 요약 

原型对象的问题

原型对象省略了为构造函数传递初始化参数这一环节,所有势力在默认情况下都取得相同的属性值。原型模型最大的问题是有其共享本性所导致的。当原型模型包含引用类型的属性来说,问题就比较严重了。来看下面的例子。

function Person() {}
 Person.prototype={
 constructor:Person,
 name :"Nicholas",
 age : 22,
 job : "software Engineer",  
 friends:["Shelby","Court"],
 sayName:function(){
    alert(this.name);
    }
  };
  var person1=new Person();
  var person2=new Person();
  person1.friend.push("Van");
  alert(person1.friends);//"Shelby,Court,Van"
  alert(person2.friends);//"Shelby,Court,Van"
 alert(person1.friends==person2.friends);//true

5、组合使用构造函数模式和原型模式

组合使用构造函数模式和原型模式中,构造函数用于定义实例属性,原型模型用于定义方法和共享的属性。这样每个实例都会有自己的一份实例属性的副本,同时也可以共享对方法的引用,最大限度的节省了内存。

function Person(name,age,job) {
  this.name = name;
  this.age = age;
  this.job = job;  
  this.friends=["Shelby","Court"];
}
Person.prototype={
 constructor:Person,
 sayName:function(){
    alert(this.name);
    }
  }
var person1=new Person("Nicholas",22,"software Engineer");
var person2 = new Person("Greg",24,"student");
person1.friend.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

6、动态原型模式

原型动态模式将需要的所有信息都封装到构造函数中,通过if语句判断原型中的某个属性是否存在,若不存在(在第一次调用这个构造函数的时候),执行if语句内部的原型初始化代码。

function Person(name,age) {
  this.name = name;
  this.age = age;
  this.job =job;
//方法
  if(typeof this.sayName != 'function') {
  Person.prototype.sayName = function() {
      alert(this.name);
    };   
  }
}
var friend = new Person('Nicholas','22','Software Engineer');//初次调用构造函数,此时修改了原型
var person2 = new Person('amy','21');//此时sayName()方法已经存在,不会再修改原型

추천 도서:

JS 객체 지향 객체를 생성하는 일반적인 방법(팩토리 모드, 생성자 모드, 프로토타입 모드)

위는 에디터가 소개한 자바스크립트의 객체 생성 모드입니다. 도움이 되셨으면 좋겠습니다!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.