JavaScript의 객체 모델은 널리 알려져 있지 않습니다. 나는 한때 그들에 대해 블로그를 썼습니다. 잘 알려지지 않은 이유 중 하나는 널리 사용되는 언어 중 프로토타입을 통해 상속을 구현하는 언어가 자바스크립트뿐이라는 점이다. 그러나 또 다른 이유는 이 객체 모델이 매우 복잡하고 설명하기 어렵다는 점이라고 생각합니다. 왜 이렇게 복잡하고 혼란스럽습니까? 이는 JavaScript가 전통적인 객체지향 특성을 숨기려고 시도하여 궁극적으로 이중 성격을 가지게 되었기 때문입니다(역자 주: 저자는 JavaScript가 프로세스 지향 특성과 객체 지향 특성을 모두 가지고 있음을 의미함).
CoffeeScript, Dart, TypeScript와 같이 컴파일을 통해 JS 코드를 생성할 수 있는 언어가 있는 것은 바로 JavaScript 객체 모델을 이해하고 사용하는 것이 어렵기 때문이라고 생각합니다.
JavaScript의 전임자와 완고한 사람들은 JavaScript가 더 나은 객체 모델을 가지고 있다고 믿으며 모든 사람에게 잊혀질 것이라고 한탄합니다. JavaScript 전문가인 Nicholas Zakas조차도 ECMAScript 6에 추가된 새로운 클래스 구문을 환영합니다. 이는 프로토타입 스타일 구문을 수정한 것에 불과합니다. 즉, 전통적인 OOP가 승리합니다.
대담한 아이디어
그러나 농담으로 아이디어를 하나 생각해 보겠습니다. 전통적인 객체 지향 프로그래밍이 그다지 좋지 않았던 과거로의 여행을 상상해 보겠습니다. 이제 이것은 모든 사람에게 널리 받아들여지고 있습니다. 반대로 프로토타입 기반 상속 모델은 모든 사람에게 널리 받아들여지고 있습니다. 무슨 일이 일어날까요? 우리는 어떤 디자인 패턴을 갖게 될까요?
다시 상상해 봅시다. JavaScript에 생성자가 없거나 새 키워드가 없다면 어떻게 될까요? 다음에 무슨 일이 일어날까요? 과거로 돌아가 보겠습니다. :)
우선, JavaScript에서는 객체 리터럴을 사용하여 새 객체를 생성할 수 있습니다. 아래와 같이
var felix = {
name : 'Felix',
greet: function(){
console.log('안녕하세요, 저는 'this.name'입니다.')
}
}; >
다음으로, 동일한 Greeting 메소드를 공유하기 위해 여러 객체를 생성할 수 있도록 Greeting 기능을 일반화하고 이를 추출하여 일반 위치에 배치한다고 가정해 보겠습니다. 이것을 달성하는 방법은 무엇입니까?
몇 가지 옵션이 있습니다. 먼저 믹스인부터 시작해 보겠습니다.
1. Mixin(Augmentation)
JavaScript 언어에서는 속성을 혼합하는 것이 매우 간단합니다. 혼합하려는 개체에 혼합된 개체의 속성을 복사하기만 하면 됩니다. 이를 구현하기 위해 "증강" 기능을 사용할 것입니다. 코드를 보면 이해할 수 있습니다.
var Dude = {
greet: function(){
console.log('안녕하세요, 저는 'this.name'입니다.')
}
};
var felix = { name: 'Felix' };
augment(felix, Dude);//Dude의 속성을 felix에 복사합니다. 즉, mixin
위 코드에서 Augment 함수는 Dude 객체의 속성을 felix에 혼합합니다. 많은 JS 라이브러리에서 기능 보강 기능을 확장이라고 합니다. 나는 상속을 표현하기 위해 확장을 사용하는 일부 언어가 혼란스럽기 때문에 확장을 사용하는 것을 좋아하지 않습니다. 나는 "augment"를 사용하여 이를 표현하는 것을 선호합니다. 왜냐하면 실제로 이 접근 방식은 상속이 아니며, Augment(felix, Dude) 구문은 상속이 아닌 Dude의 속성으로 felix를 확장하고 있음을 이미 명확하게 보여주기 때문입니다.
아마도 증강 코드가 구현되어 있다는 것을 이미 짐작하셨을 것입니다. 예, 매우 간단합니다. 아래와 같습니다.
function Aug(obj, 속성){
for(속성 내 var 키){
obj[key] =
}
}
2. Cloning )
mixin의 대안은 Dude 객체를 먼저 복제한 다음 복제된 객체에 name 속성을 설정하는 것입니다. 아래와 같이
var Dude = {
greet : function(){
console.log('안녕하세요. 저는 'this.name'입니다.')
}
}
var felix = clone(Dude);// Dude 객체 복제
felix.name = 'Felix'
두 방법의 유일한 차이점은 속성이 추가되는 순서입니다. 복제된 개체의 특정 메서드를 재정의하려는 경우 이 기술을 사용하는 것이 좋습니다.
var felix = clone(Dude)
felix .name = 'Felix';
felix.greet = function(){
console.log('Yo dawg!')
};//인사 방법 재정의
상위 클래스의 메소드를 호출하려는 경우에도 매우 간단합니다. 아래와 같이 적용 함수를 사용하세요.
felix.greet = function(){
Dude.greet.apply(this)
this.greetingCount ; 🎜>}
생성의 .prototype 속성을 사용할 필요가 없기 때문에 프로토타입 스타일 코드보다 훨씬 낫습니다. 생성자를 사용하지 않습니다.
clone 기능 구현은 다음과 같습니다.
function clone(obj){
var retval = {};//빈 객체 생성
augment(retval, obj);//속성 복사
return retval; 🎜>
3. 상속
마지막으로 상속입니다. 제 생각에는 상속이 과대평가되어 있지만 "인스턴스 개체" 간에 속성을 공유한다는 점에서 상속은 개체 확장에 비해 몇 가지 장점이 있습니다. 객체를 매개변수로 취하고 해당 객체를 상속하는 새 객체를 반환하는 상속 함수를 작성해 보겠습니다.
felix .name = 'Felix';
상속을 사용하면 동일한 개체에서 상속되는 여러 하위 개체를 만들 수 있습니다. 이러한 하위 개체는 상위 개체의 속성을 실시간으로 상속할 수 있습니다. 아래 코드와 같이
코드 복사
코드는 다음과 같습니다. var garfield = 상속( Dude);//garfield는 Dude에서 상속받습니다
Dude.walk = function(){//Dude walk에 새 메서드 추가
console.log('Step, step')
} ;
garfield.walk(); // "Step, step"을 인쇄합니다.
felix.walk(); // "Step, step"도 인쇄합니다.
프로토타입 기반이 사용됩니다. 상속 함수에서 객체 상속
if (Object.create){
//ES5에서 Object.create 메서드 사용
return Object.create(proto)
}else if ({}.__proto__) {
//비표준 속성 사용 __proto__
var ret = {};
ret.__proto__ = proto;
return ret{
//둘 다 그렇지 않은 경우 지원되는 경우 생성자 Inherit
var f = function(){};
f.prototype = proto;
return new f()
}
위의 코드가 보기에 좋지 않습니다. 이는 기능 모니터링을 사용하여 3가지 방법 중 어떤 방법을 사용할지 결정하기 때문입니다.
그런데 생성자 메소드(즉, 초기화 메소드)는 어떻게 사용하나요? 인스턴스 객체 간에 초기화 코드를 어떻게 공유합니까? 어떤 경우에는 객체의 일부 속성만 설정해야 하는 경우 위의 예에서처럼 초기화 함수가 필요하지 않습니다. 그러나 더 많은 초기화 코드가 있는 경우 다음과 같은 규칙을 만들 수 있습니다. 초기화라는 초기화 메서드를 사용합니다. Dude에는 초기화라는 메소드가 다음과 같이 정의되어 있다고 가정합니다.
코드 복사
코드는 다음과 같습니다. var Dude = { initialize: function(){ this.greetingCount = 0;
},
greet: function(){
console.log( '안녕하세요, 저는 'this.name'입니다.');
this.greetingCount ;
}
}
그러면 이렇게 객체를 초기화할 수 있습니다
코드 복사