⚡객체지향 프로그래밍에서 객체는 뭐라고 생각하세요?
객체지향 프로그래밍에서 객체는
상태 데이터와 동작을 하나의 논리적인 단위로 묶은 복합적인 자료구조라고 생각합니다.
객체의 상태데이터로는 프로퍼티를 동작으로는 메서드를 말할 수 있을것입니다.
⚡객체지향에서 상속은 뭔가요?
상속은 어떤 객체의 프로퍼티 또는 메서드를 다른 객체가 상속받아 그대로 사용할 수 있는 것을 말합니다.
자바스크립트는 프로토타입을 기반으로 상속을 구현하여 중복을 제거합니다.
⚡생성자 함수의 문제점은 뭐가 있을까요?
동일한 생성자 함수에 의해 생성된 모든 인스턴스가 동일한 메서드를 중복 소유하는 건
메모리를 불필요하게 낭비한다는 문제점이 있습니다.
또한 인스턴스를 생성할 때마다 메서드를 생성하므로 퍼포먼스에도 악영향을 줍니다.
자바스크립트에서는 프로토타입을 기반으로 상속을 구현해 불필요한 중복을 제거합니다.
프로토타입에 대한 스피드 웨건
function Circle(radius) {
this.radius = radius
}
Circle.prototype.getArea = function () {
return Math.PI * this.radius ** 2
}
const circle1 = new Circle(1)
const circle2 = new Circle(2)
console.log(circle1.getArea === circle2.getArea) // true
Circle 생성자 함수로 생성한 모든 인스턴스에 getArea 메서드를 공유해서 사용할 수 있도록
프로토타입에 getArea 메서드를 추가합니다.
그 후 인스턴스를 생성한 뒤 두 인스턴스의 getArea를 비교해보면 true가 반환되어
두 인스턴스가 같은 메서드를 공유한다는 것을 확인할 수 있습니다.
즉 프로토타입으로 메서드를 추가해주면 불필요하게 동일한 메서드를 중복 생성하는게 아니라
하나의 메서드를 공유해서 사용하는 상속같은 결과를 만드는군요!!!
이렇듯 Circle생성자 함수가 생성한 모든 인스턴스는 자신의 프로토타입(상위 객체)인
Circle.prototype의 모든 프로퍼티와 메서드를 상속받는다는 것을 알 수 있습니다.
근데 프로토타입은 상속이 가지는 단점도 그대로 공유하는것일까요..? 그건 좀 궁금하네요
https://xionwcfm.tistory.com/101
⚡프로토타입 객체에 대해 설명해주세요
프로토타입 객체는 객체 간 상속을 구현하기 위해 사용됩니다.
프로토타입은 어떤 객체의 부모 객체 역할을 하는 객체로서 다른 객체에
공유 프로퍼티와 공유 메서드를 제공합니다.
모든 객체는 [[Prototype]]이라는 내부 슬롯을 가지며 내부 슬롯의 값은
프로토타입의 참조입니다.(프로토타입 객체가 없는 경우 내부슬롯의 값은 null 입니다.)
프로토타입 내부슬롯에 저장되는 프로토타입은 객체 생성 방식에 따라 결정됩니다.
모든 프로토타입은 생성자 함수와 연결되어있습니다.
모든 객체는 __proto__ 접근자 프로퍼티를 통해 자신의 프로토타입 내부슬롯에 간접접근할수있습니다.
⚡프로토타입 체인의 종점은 어디인가요?
그것은 Object.prototype 입니다.
모든 객체는 프로토타입 체인에 묶여있고 자바스크립트 엔진은 객체의 프로퍼티에 접근할 때
해당 객체에 접근하려는 프로퍼티가 없으면 __proto__접근자 프로퍼티가 가리키는
참조를 따라서 자신의 부모 역할을 하는 프로토타입의 프로퍼티를 순차적으로 검색합니다.
즉 프로토타입 체인의 최상위 객체는 object.prototype이고
이 객체의 프로퍼티와 메서드는 모든 객체에 상속됩니다.
⚡__proto__ 접근자 프로퍼티를 이용해 프로토타입에 접근하는 이유는?
상호 참조에 의해 프로토타입 체인이 생성되는 것을 방지하기 위해서입니다.
그것이 [Prototype]] 내부 슬롯의 값 즉 프로토타입에 접근하기 위해 접근자 프로퍼티를 사용하는 이유입니다.
프로토타입 체인은 단방향 링크드리스트 형태로 구현되어야 하는데 서로가 자신의 포로토타입이 되는
순환 참조형식의 프로토타입 체인이 만들어지면 무한루프에 빠지게됩니다.
⚡__proto__ 대신 사용할 메서드는 뭐가 있나요?
object.getPrototypeOf 메서드를 이용합니다.
__proto__접근자 프로퍼티는 모든 객체가 __proto__ 접근자 프로퍼티를 사용하는 것이 아니기 때문입니다.
// obj는 프로토타입 체인의 종점이다. 따라서 Object.__proto__를 상속받을 수 없습니다.
const obj = Object.create(null)
//obj는 Object.__proto__를 상속받을 수 없습니다.
console.log(obj.__proto__) // undefined
console.log(Object.getPrototypeOf(obj)) // null
Object.create(proto[, propertiesObject])
위 코드에서 obj는 프로토타입체인의 종점인 Object를 create해서
Object.prototype을 상속받지 않습니다.
따라서 위 예제에서 obj는 참조하는 prototype이 Object.prototype이 아니라 null이기 때문에
Object.prototype이 상속해주는 프로퍼티들을 사용할 수 없는 상태입니다.
그래서 obj.__proto__를 하면 obj의 프로토타입체인에 __proto__가 없기 때문에
__proto__ 접근자 프로퍼티를 사용할수도 없고
프로토타입체인을 끝까지 탐색해도 __proto__를 찾을 수 없기 때문에 undefined를 반환합니다.
하지만 Object.getPrototypeOf(obj)는 Object의 getPrototypeOf()메서드를 사용하면서
인자로 obj를 넣어주는 형태이기 때문에
둘의 동작과정은 같지만 다르게 동작하는 것을 확인할 수 있습니다.
⚡함수 객체의 프로토타입 프로퍼티에 대해 말해주세요
함수 객체만이 소유하는 prototype 프로퍼티는 생성자 함수가 생성할 인스턴스의 프로토타입을 가리킵니다.
따라서 화살표 함수와 ES6 메서드 축약 표현으로 정의한 메서드는
prototype프로퍼티가 없고 프로토타입을 생성하지도 않습니다.
생성자 함수로 호출하기 위해 정의하지 않은 일반함수(함수 선언문, 표현식)도
prototype 프로퍼티를 소유하긴 하지만 객체를 생성하지 않는 일반 함수의
prototype 프로퍼티는 아무런 의미가 없습니다.
거의 모든 객체가 가지고 있는 __proto__접근자 프로퍼티와 함수 객체만이 갖고 있는 prototype 프로퍼티는
결국 동일한 프로토타입을 가리킵니다.
하지만 이들 프로퍼티를 사용하는 주체가 다릅니다.
구분 | 소유 | 값 | 사용주체 | 사용 목적 |
__proto__ 접근자 프로퍼티 | 모든 객체 | 프로토타입의 참조 | 모든 객체 | 객체가 자신의 프로토타입에 접근 또는 교체하기 위해 사용 |
prototype 프로퍼티 | constructor | 프로토타입의 참조 | 생성자 함수 | 생성자 함수가 자신이 생성할 객체(인스턴스)의 프로토타입을 할당하기 위해 사용 |
즉 __proto__ 는 객체가 자기꺼에 접근할 때 사용
prototype 프로퍼티는 생성자 함수가 자기가 만들 객체에 할당하기 위해 사용한다는 거군요
⚡모든 프로토타입은 constructor 프로퍼티를 갖나요?
네 모든 프로토타입은 constructor 프로퍼티를 갖습니다.
이 constructor 프로퍼티는 자신을 참조하고 있는 생성자 함수를 가리킵니다.
이 연결은 생성자 함수가 생성 될 때 즉 함수 객체가 생성될 때 이루어집니다.
⚡리터럴 표기법에 의해 생성된 객체가 가리키는 생성자 함수??
리터럴 표기법에 의해 생성된 객체도 프로토타입이 존재합니다.
하지만 이 경우 프로토타입의 constructor 프로퍼티가 가리키는 생성자 함수가 반드시
객체를 생성한 생성자 함수라고 단정할 수 없습니다.
const = {}
// 객체 리터럴로 객체 생성
console.log(obj.constructor === Object) // true
왜 이런 결과가 나타나는 걸까요?
Object 생성자 함수에 인수를 전달하지 않거나 undefined 또는 null을 인수로 전달하면서 호출하면
내부적으로는 추상 연산 OrdinaryObjectCreate를 호출하여
Object.prototype을 프로토타입으로 갖는 빈 객체를 생성하기 때문에
객체 리터럴로 생성한 객체는 Object를 constructor로 갖습니다.
⚡객체리터럴이랑 생성자 함수 호출은 같은거에요?
아니오
Object 생성자 함수 호출과 객체 리터럴의 평가는 추상 연산 OrdinaryObjectCreate를 호출하여
빈 객체를 생성하는 점은 똑같지만
new.target의 확인이나 프로퍼티를 추가하는 처리 등 세부 내용은 다릅니다.
그렇기 때문에 객체 리터럴에 의해 생성된 객체는 Object 생성자 함수가 생성한 객체가 아닙니다.
⚡아니 추상 연산이 뭔데요?
추상 연산은 ECMAScript 사양에서 내부 동작의 구현 알고리즘을 표현한 것입니다.
수도코드 비슷한거라고 하네요..
⚡그럼 생성자함수 안쓰고 만든 함수객체의 constructor 프로퍼티는요?
function 생성자 함수를 호출하여 만든 함수는 렉시컬 스코프를 만들지 않고
전역 함수인것처럼 스코프를 생성하며 클로저를 만들지 않습니다.
그렇기 때문에 함수 선언문, 표현식을 평가해서 생성한 함수객체는 function 생성자 함수가 아닙니다.
하지만 constructor 프로퍼티를 통해 확인해보면
함수선언문으로 생성한 함수의 생성자 함수도 function 생성자 함수입니다.
이것은 생성자 함수 호출로 생성한 것과 함수 리터럴의 평가의 세부처리가 다르기 때문에
일어나는 일이라고 볼 수 있겠네요
이렇듯 리터럴 표기법에 의해 생성된 객체도 가상적인 생성자 함수를 갖습니다.
이것은 프로토타입과 생성자 함수는 단독으로 존재할 수 없으며
언제나 pair로 존재한다는 것을 뜻합니다.
⚡ 그럼 리터럴 표기법으로 만든거랑 생성자 함수로 만든거랑 다른거에요?
리터럴 표기법에 의해 만든 객체는 생성자 함수에 의해 생성된 객체가 아니긴 합니다
하지만 크게 생각해보면 리터럴 표기법으로 생성한 객체도 생성자 함수로 생성한 객체와
본질적으로 크게 다르지는 않습니다.
그 둘은 생성 과정에서 작은 차이가 있지만 객체로서 동일한 특성을 가지기 때문입니다.
⚡프로토타입의 생성시점에 대해 말해주세요
프로토타입은 생성자 함수가 생성되는 시점에 더불어 생성됩니다.
리터럴 표기법에 의해 생성된 객체도 결국은 생성자 함수와 연결됩니다.
객체는 리터럴 표기법, 생성자 함수 두가지 방법으로 생성되므로 모든 객체는 생성자 함수와 연결되어있습니다.
프로토타입과 생성자 함수는 단독으로 존재할 수 없고 언제나 쌍으로 존재하기 때문입니다.
constructor는 함수 정의가 평가되어 함수 객체를 생성하는 시점에 프로토타입도 더불어 생성됩니다.
⚡생성자 함수는 어케 구분 할 수 있나요?
생성자 함수는 사용자가 직접 정의한 사용자 정의 생성자 함수와
자바스크립트가 기본 제공하는 빌트인 생성자 함수로 구분할 수 있습니다.
⚡사용자 정의 생성자 함수의 프로토타입 생성 시점은 언제인가요?
사용자 정의 생성자 함수는 자신이 평가되어 함수 객체로 생성되는 시점에
프로토 타입도 더불어 생성되며 생성된 프로토타입의 프로토타입은
언제나 Object.prototype 입니다.
따라서 함수 선언문으로 정의된 함수의 경우 런타임 이전에 함수 객체가 되고
이때 더불어서 프로토타입도 생성됩니다. 이 생성된 프로토타입은
생성자 함수의 prototype 프로퍼티에 바인딩됩니다.
⚡빌트인 생성자 함수의 프로토타입 생성 시점은 언제인가요?
먼저 빌트인 생성자 함수는 다음과 같습니다.
Object, String, Number, Function , Array, RegExp, Date, Promise 등
빌트인 생성자 함수는 일반 함수와 마찬가지로 빌트인 생성자 함수가
생성되는 시점에 프로토타입이 생성됩니다.
모든 빌트인 생성자 함수는 전역 객체가 생성되는 시점에 생성됩니다.
생성된 프로토타입은 빌트인 생성자 함수의 prototype 프로퍼티에 바인딩됩니다.
이처럼 객체가 생성되기 이전에 생성자 함수와 프로토타입은 이미 객체화되어 존재합니다.
이후 생성자 함수 또는 리터럴 표기법으로 객체를 생성하면
프로토타입은 생성된 객체의 [[Prototype]] 내부 슬롯에 할당됩니다.
⚡객체의 생성 방식을 알려주세요
1. 객체 리터럴
2. Object 생성자 함수
3. 생성자 함수
4. Object.create 메서드
5. 클래스(ES6)
하지만 생성된 모든 객체는 약간의 차이는 있어도 추상연산 ordinaryObjectCreate에 의해
생성된다는 공통점이 존재합니다.
** OrdinaryObjectCreate의 동작 과정
1. 자신이 생성할 객체의 프로토타입을 인수로 전달받는다.
2. 자신이 생성할 객체에 추가할 프로퍼티 목록을 옵션으로 전달할 수 있다.
3. 빈 객체를 생성한 후 프로퍼티 목록이 인수로 전달된 경우 프로퍼티를 객체에 추가한다.
4. 인수로 전달받은 프로토타입을 자신이 생성한 객체의 [[prototype]] 내부슬롯에 할당한다.
5. 생성한 객체를 반환한다.
⚡객체 리터럴로 만든 객체의 프로토타입은?
자바스크립트 엔진은 객체 리터럴을 평가해 객체를 생성할 때 OrdinaryObjectCreate를 호출합니다.
이때 전달되는 프로토타입은 Object.prototype 입니다.
따라서 객체 리터럴로 만든 객체는
constructor, hasownProperty 메서드 등을 소유하지 않지만
Object.prototype의 constructor , hasownProperty 메서드를 자신의 것처럼 사용할 수 있습니다.
object.prototype 객체를 상속받았기 때문입니다.
⚡그럼 생성자 함수로 만들면요?
리터럴과 비슷하게 OrdinaryObjectCreate가 호출됩니다.
다만 이때 전달되는 프로토타입은 생성자 함수의 prototype 프로퍼티에 바인딩되어있는 객체입니다.
즉 생성자 함수에 의해 생성되는 객체의 프로토타입은
생성자 함수의 prototype 프로퍼티에 바인딩되어 있는 객체입니다
⚡프로토타입의 프로토타입은 언제나 object.prototype일까요?
네
⚡프로토타입체인에 대해 말해주세요
자바스크립트는 객체의 프로퍼티에 접근하려고 할 때 해당 객체에 접근하려는 프로퍼티가 없다면
[[property]]내부 슬롯의 참조를 따라 순차적으로 프로토타입의 프로퍼티를 검색합니다.
이것을 프로토타입 체인이라고 하며 프로토타입체인은
자바스크립트가 객체지향 프로그래밍의 상속을 구현하는 메커니즘입니다.
⚡만약 프로토타입체인의 종점에 가도 프로퍼티를 검색할 수 없으면 어떻게 되나요?
undefined가 반환됩니다.
따로 에러가 발생하지 않습니다.
⚡프로토타입체인과 스코프체인의 차이가 뭘까요?
그것은 검색하는 대상의 차이입니다.
프로토타입체인은 상속과 프로퍼티 검색을 위한 메커니즘이라고 할 수 있고
스코프체인은 프로퍼티가 아닌 식별자 검색을 위한 메커니즘이라고 할 수 있습니다.
허나 스코프체인과 프로토타입 체인은 서로 별도의 동작을 하는 것이 아닌
서로 협력하여 식별자와 프로퍼티를 검색하는데 사용됩니다.
⚡오버라이딩이 뭔가요?
오버라이딩이란 상위 클래스가 가지고 있는 메서드를
하위 클래스가 재정의하여 사용하는 방식을 말합니다.
⚡그럼 오버로딩은 뭔데요
오버로딩이란 함수의 이름은 동일하지만 매개변수의 타입 또는 개수가 다른 메서드를 구현하고
매개변수에 의해 메서드를 구별하여 호출하는 방식을 말합니다.
다만 자바스크립트에서는 오버로딩을 지원하지 않고
arguments 객체를 사용하여 구현은 할 수 있습니다.
⚡프로퍼티 섀도잉이 뭔가요?
프로퍼티 섀도잉이란 상속관계에 의해 프로퍼티가 가려지는 현상을 말합니다.
프로토타입 프로퍼티와 같은 이름의 프로퍼티를 인스턴스에 추가하면
프로토타입체인을 따라 프로토타입 프로퍼티를 검색하는게 아니라
인스턴스 프로퍼티로 추가합니다.
이 과정에서 오버라이딩이 발생하게되고 이 상속관계에 의해
프로토타입 프로퍼티가 가려지는 현상을 프로퍼티 새도잉이라고 합니다.
다만 하위 객체를 통해 프로토타입의 프로퍼티를 변경,삭제하는것은 불가능합니다.
정확히는 get 액세스는 허용되지만 set 액세스는 허용되지 않습니다.
** 프로토타입 프로퍼티? 인스턴스 프로퍼티?
프로토타입이 소유한 프로퍼티를 프로토타입 프로퍼티
인스턴스가 소유한 프로퍼티를 인스턴스 프로퍼티라고합니다.
**그럼 프로토타입 프로퍼티를 변경하고 싶으면요?
프로토타입에 직접 접근해야합니다.
⚡프로토타입의 교체에 대해 설명해주세요
프로토타입은 동적으로 변경할 수 있습니다. 즉 객체 간의 상속 관계를 동적으로 변경 가능합니다.
프로토타입은 생성자 함수 또는 인스턴스에 의해 교체할 수 있습니다.
생성자 함수로 프로토타입 동적 교체하기
const Person = (function () {
function Person(name) {
this.name = name
}
Person.prototype = {
sayHello() {
console.log(`HI`)
}
}
return Person
}())
const me = newPerson('Lee')
위 예제에서는 Person.prototype에 객체 리터럴을 할당합니다.
이는 Person 생성자 함수가 생성할 객체의 프로토타입을 객체 리터럴로 교체한것입니다.
변수 me의 생성자 함수를 검색하면 Person이 아닌 object가 나옵니다.
즉 constructor 프로퍼티와 생성자 함수간의 연결이 파괴됩니다.
생성자 함수 프로토타입 살려내기
const Person = (function () {
function Person(name) {
this.name = name
}
Person.prototype = {
constructor : Person,
sayHello() {
console.log(`HI`)
}
}
return Person
}())
const me = newPerson('Lee')
⚡인스턴스에 의한 프로토타입의 교체는요?
프로토타입은 생성자 함수의 prototype 프로퍼티로도 접근가능하지만
인스턴스의 __proto__ 접근자프로퍼티나 Object.getPrototypeOf() 메서드를 통해서도 접근할 수 있습니다.
따라서 위 프로퍼티와 메서드를 이용해서도 프로토타입을 교체할 수 있습니다.
생성자 함수의 prototype 프로퍼티에 다른 임의의 객체를 바인딩하는 것은
미래에 생성할 인스턴스의 프로토타입을 교체하는 것입니다.
하지만
__proto__ 같은 인스턴스에 의한 프로토타입 교체는
이미 생성된 객체의 프로토타입을 교체합니다.
⚡프로토 타입은 직접 교체하는게 좋을까요?
음..아니오
프로토 타입 교체를 통해 상속 관계를 동적으로 변경하는 것은 꽤나 번거롭습니다.
따라서 상속관계를 인위적으로 설정하고자한다면 직접 상속이 더 편리하고 안전할 것입니다.
혹은 클래스를 사용하면 간편하고 직관적으로 상속관계를 구현할 수도 있습니다.
⚡instanceof 연산자에 대해 말해주세요
이항 연산자로 좌변에 객체를 가리키는 식별자 우변에 생성자 함수를 가리키는 식별자를 피연산자로 받습니다.
만약 좌변의 객체의 프로토타입체인에 우변의 생성자함수가 존재하면 True 아니면 false를 반환합니다.
⚡직접 상속에 대해 말해주세요
직접 상속은 두가지 방법으로 구현할 수 있습니다.
1. Object.create()에 의한 직접 상속
2. 객체 리터럴 내부에서 __proto__에 의한 직접 상속
Object.create를 사용하면
new 연산자 없이도 생성할 수 있고 프로토타입을 지정하여 객체를 생성할 수 있으며
객체 리터럴에 의해 생성된 객체를 상속받을 수도 있습니다.
__proto__에 의한 직접상속
const myProto = {x:10}
const obj = {
y:20,
__proto__ : myProto
}
⚡정적 프로퍼티/메서드가 뭔가요?
정적 프로퍼티/메서드는 생성자 함수로 인스턴스를 생성하지 않아도
참조/호출 할 수 있는 프로퍼티/ 메서드를 말합니다.
정적 프로퍼티/메서드는 생성자 함수가 생성한 인스턴스로 참조/호출 할 수 없습니다.
예시로는 Object.create()를 들 수 있는데 이경우
Object.create() 는 정적 메서드로 Object 생성자 함수가 생성한 객체로 호출할 수 없습니다.
⚡for...in문에 대해 설명해주세요
for..in문은 객체의 프로토타입 체인 상에 존재하는 모든 프로토타입의 프로퍼티 중에서
프로퍼티 어트리뷰트 [[enumerable]]의 값이 true인 프로퍼티를 순회하며 열거합니다.
만약 상속받은 프로퍼티를 제외하고 자신의 프로퍼티만 열거하려면
Object.prototype.hasOwnProperty()메서드를 이용해서 객체 자신의 프로퍼티인지 확인해야합니다.
'javascript' 카테고리의 다른 글
자바스크립트의 this를 이해해보자 (0) | 2023.01.12 |
---|---|
요약 정리는 못 참지 않을까요? (6) (0) | 2023.01.12 |
요약 정리는 못 참지 않을까요? (4) (0) | 2023.01.10 |
요약 정리는 못 참지 않을까요? (3) (0) | 2023.01.10 |
요약 정리는 못 참지 않을까요?(2) (0) | 2023.01.06 |