객체의 모든 것이라는 어그로성 제목의 글이지만 내가 면접을 보는데 정말 아무 것도 모르는 미지의 세계인 객체, 상속 , 프로토타입 , 생성자 함수 등을 다루는 글이다. 이미 아는 이야기를 할 수 도있고 이상한 이야기를 할 수도있다. 최대한 많은 조사를 해서 사실 기반으로 다루기 위해서 노력했다는 것을 알아주시고 잘못된 정보에 대한 피드백은 언제나 환영입니다.
자바스크립트에서는 거의 모든게 객체입니다. 함수도 객체... 배열도 객체.. 이 글에서는 명확한 호칭을 정리하기 위해 객체라는 것과 최상위 Object 를 다르게 생각하고 글을 써내려갔습니다.
자바스크립트는 객체기반의 언어이다. 라는 이야기는 프로그래밍 세계에서 속담처럼 내려오는 구문이다. 그럼 객체가 무엇인지 부터 생각해보자.
자바스크립트에서 객체(Object)는 프로퍼티와 메서드의 집합체 이다.
ECMAScript 사양에서 사용하는 이중괄호[[]]로 감싼 이름들이 내부 슬롯과 내부 메서드이다.
내부 슬롯과 내부 메서드들은 자바스크립트 엔진에서 실제로 동작하지만 개발자가 직접 접근할수 있도록 외부로 공개된 객체의 프로퍼티는 아니다. 그러나 [[prototype]] 의 경우 자바스크립트에서 __proto__
프로퍼티를 동해 간접적으로 접근할수있다.
데이터 프로퍼티
[[value]]
[[writable]]
[[Enumerable]]
열거가능 하다 라는 말은 for ...in , forEach 메소드를 사용 할 수 있다는 것이다.
[[Configurable]]
접근자 프로퍼티
[[Get]]
[[Set]]
대표적인 접근자 프로퍼티는 __proto__
가 있는데 get __proto__
와 set __proto__
를 이용해서 [[Prototype]] 내부 슬롯에 간접적으로 접근할 수 있다.
📝 함수가 자바스크립트의 1급 객체다 📝
값
(할당, 전달, 반환 가능) 으로 평가 될 수 있습니다.자바스크립트는 프로토 타입객체를 이용해서 상속을 구현한다. 모든 객체는 [[Prototype]] 이라는 내부슬롯을 가지며 이 내부 슬롯의 값은 프로토타입의 참조다.
[[Prototype]]에 저장되는 값은 객체가 생성될때 객체 생성 방식에 따라 프로토 타입이 결정되고 저장된다.
__proto__
접근자 프로퍼티proto 접근자 프로퍼티는 객체가 직접 소유하는 프로퍼티가 아니라 Object.prototype의 프로퍼티다.
[[Prototype]]에 접근자 프로퍼티를 이용해서 접근하는 이유는 사옿 참조에 의해 프로토 타입 체인이 생성되는 것을 방지 하기 위해서 이다.
상호 참조라는 것은 자식의 프로토타입이 부모를 가리키고있지만 부모의 프로토 타입도 자식을 가리키고있을 때를 말한다.
그러나 코드 내에서 proto 접근자 프로퍼티를 이용해서 상속을 구현하는 것은 추천되지 않는다.
몇가지 예외사항이 있기 때문인데. 직접 상속을 통해 Object.prototype 을 상속 받지 않는 객체를 생성 할 수있기때문에 proto 에 접근하지 못하는 경우가 생긴다.
함수 객체만이 소유하는 prototype 프로퍼티는 생성자 함수가 생성할 인스턴스의 프로토 타입을 가리킨다.
모든 프로토 타입은 constructor 프로퍼티를 가진다.
객체를 생성하는 방법과 그 방법에 따른 상속은 어떻게 이뤄지는지 알아보자.
리터럴
은 사람이 이해할수있는 문자를 사용해서 값을 생성하는 표기법을 말합니다 .객체리터럴은 중괄호 안의 {} 키와 value 로 선언된 프로퍼티들을 해석해서 객체를 생성한다.
const obj = {
key : 'value'
}
선언된 프로퍼티를 해석해서 Object.prototype 을 프로토 타입으로 가지게 되며 상속받는다. 그렇기 때문에 obj 는 접근자 프로퍼티__proto__
와 constrictor 등의 프로퍼티를 자신의 것처럼 쓸 수 있습니다.
new 연산자와 함께 생성자 함수를 호출하면 빈객체를 생성하여 반환한다. 빈객체를 생성한 이후 프로퍼티와 메서드들을 추가하여 객체를 완성할 수 잇다 . 생성자 함수(constructor)에 의해서 생성된 객체를 인스턴스
라고 한다.
const obj = new Object()
Object 생성자 함수에 의해 생성된 obj 객체는 객체리터럴에 의한 생성과 같이 Object.prototype을 프로토 타입으로 가지게 되고 상속받습니다.
constructor
프로퍼티는 생성자함수 Object를 가르킨다.
constructor - Object
obj.constructor === Object // true
Object.protoype
는 생성된 객체의 프로토타입에 저장된다.
[[Prototype]] <- Object.protoype
obj.__proto__ === Object.prototype // true
Object , String, Number, Array 등 자바스크립트의 빌트인 생성자 함수 뿐만이 아니라, 우리가 만든 함수에도 new 를 붙이면 생성자 함수가 된다.
함수 정의가 평가되어 함수 객체를 생성하는 시점에 프로토 타입도 더불어 생성된다.
생성자 함수에서의 객체생성은 다음과 같은 과정으로 생성된다.
function Person(name) {
this.name = name;
}
const me = new Person('hoo');
Person 생성자 함수에 의해 생성된 me 객체는 Person.prototype을 프로토 타입으로 가지게 되고 상속받습니다.
constructor
프로퍼티는 생성자함수 Person 을 가르킨다.
constructor
- Person
me.constructor === Person // true
Person.protoype
는 생성된 객체의 프로토타입에 저장된다.
[[Prototype]] <- Person.protoype
obj.__proto__ === Object.prototype // true
me 객체는 프로토타입 체인을 통해서 최상위 객체의 prototype에 도달할수있다.
me.__proto__.__proto__ === Object.prototype //ture
class 에 의한 객체 생성 또한 생성자 함수의 객체 생성 에서의 prototype 과 constructor 규칙과 유사하다.
class animal {}
const cat = new animal
cat.constructor === animal // true
animal.protoype
는 생성된 객체의 프로토타입에 저장된다.
[[Prototype]] <- animal.protoype
cat.__proto__ === animal.prototype // true
함수가 호출되는 방식에 따라 달라지는 함수 안의 this
Object.create(proto[, propertiesObject])
let obj = Object.create(null)
create 의 인자에 null을 넣으면 프로퍼티가 하나도 없는 빈객체가 생성된다. 이 객체는 prototype 이 null 이기 때문에 __proto__
프로퍼티도 접근이 불가능하다.
let bam = Object.create(Object.prototype)
proto 라는 인자에 Object.prototype 객체를 넣으면 객체리터럴이나 Object 생성자함수에서 생성되는 객체와 같이 Object.prototype 를 프로토타입으로 가지는 객체가 생성됩니다.
❓ 리터럴 표기법에 의해 생성되는 객체도 생성자 함수와 연결되어지기 때문에 모든 객체는 생성자함수에 연결되어있다. 자바스크립트는 왜 Function.prototype 을 만들어서 생성자 함수들의