프로토타입
마지막 챕터인줄 알았는데 아니었다 ㅎ ㅎ
자바스크립트는 프로토타입 기반 언어라고 하는데, 그동안 개발 공부하면서 이에 대해 들을 기회가 딱히 없었다.
https://developer.mozilla.org/ko/docs/Web/JavaScript/Guide/Inheritance_and_the_prototype_chain
상속과 프로토타입 - JavaScript | MDN
JavaScript는 동적 타입이고 정적 타입이 없기 때문에, (Java 또는 C++와 같은) 클래스 기반 언어에 경험이 있는 개발자에게는 약간 혼란스럽습니다.
developer.mozilla.org
MDN에서 클래스 기반 언어 경험이 있는 개발자는 혼란스러울수도 있다고 하는데
나는 처음이니 혼란스러울게 없어서 럭키 비키 잖아? 🍀
어떤 생성자 함수를 new 연산자와 함께 호출하면 Constructor 에서 정의된 내용을 바탕으로 새로운 인스턴스가 생성되는데
이 인스턴스에는 `__proto__` 라는 프로퍼티가 자동으로 부여된다.
이 프로퍼티는 Constructor 의 prototype 프로퍼티를 참조한다.
인스턴스가 자신의 생성자 함수가 무엇인지를 알고자 할때 필요한 수단이다.
생성자 함수
생성자 함수(constructor function)와 일반 함수에 기술적인 차이는 없습니다. 다만 생성자 함수는 아래 두 관례를 따릅니다.
함수 이름의 첫 글자는 대문자로 시작합니다.반드시 'new' 연산자를 붙여 실행합니다.
https://ko.javascript.info/constructor-new
var Person = function (name){
thils._name = name;
}
Person.prototype.getName = function(){
return this._name;
}
var suzi = new Person("suzi");
suzi.__proto__.getName(); // (1) undefined
Proson.prototype === suzi.__proto__ // true;
suzi.__proto__._name = "SUZI__proto__"; // _name 프로퍼티를 부여하고 나면
suzi.__proto__.getName() // (2) SUZI__proto__ 출력됨
suzi.getName(); // (3) suzi 출력됨 : __proto__ 생략 가능하므로
수지 좋아하시나보다
suzi 라는 인스턴스가 생성될때 __proto__ 은 Person.prototype 객체를 동일하게 참조한다.
(1)번 코드에서 getName () 메서드를 호출한 대상이 suzi.__proto__ 가 this 로 바인딩 되기 때문에
(2)번 코드 출력전에 suzi.__proto__ 의 _name 프로퍼티에 값을 부여하고나서야 getName() 에 의해 값이 출력이 된다.
(3) getName() 메서드가 suzi에 의해 바로 호출되면
이때는 this = suzi 이므로 "suzi"가 출력이 된다.
__proto__ 는 생략이 가능하게 설계 되었기때문에 이렇게 작동한다고 이해하면 된다고한다. ^.^
다시한번 이 그림을 문장으로 설명하면
어떤 생성자 함수를 new 연산자와 함께 호출하면 Constructor 에서 정의된 내용을 바탕으로 새로운 인스턴스가 생성되는데
이 인스턴스에는 `__proto__` 라는 프로퍼티가 자동으로 부여된다.
이 프로퍼티는 Constructor 의 prototype 프로퍼티를 참조한다.
또 다른 예시를 보면
let arr = [1,2]
console.dir(arr)
console.dir(Array)
Array 는 생성자 함수이고
arr [1,2] 는 Array 의 인스턴스 이다.
arr [1, 2] 의 __proto__ 에 있는 객체가 Array의 prototype 와 동일한 것을 볼 수 있다.
즉 인스턴스의 __proto__ 는 contruncor.prototype 을 참조한다.
__proto__ 가 생략가능하도록 설계되어있기때문에 인스턴스가 push, pop, forEach 등의 메서드를 마치 자신의 것처럼 호출할 수 있다.
Array.prototype 프로퍼티 내부에 있지 않은 fill, isArray 와 같은 메서드는 인스턴스가 직접 호출할 수 없다.
Array.isArray(arr) // true
arr.isArray(); // 타입에러 - 호출 불가
왜 어떤 메서드는 바로 사용이 가능하고 어떤 메서드는 앞에 Array나 Object를 붙여줘야하나 궁금했는데 이런 이유였군
어떤 객체의 .constructor에 접근해서 변경이 가능하다
-> 생성자 정보를 알아내기 위해 constructor 프로퍼티에 의존하는게 항상 안전한 것은 아님
변경하더라도 이미 만들어진 인스턴스의 원형이 바뀌지는 않는다.
생성자 함수 A의 인스턴스 a에 대해
a.constructor = B 라고 접근하여 변경하더라도
a instanceof B 는 false를 반환한다.
메서드 오버라이드
동일한 이름의 프로퍼티에 메서드를 할당하면 덮어쓰기가 아닌 얹는 방식의 오버라이드가 일어난다
var Person = function (name) {
this.name = name;
}
Person.prototype.getName = function (){
return this.name;
}
var iu = new Person('지금');
iu.getName = function (){
return '바로' + this.name;
}
console.log(iu.getName()) // (1) 바로 지금
console.log(iu.__proto__.getName()) // undefined;
iu.__proto__.name = '이지금';
console.log(iu.__proto__.getName()) // (2) 이지금
console.log(iu.__proto__.getName.call(iu)); // (3) 지금
아이유 좋아하시나보다
Person 생성자 함수의 prototype 객체의 getName 프로퍼티에 메서드를 정의하고,
생성된 인스턴스의 getName 프로퍼티에 에 접근해 다른 메서드로 변경했을때
iu.getName은 오버라이드하여 변경된 메서드가 실행되지만
iu.__proto__ 로 접근하면 (name 프로퍼티도 설정해주면) 원래 메서드가 실행된다. (이때의 this는 iu.__proto__ )
iu.__proto__ = Person.prototype 을 참조하기 때문이지..
getName 이라는 메서드가 호출되면 ?
자바스크립트 엔진은 가장 가까운 대상인 자신의 프로퍼티를 검색하고
없으면 그 다음으로 가까운 대상인 __proto__ 를 검색하는 순으로 진행된다.
__proto__ 로 getName 호출하더라도 ( 이때의 this는 iu.__proto__ )
call이나 apply 로 this 바인딩을 해주면 iu 가 this에 바인딩이 된다.
iu.__proto__.getName.call(iu)
즉 메서드가 오버라이드 되더라도, 원래의 메서드에 __ proto__ 로 우회하여 접근할 수 있다.
프로토타입 체인
어떤 데이터의 __proto__ 프로퍼티 내부에 다시 __proto__ 가 연쇄적으로 이어져 프로토타입 체인을 형성
이 체인을 따라 검색하는 것을 프로토타입 체이닝 이라고 한다.
어떤 생성자 함수이든 prototype = 객체 이므로
Object.prototype 이 프로토타입 체인 최상단에 존재한다.
따라서 Object.prototype 에 있는 메서드를 변경하면, 하위의(?) 다른 객체가 호출했을 때 영향을 미친다.
또한 어떤 데이터에서든 활용할 수 있는 범용적인 메서드만 있다.
즉 객체에서만 사용할 메서드는 다른 여느 데이터 타입처럼 프로토타입 객체 안에 정의할 수 없다.
두 단계 이상의 체인을 지니는 다중 프로토타입 체인도 가능하다
(이 내용은 생략... )
다음 찐막 챕터는 '클래스'이다.
책 반납일 전에 반드시 공부할 것 ^^..
'개발 공부 일지 > 코어 자바스크립트 (정재남)' 카테고리의 다른 글
[코어 자바스크립트] 클래스 (0) | 2025.03.10 |
---|---|
[코어 자바스크립트] 클로저 활용 사례 (0) | 2025.03.04 |
[코어 자바스크립트] 클로저 개념 (0) | 2025.03.04 |
[코어 자바스크립트] 비동기 제어로 콜백 지옥 탈출하기 (1) | 2025.02.25 |
[코어 자바스크립트] 콜백 함수 (0) | 2025.02.25 |