super
Baseline Widely available
This feature is well established and works across many devices and browser versions. It’s been available across browsers since March 2016.
super
키워드는 객체 리터럴 또는 ���래스의 [[Prototype]] 속성에 접근하거나 슈퍼클래스의 생성자를 호출하는 데 사용됩니다.
super.prop
와 super[expr]
표현식은 클래스와 객체 리터럴의 메서드 정의에서 모두 사용할 수 있습니다. super(...args)
표현식은 클래스 생성자에서 유효합니다.
시도해 보기
class Foo {
constructor(name) {
this.name = name;
}
getNameSeparator() {
return "-";
}
}
class FooBar extends Foo {
constructor(name, index) {
super(name);
this.index = index;
}
// Does not get called
getNameSeparator() {
return "/";
}
getFullName() {
return this.name + super.getNameSeparator() + this.index;
}
}
const firstFooBar = new FooBar("foo", 1);
console.log(firstFooBar.name);
// Expected output: "foo"
console.log(firstFooBar.getFullName());
// Expected output: "foo-1"
구문
super([arguments]) // 부모 생성자 호출.
super.propertyOnParent
super[expression]
설명
super
키워드는 "함수 호출"(super(...args)
) 또는 "속성 조회"(super.prop
와 super[expr]
)의 두 가지 방법으로 사용할 수 있습니다.
참고:
super
는 키워드이며 특수한 구문 구조입니다.super
는 프로토타입 객체를 가리키는 변수가 아닙니다.super
자체를 읽으려는 시도는SyntaxError
입니다.jsconst child = { myParent() { console.log(super); // SyntaxError: 'super' keyword unexpected here }, };
파생 클래스(extends
를 사용)의 생성자 본문에서 super
키워드는 "함수 호출"(super(...args)
)로 나타날 수 있으며 this
키워드가 사용되기 전과 생성자가 반환되기 전에 호출되어야 합니다. 부모 클래스의 생성자를 호출하고 부모 클래스의 퍼블릭 필드를 바인딩한 후 파생 클래스의 생성자는 this
를 추가로 접근하고 수정할 수 있습니다.
"속성 조회" 형식은 객체 리터럴 또는 클래스의 [[Prototype]] 메서드와 속성에 접근하는 데 사용할 수 있습니다. 클래스 본문 내에서 super
의 참조는 실행 맥락이 인스턴스 생성인지 클래스 초기화인지에 따라 슈퍼클래스의 생성자 자체 이거나 생성자의 prototype
이 될 수 있습니다. 자세한 내용은 예제 구획을 참조하세요.
super
의 참조는 메서드가 호출된 객체가 아니라 super
가 선언된 클래스 또는 객체 리터럴에 의해 결정됩니다. 따라서 메서드를 바인딩 해제하거나 다시 바인딩해도 메서드의 super
참조는 변경되지 않습니다.(this
의 참조는 변경되지만요.) 메서드가 클로저를 생성하는 클래스 또는 객체 리터럴 범위의 변수로 super
를 볼 수 있습니다. (그러나 위에서 설명한 것처럼 실제로는 변수가 아니라는 점에 유의하세요.)
super
를 통해 속성을 설정할 때, 속성은 this
에 대신 설정됩니다.
예제
클래스에서 super 사용하기
이 코드 스니펫은 클래스 샘플 (라이브 데모)에서 가져왔습니다. 여기서 super()
는 Rectangle
과 Square
사이에 공통적인 생성자 부분의 중복을 피하기 위해 호출됩니다.
class Rectangle {
constructor(height, width) {
this.name = "Rectangle";
this.height = height;
this.width = width;
}
sayName() {
console.log(`Hi, I am a ${this.name}.`);
}
get area() {
return this.height * this.width;
}
set area(value) {
this._area = value;
}
}
class Square extends Rectangle {
constructor(length) {
this.height; // ReferenceError, super가 먼저 호출되어야 합니다!
// 여기서 Rectangle의 너비와 높이에 대해 제공된
// length를 사용하여 부모 클래스의 생성자를 호출합니다.
super(length, length);
// 참고: 파생 클래스에서 'this'를 사용하려면
// 먼저 super()를 호출해야 합니다. 이를 생략하면 참조 오류가 발생합니다.
this.name = "Square";
}
}
super를 호출하는 정적 메서드
정적 메서드에서도 super를 호출할 수 있습니다.
class Rectangle {
static logNbSides() {
return "I have 4 sides";
}
}
class Square extends Rectangle {
static logDescription() {
return `${super.logNbSides()} which are all equal`;
}
}
Square.logDescription(); // 'I have 4 sides which are all equal'
클래스 필드 선언에서 super 접근
super
는 클래스 필드 초기화 중에도 접근할 수 있습니다. super
의 참조는 현재 필드가 인스턴스 필드인지 정적 필드인지에 따라 다릅니다.
class Base {
static baseStaticField = 90;
baseMethod() {
return 10;
}
}
class Extended extends Base {
extendedField = super.baseMethod(); // 10
static extendedStaticField = super.baseStaticField; // 90
}
인스턴스 필드는 생성자의 prototype
대신 인스턴스에 설정되므로 super
를 사용하여 슈퍼클래스의 인스턴스 필드에 접근할 수 없습니다.
class Base {
baseField = 10;
}
class Extended extends Base {
extendedField = super.baseField; // undefined
}
여기서 baseField
는 Base.prototype
이 아니라 Base
인스턴스의 자체 속성으로 정의되기 때문에 10이 아닌 undefined
입니다. 이 맥락에서 super
는 Extended.prototype
의 [[Prototype]]이므로 Base.prototype
의 속성만 조회할 수 있습니다.
super 속성을 삭제하면 오류가 발생합니다
delete
연산자와 super.prop
또는 super[expr]
를 사용하여 부모 클래스의 속성을 삭제할 수 없습니다. 삭제하면 ReferenceError
가 발생합니다.
class Base {
foo() {}
}
class Derived extends Base {
delete() {
delete super.foo; // 이렇게 하면 안됩니다.
}
}
new Derived().delete(); // ReferenceError: invalid delete involving 'super'.
객체 리터럴에서 super.prop 사용
super는 객체 초기자 표기법에서도 사용할 수 있습니다. 이 예제는 두 객체가 메서드 하나를 정의합니다. 두 번째 객체에서 super
는 첫 번째 객체의 메서드를 호출합니다. 이는 obj2
의 프로토타입을 obj1
로 설정할 수 있는 Object.setPrototypeOf()
의 도움으로 작동하므로 super
는 obj1
에서 method1
을 찾을 수 있습니다.
const obj1 = {
method1() {
console.log("method 1");
},
};
const obj2 = {
method2() {
super.method1();
},
};
Object.setPrototypeOf(obj2, obj1);
obj2.method2(); // "method 1"이 로그됩니다.
super.prop을 읽는 메서드는 다른 객체에 바인딩될 때 다르게 동작하지 않습니다
super.x
에 접근하는 것은 Reflect.get(Object.getPrototypeOf(objectLiteral), "x", this)
와 같이 동작합니다. 즉, 속성은 항상 객체 리터럴/클래스 선언의 프로토타입에서 검색되고 메서드를 바인딩 해제하고 다시 바인딩해도 super
의 참조는 변경되지 않습니다.
class Base {
baseGetX() {
return 1;
}
}
class Extended extends Base {
getX() {
return super.baseGetX();
}
}
const e = new Extended();
console.log(e.getX()); // 1
const { getX } = e;
console.log(getX()); // 1
객체 리터럴에서도 동일하게 동작합니다.
const parent1 = { prop: 1 };
const parent2 = { prop: 2 };
const child = {
myParent() {
console.log(super.prop);
},
};
Object.setPrototypeOf(child, parent1);
child.myParent(); // "1"이 로그됩니다.
const myParent = child.myParent;
myParent(); // 여전히 "1"이 로그됩니다.
const anotherChild = { __proto__: parent2, myParent };
anotherChild.myParent(); // 여전히 "1"이 로그됩니다.
전체 상속 체인을 재설정해야만 super
의 참조가 변경됩니다.
class Base {
baseGetX() {
return 1;
}
static staticBaseGetX() {
return 3;
}
}
class AnotherBase {
baseGetX() {
return 2;
}
static staticBaseGetX() {
return 4;
}
}
class Extended extends Base {
getX() {
return super.baseGetX();
}
static staticGetX() {
return super.staticBaseGetX();
}
}
const e = new Extended();
// 인스턴스 상속 재설정
Object.setPrototypeOf(Extended.prototype, AnotherBase.prototype);
console.log(e.getX()); // 프로토타입 체인이 변경되었기 때문에 "1" 대신 "2"가 로그됩니다.
console.log(Extended.staticGetX()); // 정적 부분을 아직 수정하지 않았기 때문에, 여전히 "3"이 로그됩니다.
// 정적 상속 재설정
Object.setPrototypeOf(Extended, AnotherBase);
console.log(Extended.staticGetX()); // 이제 "4"가 로그됩니다.
super에서 메서드 호출
super.prop
을 함수로 호출할 때 prop
함수 내부의 this
값은 super
가 가리키는 객체가 아니라 현재 this
입니다. 예를 들어, super.getName()
호출은 코드가 Base.getName()
과 동일한 것처럼 보이지만 "Extended"
를 로그합니다.
class Base {
static getName() {
console.log(this.name);
}
}
class Extended extends Base {
static getName() {
super.getName();
}
}
Extended.getName(); // "Extended" 로그
이는 정적 프라이빗 속성과 상호 작용할 때 특히 중요합니다.
super.prop을 설정하면 this 속성이 대신 설정됩니다
super.x = 1
과 같은 super
의 속성을 설정하는 것은 Reflect.set(Object.getPrototypeOf(objectLiteral), "x", 1, this)
와 같이 동작합니다. 이는 super
를 단순히 "프로토타입 객체의 참조"로 이해하는 것에 ��계가 있는 이유 중 하나입니다. 실제로는 this
에 대한 속성을 설정하기 때문이죠.
class A {}
class B extends A {
setX() {
super.x = 1;
}
}
const b = new B();
b.setX();
console.log(b); // B { x: 1 }
console.log(Object.hasOwn(b, "x")); // true
super.x = 1
은 A.prototype
에서 x
의 속성 설명자를 찾습니다(그리고 거기에 정의된 setter를 호출하죠.). 하지만 this
값은 이 맥락에서 b
로 설정됩니다. target
과 receiver
가 다른 경우에 대한 자세한 내용은 Reflect.set
을 참조하세요.
즉, super.prop
를 get하는 메서드는 일반적으로 이 맥락의 변경에 영향을 받지 않지만 super.prop
를 set하는 메서드는 영향을 받을 수 있습니다.
/* 위와 동일한 선언 재사용 */
const b2 = new B();
b2.setX.call(null); // TypeError: Cannot assign to read only property 'x' of object 'null'
그러나 super.x = 1
은 여전히 프로토타입 객체의 속성 설명자를 참조하므로, 쓸 수 없는 속성을 다시 작성할 수 없으며 setter가 호출됩니다.
class X {
constructor() {
// 쓸 수 없는 속성 생성
Object.defineProperty(this, "prop", {
configurable: true,
writable: false,
value: 1,
});
}
}
class Y extends X {
constructor() {
super();
}
foo() {
super.prop = 2; // 값을 덮어쓸 수 없습니다.
}
}
const y = new Y();
y.foo(); // TypeError: "prop" is read-only
console.log(y.prop); // 1
명세서
Specification |
---|
ECMAScript® 2026 Language Specification # sec-super-keyword |