최근에 나는 "JavaScript Advanced Programming"을보고 있습니다 (제 2 판)
JavaScript에서 객체 생성
• 공장 모드
• 생성자 모드
• 프로토 타입 모드
• 생성자와 프로토 타입 패턴 결합
• 프로토 타입 동적 모드
대부분의 객체 지향 언어에는 클래스 개념이 있으며 동일한 방법과 속성을 가진 여러 객체를 만들 수 있습니다. 기술적으로 JavaScript는 객체 지향 언어이지만 JavaScript에는 클래스 개념이 없지만 모든 것이 객체입니다. 모든 객체는 특정 참조 유형의 인스턴스이며 기존 참조 유형을 통해 생성됩니다. 참조 유형은 기본이거나 사용자 정의 될 수 있습니다. 기본 참조 유형은 객체, 배열, 데이터, Regexp, 기능입니다. ! 참조 유형은 데이터와 기능을 함께 구성하는 데이터 구조이며, 일반적으로 클래스라고합니다. 클래스 개념이 부족한 JavaScript에서 해결해야 할 문제는 객체를 효율적으로 만드는 방법입니다.
1.1.0. 객체를 만드는 일반적인 방법
var person = {}; // 객체 문자 그대로 표현은 var person = new objcect ()와 같습니다. person.name = 'Evansdiy'; person.age = '22'; person.friends = [ 'ajiao', 'tiantian', 'pangzi']; person.logname = function () {console.log (this.name);}객체 참조 유형을 기반으로, 객체가 생성되며, 여기에는 4 개의 속성이 포함되어 있으며 그 중 하나는 메소드입니다. 사람과 같은 많은 인스턴스가 필요한 경우 중복 코드가 많이 있습니다.
1.1.1. 공장 모델
객체의 세부 사항을 포함 할 수있는 함수가있는 객체를 작성한 다음 객체를 반환하십시오.
기능인 (이름, 연령, 친구) {var o = {이름 : 이름, 나이 : 연령, 친구 : 친구, logname : function () {console.log (this.name); }}; return o;} var person1 = person ( 'evansdiy', '22', [ 'ajiao', 'tiantian', 'pangzi']);사람 함수가 호출 될 때마다 함수 내부의 객체 O를 통해 새 객체가 생성 된 다음 반환됩니다. 이 외에도,이 내부 객체 O는 새 개체를 생성하기위한 존재가 존재합니다. 다른 목적은 없습니다. 또한 공장 모드에서 생성 된 객체의 유형을 결정하는 것은 불가능합니다.
1.1.2. 생성자 모드
기능인 (이름, 나이, 직업) {this.name = 이름; this.age = age; this.job = job; this.logname = function () {console.log (this.name); }} // 새로운 운영자 var person1 = 새로운 사람 ( 'boy-a', '22', 'Worker')을 통해 사람의 인스턴스를 만듭니다. //boy-aperson2.logname (); // girl-a공장 모드를 비교하면 여기서 중간 객체를 만들 필요가 없으며 반품이 없습니다. 또한 생성자의 인스턴스는 특정 유형으로 식별 될 수 있으며, 이는 객체 인식 문제를 해결하거나 (인스턴스의 생성자 속성을 확인하거나, 연산자 인스턴스를 사용하여 인스턴스가 생성자에 의해 인스턴스가 생성되는지 확인 함)를 해결합니다.
console.log (person1.constructor == person); // 생성자는 생성자 프로토 타입에 있으며 생성자를 가리키며 결과는 사실입니다.
console.log (person1 instance of person); // 인스턴스를 사용하여 Person1이 생성자 인스턴스인지 여부를 결정하지만 생성자 패턴에도 고유 한 문제가 있습니다. 실제로, 로그 이름 메소드는 각 인스턴스에서 한 번 다시 재현됩니다. 인스턴스화에 의해 생성 된 방법은 같지 않으며 다음 코드는 False가됩니다.
console.log (person1.logname == person2.logname); // 거짓 우리는이 문제를 해결하기 위해 생성자 외부 (글로벌 함수로 변경)를 이동할 수 있습니다.
function logname () {console.log (this.name);} function logage () {console.log (this.age);}그러나 전 세계적으로 생성 된 글로벌 기능은 사람이 만든 인스턴스에 의해서만 호출 될 수 있으며, 이는 약간 비현실적입니다. 많은 방법이 있다면 여전히 캡슐화가 부족하여 하나씩 정의해야합니다.
1.1.3. 프로토 타입 모드
JavaScript의 각 함수에는 프로토 타입 속성에 대한 포인터가 포함되어 있습니다 (대부분의 브라우저는 내부 속성 __proto__를 통해 액세스 할 수 있습니다). 프로토 타입 속성은 특정 참조 유형에 의해 생성 된 모든 인스턴스가 공유하는 속성 및 메소드를 포함하는 객체입니다.
function person () {} person.name = 'evansdiy'; person.prototype.friends = [ 'ajiao', 'jianjian', 'pangzi']; person.prototype.logname = function () {console.log (this.name);} var person1 = new person (); logname (); // 'Evansdi'위의 코드는 다음과 같습니다.
1. 생성자 사람을 정의하십시오. 개인 기능은 자동으로 프로토 타입 속성을 얻습니다. 이 속성에는 기본적으로 사람을 가리키는 생성자 속성 만 포함합니다.
2. person.prototype를 통해 세 가지 속성을 추가하십시오. 그 중 하나는 방법으로 사용됩니다.
3. 사람의 인스턴스를 작성한 다음 인스턴스에서 logname () 메소드를 호출하십시오. !
여기에 주목해야 할 것은 logname () 메소드의 호출 프로세스입니다.
1. Person1 인스턴스에서 logname () 메소드를 찾아서 그러한 방법이 없다는 것을 발견했습니다. 그래서 나는 person1의 프로토 타입으로 다시 추적했습니다.
2. Person1의 프로토 타입에서 logame () 메소드를 찾으십시오. 이 방법이 있습니다. 따라서 우리는 이러한 검색 프로세스를 기반 으로이 방법을 호출합니다. 인스턴스의 프로토 타입에서 동일한 이름 속성을 정의하여 인스턴스가 프로토 타입에서 동일한 이름 속성에 액세스하는 것을 방지 할 수 있습니다. 그렇게하면 프로토 타입에서 동일한 이름 속성을 삭제하지는 않지만 인스턴스가 액세스하는 것을 방지합니다.
var person2 = 새로운 사람 ();
person2.name = 'laocai'; 인스턴스에 더 이상 속성이 필요하지 않으면 삭제 연산자를 통해 삭제할 수 있습니다.
삭제 person2.name; 인스턴스에 액세스 할 수있는 모든 속성을 열거하여 (인스턴스 또는 프로토 타입에 속성이 있는지 여부에 관계없이).
for (i in person1) {console.log (i);}동시에 HasownProperty () 메소드를 사용하여 인스턴스 또는 프로토 타입에 특정 속성이 존재하는지 여부를 결정할 수도 있습니다. 인스턴스에 존재하는 속성이 참을 때만 반환됩니다.
console.log (person1.HasOwnProperty ( 'name')); // true! HasownProperty는 객체의 프로토 타입에서 비롯되며 특성을 처리 할 때 프로토 타입 체인을 찾지 않는 JavaScript의 유일한 방법입니다. [JavaScript Secret Garden을 통해] 또한 IN OPERATOR 및 HASOWNPROPERTY () 방법을 사용하여 인스턴스 또는 프로토 타입에 특정 속성이 존재하는지 여부를 결정할 수도 있습니다.
console.log (( 'friends'in person1) &&! person1.hasownproperty ( 'friends')); 먼저 Person1이 친구 재산에 액세스 할 수 있는지 여부를 결정합니다. 가능하면이 속성이 인스턴스에 존재하는지 여부를 결정하십시오 (이전에 참고하십시오!). 인스턴스에 존재하지 않으면이 속성이 프로토 타입에 존재 함을 의미합니다. 앞에서 언급했듯이 프로토 타입은 객체이기 때문에 객체 문자 그대로 표현을 사용하여 프로토 타입을 쓸 수 있습니다. 프로토 타입에 코드를 추가하는 이전의 작문 방법은 다음과 같이 수정할 수 있습니다.
person.prototype = {name : 'evansdiy', 친구 : [ 'ajiao', 'jianjian', 'pangzi'], logname : function () {console.log (this.name); }}객체 문자 그대로 구문은 전체 프로토 타입 프로토 타입을 다시 작성하기 때문에 생성자를 생성 할 때 기본적으로 얻은 생성자 속성은 객체 생성자를 가리 킵니다.
// 객체 후 문자 그대로 프로토 타입을 다시 작성합니다
console.log (person1.constructor); // 객체 그러나 인스턴스는 여전히 원하는 결과를 반환합니다.
// 객체 후 문자 그대로 프로토 타입을 다시 작성합니다
Console.log (person1 instance of person); // 사실, 물론,이 문제를 해결하기 위해 프로토 타입에서 생성자 값을 수동으로 설정할 수 있습니다.
person.prototype = {생성자 : person, ......}객체 인스턴스가 생성 된 후 프로토 타입 객체가 수정되면 프로토 타입의 수정은 모든 객체 인스턴스에 즉시 반영됩니다.
function person () {}; var person1 = new person (); person.prototype.name = 'evansdiy'; console.log (person1.name); // 'evansdiy'인스턴스와 프로토 타입 사이의 연결은 프로토 타입의 사본이 아니라 포인터 일뿐입니다. 프로토 타입은 실제로 검색 프로세스입니다. 인스턴스가 생성 된 후 프로토 타입이 수정 되더라도 프로토 타입 객체에 대한 수정은 모든 개체 인스턴스에 반영됩니다. 객체 인스턴스를 만든 후 프로토 타입 객체가 다시 작성되면 어떻게됩니까?
function person () {{}; var person1 = new person1 (); // 생성 된 인스턴스는 원래 프로토 타입 // 프로토 타입 person.prototype = {friends : [ 'ajiao', 'jianjian', 'pangzi']} var person2 = 새로운 사람 (); Console.log (person1.friends);위의 코드는 마지막 줄에 실행될 때 정의되지 않은 오류가 발생합니다. 개인 1의 접근 가능한 속성을 열거하기 위해 In-In을 사용하면 내부에 아무것도 없다는 것을 알지만 Person2는 프로토 타입에서 친구 속성에 액세스 할 수 있습니다. ! 프로토 타입을 다시 작성하면 기존 프로토 타입과 이전에 생성 된 모든 객체 인스턴스 간의 연결을 잘라냅니다. 이전에 생성 된 객체 인스턴스의 프로토 타입은 여전히 존재하지만 오래되었습니다.
// person1을 만들 때 프로토 타입 객체는 아직 다시 작성되지 않았습니다. 따라서 프로토 타입 객체의 생성자는 여전히 기본 인원 () console.log (person1.constructor); // person () // 그러나 person2의 생성자는 Object () console.log (person2.constructor); // object ()를 가리킨다.
프로토 타입 패턴은 생성자에 대한 매개 변수를 전달하는 프로세스를 무시하고 모든 인스턴스는 동일한 속성 값을 얻습니다. 동시에, 프로토 타입 패턴에 큰 문제가 있습니다. 즉, 프로토 타입 객체의 기준 유형 값은 모든 인스턴스에서 공유되며 참조 유형 값의 수정은 모든 객체 인스턴스에 반영됩니다.
function person () {}; person.prototype = {friends : [ 'ajiao', 'tiantian', 'pangzi']} var person1 = new person (); var person2 = new person (); person1.friends.push ( 'laocai'); console.log (person2.friends); // [ 'ajiao', ''wangzi 'Person1 친구의 참조 유형 값을 수정한다는 것은 Person2의 친구도 변경 될 것임을 의미합니다. 실제로, 프로토 타입에 저장된 친구는 실제로 힙의 친구들 가치에 대한 포인터 일뿐입니다 (이 포인터의 길이는 고정되어 스택에 저장됩니다). 인스턴스가 프로토 타입을 통해 참조 유형 값에 액세스하면 해당 인스턴스에서 사본에 액세스하는 대신 포인터에 의해 액세스됩니다 (이 사본은 존재하지 않음).
1.1.4. 생성자 및 프로토 타입 패턴과 함께 객체를 만듭니다
생성자 및 프로토 타입 모드의 장점을 결합하여 각 단점을 보충하고 생성자를 사용하여 초기화 매개 변수를 전달하고 인스턴스 속성을 정의하고 프로토 타입을 사용하여 공통 메소드 및 공개 속성을 정의합니다. 이 모드는 가장 널리 사용됩니다.
기능인 (이름, 나이) {this.name = 이름; this.age = age; this.friends = [ 'ajiao', 'jianjian', 'pangzi'];} person.prototype = {생성자 : person, logname : function () {console.log (this.name); }} var person1 = 새로운 사람 ( 'evansdiy', '22'); var person2 = 새로운 사람 ( 'amy', '21'); person1.logname (); // 'evansdiy'person1.friends.push ('haixao '); console.log (person2.friftles.length); // 31.1.5. 프로토 타입 동적 모드
프로토 타입 동적 모드는 필요한 모든 정보를 생성자에 캡슐화하고 IF 문을 사용하여 프로토 타입의 특정 속성이 존재하는지 여부를 결정합니다. 존재하지 않는 경우 (생성자가 처음으로 요구 될 때) IF 문 내에서 프로토 타입 초기화 코드를 실행하십시오.
기능인 (이름, 나이) {this.name = 이름; this.age = age; if (this.logname! = 'function') {person.prototype.logname = function () {console.log (this.name); }; person.prototype.logage = function () {console.log (this.age); }; }; . var person2 = new Person ( 'Amy', '21'); // logname () 메소드가 이미 존재하고 프로토 타입이 다시 수정되지 않습니다.이 패턴은 객체 문자 그럴 구문을 사용하여 프로토 타입 객체를 작성할 수 없다는 점에 유의해야합니다 (프로토 타입 객체를 무시합니다). 프로토 타입이 다시 작성되면 생성자가 만든 첫 번째 인스턴스에 액세스 할 수있는 프로토 타입 객체는 IF 문에 프로토 타입 객체 속성을 포함하지 않습니다.
기능인 (이름, 나이) {this.name = 이름; this.age = age; if (this.logname! = 'function') {person.prototype = {logname : function () {console.log (this.name); }, 로지 : function () {console.log (this.age); }}}};} var person1 = new Person ( 'evansdiy', '22'); var person2 = new person ( 'amy', '21'); person2.logname (); // 'amy'person1.logname (); // logname () 메서드가 존재하지 않습니다.각 모델에는 자체 응용 프로그램 시나리오가 있으며 장점과 단점은 중요하지 않습니다.
JavaScript에서 객체를 만드는 다양한 패턴에 대한 위의 분석은 내가 공유하는 모든 내용입니다. 나는 그것이 당신에게 참조를 줄 수 있기를 바랍니다. 그리고 당신이 wulin.com을 더 지원할 수 있기를 바랍니다.