-
[JS] 클래스 문법을 비스무리하게 구현해보자Javascript 2025. 2. 23. 16:09
처음 개발을 알려준 친구가 클래스 문법을 가르쳐 줬던 문구가 아직 생생합니다.
'붕어빵을 먹고 싶을 때, 그냥 붕어빵 가게에 가서 먹으면 한 번 먹고 끝이지만, 직접 붕어빵 틀을 만들어서 먹는다면, 언제든 다시 먹고 싶을 때마다 먹을 수 있는데 이 것이 바로 클래스의 기초다.'
클래스는 객체지향에서 빠질 수 없는 개념입니다.
또한 우리는 자바스크립트는 프로토타입 기반 언어와 객체지향 언어라고 불린다는 것을 들어보았을 겁니다.
JS에는 클래스라는 개념은 없고 프로토타입이 존재합니다.
자바스크립트는 클래스 기반인가? X
클래스 문법이 추가된 것이다 O
자 그럼, 클래스가 없을 때는 어떻게 구현했었는지 봅시다.
Functional
const Person = function (name, age) { const person = {}; person.name = name; person.age = age; person.sayHi = function () { console.log(`Hi! my name is ${this.name}!`); }; return person; }; let person = Person("Peter", 18); person.sayHi();
어떤가요?
객체를 생성할 때마다 메서드도 함께 생성되어 메모리 관리가 비효율적입니다.
이러한 문제를 해결하기 위해 아래 Functional-shared 방식이 나왔습니다.
Functional-shared
const _extend = function (to, from) { Object.assign(to, from); }; const sharedMethods = { sayHi: function () { console.log(`Hi! my name is ${this.name}!`); }, }; const Student = function (name, age) { const student = {}; student.name = name; student.age = age; _extend(student, sharedMethods); return student; }; const student = Student("Peter", 18); student.sayHi(); //Hi! my name is Peter! //참조 함수의 값을 수정해도 인스턴스들에 적용되지 않는다 sharedMethods.sayHi = function () {}; student.sayHi(); //Hi! my name is Peter!
이렇게 공용으로 사용할 함수를 참조시킴으로써, 메모리를 과하게 소비하던 문제는 해결되었지만,
재할당시 객체의 메서드와 참조 함수의 메모리 주소가 달라지기 때문에 변경된 내용이 객체의 메서드에 적용이 되지 않는다는 문제가 있습니다.
여기서 잠깐. 왜 변경된 내용은 적용이 안될까요?
여기서부터는 얕은복사와 깊은복사를 알아야 합니다.
Object.assign은 얕은복사에 해당하여, 객체의 참조값(주소값)을 복사하기 때문에 그렇습니다.
(깊은 복사는 객체의 실제 값을 복사)
자바스크립트에는 원시값과 참조값이 존재
원시값은 변수의 메모리 공간에 실제 데이터 값 저장. 이 변수를 조작하려고 하면 실제 값이 조작됨.
참조값은 변수에 객체를 저장하면 독립적인 메모리 공간에 값을 저장하고, 변수에 저장된 메모리 공간의 참조(위치 값)를 저장함.
따라서 할당된 변수를 조작하는 것은 객체 자체를 조작하는 것이 아닌, 해당 객체의 참조를 조작하는 것.
(더 자세한 설명 :https://youngmin.hashnode.dev/js-book-corejs-01)
다시 돌아와서,
변경된 내용이 객체의 메서드에 적용이 되지 않는 문제는 어떻게 해결할 수 있을까요?
Prototypal
const Person = function (name, age) { const person = Object.create(personMethod); person.name = name; person.age = age; return person; }; const personMethod = { sayHi: function () { console.log(`Hi! my name is ${this.name}!`); }, }; let person = Person("Peter", 18); person.sayHi(); // Hi! my name is Peter! personMethod.sayHi = function () { console.log("changed"); }; person.sayHi(); // changed
Object.create() 메서드는 지정된 프로토타입 객체 및 속성(property)을 갖는 새 객체를 만듭니다.
위 코드에서 person은 personMethod를 프로토타입으로 삼는 객체입니다. 따라서 personMethod.sayHi의 값이 변경되더라도 person의 prototype은 여전히 personMethod이기 때문에 변경된 내용이 person에서도 적용됩니다.
더 간략화 할 순 없을까요?
const Person = function (name, age) { this.name = name; this.age = age; }; Person.prototype.sayHi = function () { console.log(`Hi! my name is ${this.name}!`); }; let person = new Person("Peter", 18); person.sayHi();
달라진 점은, Person 함수가 객체를 생성하지 않고 아무것도 return하지 않는다는 것입니다.
또한 인스턴스는 Person 생성자 함수 내부에서 생성되지 않고 new연산자를 통해 생성됩니다.
new연산자가 처리해주는 일을 코드로 작성하면 아래와 같습니다.
const Person = function (name, age) { let this = Object.create(프로토타입 객체) this.name = name; this.age = age; return this };
new Person('peter',18)이 실행되기 전, new 연산자가 Person의 prototype을 상속하는 새로운 객체를 생성합니다.
그 다음 이 객체를 this로 바인딩합니다.
new 연산자는 return이 없다면 암시적으로 this를 반환합니다.
아래는 new 연산자로 실행했을 때 자동적으로 동작하는 알고리즘 입니다.
function Person(name,age) { // this = {}; (빈 객체가 암시적으로 만들어짐) // 새로운 프로퍼티를 this에 추가함 this.name = name; this.age = age; // return this; (this가 암시적으로 반환됨) }
이러한 방식들로, 자바스크립트는 클래스를 비스무리하게 구현해왔습니다.
출처:
(https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/create)
https://medium.com/@bluesh55/javascript-prototype-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0-f8e67c286b67
https://youngmin.hashnode.dev/js-book-corejs-01
https://ko.javascript.info/constructor-new
https://roy-jung.github.io/161007_is-class-only-a-syntactic-sugar/
ES6 Class는 단지 prototype 상속의 문법설탕일 뿐인가?
최근 모 커뮤니티에서 ‘ES6를 공부해야 할 필요는 없다’는 의견을 발견하였는데, 그 분의 견해를 읽던 중 ‘Class는 문법설탕일 뿐’이라는 내용에 대해서 정말로 그러한지 알아보고 싶은 마음
roy-jung.github.io
new 연산자와 생성자 함수
ko.javascript.info
코어 자바스크립트 NOTE - 01. 데이터 타입
Chapter. 01 - 데이터 타입 (책 - 코어 자바스크립트를 읽고 정리합니다.)
youngmin.hashnode.dev
Object.create() - JavaScript | MDN
Object.create() 메서드는 지정된 프로토타입 객체 및 속성(property)을 갖는 새 객체를 만듭니다.
developer.mozilla.org
'Javascript' 카테고리의 다른 글
[JS] 바닐라 js로 useState를 만들어 보자 (0) 2025.03.23 [JS] 클래스 상속과 프로토타입 체이닝 (0) 2025.03.02 [JS] 콜백지옥에서 벗어나기 (5) 2024.06.02 NOW SOPT 자바스크립트 과제 중 타입이 string이었던 이슈 (3) 2024.05.12 [JS] 배열 메서드들의 올바른 역할 (3) 2024.05.05