##1.객체의 정의##
ECMAScript 에서 객체는 순서 없는 프로퍼티의 집합이며, 여기서의 "프로퍼티"란 기본값, 객체 또는 함수일 수 있습니다
##2.데이터 프로퍼티와 접근자 프로퍼티##
-
데이터 프로퍼티란 값을 가진 프로퍼티로, 프로퍼티를 읽기 전용, 삭제 불가, 열거 불가 등으로 설정할 수 있습니다
-
접근자 프로퍼티는 getter 와 setter 를 설정하는 데 사용되며, 프로퍼티 이름 앞에"_"(밑줄) 를 붙여 해당 프로퍼티는 접근자를 통해서만 액세스 가능함 (프라이빗 프로퍼티) 을 나타내지만, 밑줄을 붙였다고 해서 프로퍼티가 프라이빗이 되는 것은 아닙니다. 이는단순히 관습적인 명명 방식 중 하나일 뿐입니다. 접근자 프로퍼티는 별로 쓸모가 없습니다. 이유는 다음과 같습니다:
var book={ _year:2004, edition:1 } Object.defineProperty(book,"year",{ get:function(){ return this._year; }, set:function(newValue){ if(newValue>2004){ this._year=newValue; this.edition+=newValue-2004; } } }); book.year=2005; alert(book.edition); /* for(var attr in book){ showLine(attr + ' = ' + book[attr]); } */
高程에서는 위의 샘플 코드를 사용했으며, 원리는 book 객체의 프로퍼티 중_year 는 데이터 프로퍼티이고 year 는 접근자 프로퍼티이며, getter 와 setter 를 이용해 읽기 쓰기 제어를 삽입할 수 있다는 것으로, 듣기에는 좋습니다.
하지만 문제는_year 와 edition 은 모두 열거 가능하여, 즉 for...in 루프로 볼 수 있지만, 접근자 프로퍼티 year 는 열거 불가합니다. 공개해야 할 접근자는 공개되지 않고, 숨겨야 할 프라이빗 프로퍼티가 공개되어 버립니다.
그 외에도, 이렇게 접근자를 정의하는 방식은 전체 브라우저 호환이 아니며, [IE9+] 에서만 완전히 지원됩니다. 물론, 구형 브라우저용 방법 (__defineGetter__() 과__defineSetter__()) 도 있지만, 상당히 번거롭습니다.
总之、접근자 프로퍼티는 별로 쓸모가 없습니다.
##3.생성자##
function Fun(){} var fun = new Fun();여기서 Fun 은 생성자이며, 일반 함수와 선언 방식의 차이는 전혀 없고, 호출 방식만 다를 뿐입니다 (new 연산자로 호출)
생성자는 커스텀 타입을 정의하는 데 사용할 수 있습니다. 예를 들어:
function MyClass(){
this.attr = value;//멤버 변수
this.fun = function(){...}//멤버 함수
}
Java 의 클래스 선언과 다소 비슷하지만, 몇 가지 차이점도 있습니다. 예를 들어 this.fun 은 단지 함수 포인터일 뿐이므로, 완전히 다른 액세스 가능한 함수 (글로벌 함수 등) 를 가리키도록 할 수 있지만, 이렇게 하면 커스텀 객체의 캡슐성을 파괴합니다
##4.함수와 프로토타입 prototype##
-
함수를 선언함과 동시에 프로토타입 객체가 생성되며, 함수명이 해당 프로토타입 객체에 대한 참조를保持합니다 (fun.prototype)
-
프로토타입 객체에 프로퍼티를 추가할 수도 있고, 인스턴스 객체에 프로퍼티를 추가할 수도 있습니다. 차이는 프로토타입 객체의 프로퍼티는 해당 타입의 모든 인스턴스가 공유하는 반면, 인스턴스 객체의 프로퍼티는 비공유라는 점입니다
-
인스턴스 객체의 프로퍼티에 액세스할 때, 먼저 해당 인스턴스 객체의 스코프 내에서 검색하고, 찾지 못한 경우에만 프로토타입 객체의 스코프 내에서 검색하므로, 인스턴스의 프로퍼티는 프로토타입 객체의 동명 프로퍼티를쉐도우할 수 있습니다
-
프로토타입 객체의 constructor 프로퍼티는 함수 포인터이며, 함수 선언을 가리킵니다
-
프로토타입을 통해 네이티브 참조 타입 (Object, Array, String 등) 에 커스텀 메서드를 추가할 수 있습니다. 예를 들어 String 에 Chrome 에서는 지원되지 않지만 FF 에서는 지원되는 startsWith 메서드를 추가:
var str = 'this is script'; //alert(str.startsWith('this'));//Chrome 에서 에러 String.prototype.startsWith = function(strTarget){ return this.indexOf(strTarget) === 0; } alert(str.startsWith('this'));//에러가 나지 않음
주의: 네이티브 객체에 프로토타입 프로퍼티를 추가하는 것은 권장되지 않습니다. 이렇게 하면 네이티브 메서드를 의도치 않게 재작성하여 다른 네이티브 코드 (해당 메서드를 호출하는 네이티브 코드) 에 영향을 줄 수 있기 때문입니다
-
프로토타입을 통해 상속을 구현할 수 있습니다. 아이디어는 서브클래스의 prototype 프로퍼티가 슈퍼클래스의 인스턴스를 가리키도록 하여 서브클래스가 액세스 가능한 프로퍼티를 늘리는 것입니다. 따라서 프로토타입 체인으로 연결한 후
서브클래스가 액세스 가능한 프로퍼티 = 서브클래스 인스턴스 프로퍼티 + 서브클래스 프로토타입 프로퍼티 = 서브클래스 인스턴스 프로퍼티 + 슈퍼클래스 인스턴스 프로퍼티 + 슈퍼클래스 프로토타입 프로퍼티 = 서브클래스 인스턴스 프로퍼티 + 슈퍼클래스 인스턴스 프로퍼티 + 슈퍼슈퍼클래스 인스턴스 프로퍼티 + 슈퍼슈퍼클래스 프로토타입 프로퍼티 = ...
최종적으로 슈퍼슈퍼...슈퍼클래스 프로토타입 프로퍼티는 Object.prototype 이 가리키는 프로토타입 객체의 프로퍼티로 대체됩니다
구체적인 구현은 SubType.prototype = new SuperType();이며, 이를 심플 프로토타입 체인 방식의 상속이라고 할 수 있습니다
##5.커스텀 타입을 생성하는 최선의 방법 (생성자 패턴 + 프로토타입 패턴)##
인스턴스 프로퍼티는 생성자로 선언하고, 공유 프로퍼티는 프로토타입으로 선언합니다. 구체적인 구현은 다음과 같습니다:
function MyObject(){
//인스턴스 프로퍼티
this.attr = value;
this.arr = [value1, value2...];
}
MyObject.prototype = {
constructor: MyObject,//서브클래스가 올바른 생성자 참조를保持하도록 보장。否则 서브클래스 인스턴스의 constructor 는 Object 의 생성자를 가리키게 됩니다. 프로토타입을 익명 객체로 변경했기 때문
//공유 프로퍼티
fun: function(){...}
}
##6.상속을 구현하는 최선의 방법 (패러시틱 콤비네이션 상속)##
function object(obj){//프로토타입이 obj 이고 인스턴스 프로퍼티가 없는 객체를 반환
function Fun(){}
Fun.prototype = obj;
return new Fun();
}
function inheritPrototype(subType, superType){
var prototype = object(superType.prototype);//프로토타입 체인 구축, 슈퍼클래스 프로토타입 프로퍼티 상속. 커스텀 함수 object 로 처리하는 이유는 서브클래스 프로토타입이 되는 슈퍼클래스 인스턴스가 인스턴스 프로퍼티를 가지지 않도록 하기 위함. 간단히 말해,余分한 인스턴스 프로퍼티를 잘라내기 위함. 콤비네이션 상속과 비교하여 이해할 수 있음
prototype.constructor = subType;//생성자가 올바르도록 보장. 프로토타입 체인은 서브클래스가 保持하는 생성자 참조를 변경하므로, 프로토타입 체인 구축 후 다시 되돌려야 함
subType.prototype = prototype;
}
function SubType(arg1, arg2...){
SuperType.call(this, arg1, arg2...);//슈퍼클래스 인스턴스 프로퍼티 상속
this.attr = value;//서브클래스 인스턴스 프로퍼티
}
inheritPrototype(SubType, SuperType);
구체적인 설명은 코드 주석 참조. 이 방식은 SubType.prototype = new SuperType(); 심플 프로토타입 체인의 단점을 회피합니다:
-
서브클래스 인스턴스가 슈퍼클래스 인스턴스 참조 프로퍼티를 공유하는 문제 (프로토타입 참조 프로퍼티는 모든 인스턴스가 공유하므로, 프로토타입 체인을 구축하면 슈퍼클래스의 인스턴스 프로퍼티가 자연스럽게 서브클래스의 프로토타입 프로퍼티가 됨).
-
서브클래스 인스턴스 생성 시 슈퍼클래스 생성자에 파라미터를 전달할 수 없음
##7.상속을 구현하는 가장 일반적인 방식 (콤비네이션 상속)##
위의 inheritPrototype(SubType, SuperType);문을 다음과 같이 교체:
SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;
이 방식의 단점은: 슈퍼클래스의 컨스트럭트 메서드를 2 번 호출하므로, 余分한슈퍼클래스 인스턴스 프로퍼티가 존재한다는 점입니다. 구체적인 이유는 다음과 같습니다:
첫 번째 SuperType.call(this);문에서 슈퍼클래스에서 슈퍼클래스 인스턴스 프로퍼티를 한 부 복사하여 서브클래스의 인스턴스 프로퍼티로 하고, 두 번째 SubType.prototype = new SuperType();에서 슈퍼클래스 인스턴스를 생성하여 서브클래스 프로토타입으로 합니다.此时이 슈퍼클래스 인스턴스에는 또 하나의 인스턴스 프로퍼티가 있지만, 이는 첫 번째에 복사된 인스턴스 프로퍼티에 의해 쉐도우되어 버리므로, 余分합니다.
아직 댓글이 없습니다