boostcourse 생활코딩: 자바스크립트의 시작


  • class에 필요한 메서드가 있는데 추가할 수 없는 경우(다른 사람의 코드, 라이브러리 등)

  • class 자체에 추가하면서 무겁게 되길 원치 않는 경우

  • 모든 요소를 받을 클래스를 extends class명 을 통해서 부모 클래스로 두고 상속

class Person { constructor(name, first, second) { this.name = name; this.first = first; this.second = second; } sum() { return "class method > " + this.name + " : " + (this.first + this.second); } } class PersonPlus extends Person { avg() { return (this.first + this.second) / 2; } } var kim = new PersonPlus("kim", 10, 20); console.log("kim.sum()", kim.sum()); console.log("kim.avg()", kim.avg());
  • avg() 메서드를 Person 클래스 자체에 넣지 않고, Person 클래스를 부모 클래스로 하여 상속받는 PersonPlus 클래스에 메서드를 새로 만들었다.
  • 부모 클래스의 요소인 name, first, second 등을 모두 받아온다.
  • 부모 클래스의 메서드도 사용 가능하고 자식 클래스의 메서드도 사용 가능하다.
  • 부모 클래스에 이미 있는 메서드가 마음에 들지 않는다면 자식 클래스에서 바꾸어도 된다.

  • 부모 클래스의 요소를 불러 가져오고, 부모 클래스에서 하지 못하는 것들을 자식에서 할 수 있도록 하는 것
class Person { constructor(name, first, second) { this.name = name; this.first = first; this.second = second; } sum() { return this.first + this.second; } } class PersonPlus extends Person { constructor(name, first, second, third) { super(name, first, second); this.third = third; // 자식 클래스에서만 추가되는 것 } sum() { return super.sum() + this.third; } avg() { return (super.sum() + this.third) / 3; } } var kim = new PersonPlus("kim", 10, 20, 30); console.log("kim.sum()", kim.sum()); console.log("kim.avg()", kim.avg());
  • super(param1, param2,...) : 부모 클래스의 생성자 호출, 자식 클래스에 super()로 가져올 수 있다.
  • 생성자 vs 생성자 이므로 자식 생성자 이전에 부모 생성자를 가져올 수 있다.
  • super.~~~ : 부모 클래스의 메서드 호출
  • super을 이용해 간단하게 상속 클래스에서 수정 가능

  • 일반적인 프로그래밍 언어에서 상속은 클래스끼리만 되고 인스턴스끼리는 상속이 되지 않는다.
  • 자바스크립트는 너무 유연한 언어라 super object로부터 sub object가 기능을 상속받을 수 있다.
  • 심지어 super object를 상속하고 있다가 다른 객체에게 상속받을 필요가 있다면 prototype link만 다른 객체로 바꿔주면 된다.
  • 이 prototype link는 별도의 지정이 없으면 super object와 연결되어 있는 것.
  • super와 상관 없이 prototype link로 연결되어 있는 객체를 prototype object라고 부른다.

  • class를 사용하지 않고 __proto__를 사용해 상속한다.
  • 클래스와 클래스가 아닌, 객체가 객체를 상속하도록 하는 것이다.

var superObj = { superVal: "super" }; var subObj = { subVal: "sub" }; subObj.__proto__ = superObj; console.log("subObj.subVal =>", subObj.subVal); console.log("subObj.superVal =>", subObj.superVal); // subObj.subVal => sub // subObj.superVal => super
  • subObj에는 없는 superVal key를 이용해 super를 출력한다.
  • subObj.__proto__ = superObj;를 통해 인스턴스 상속을 한 것!
  • 우선 subObj에 superVal을 찾아보고 인스턴스 내에 이게 없으면 __proto__ 연결한 인스턴스에 있는지 확인

subObj.superVal = "sub"; console.log("superObj.superVal =>", superObj.superVal); // superObj.superVal => super
  • subObj의 superVal 프로퍼티를 바꾸더라도, 객체의 proto의 프로퍼티가 바뀌지는 않는다.

  • prototype
    • constructor 안이 아닌 밖에서 Method를 지정할 수 있다.
    • 모든 객체들이 프로토타입을 함께 쓸 수 있게 한다.
  • __proto__ : 객체가 객체를 상속하도록 한다.

  • 객체가 객체를 상속받기 위해서 위에서는 __proto__를 사용하였다.
// __proto__ 사용 var superObj = { superVal: "super" }; var subObj = { subVal: "sub" }; subObj.__proto__ = superObj;

그런데 Object.create()를 이용해 부모 객체로부터 자식 객체를 만들 수 있다.

// Object.create() 사용 var superObj = { superVal: "super" }; var subObj = Object.create(superObj); subObj.subcal = "sub";

  • 모든 함수는 call이라는 메서드를 가진다.
  • 모든 함수는 객체이기 때문
  • 객체와 연결해 객체의 속성을 이용해 함수 동작을 할 수 있다. (this가 객체가 됨)
  • 일시적으로 객체를 연결해 함수를 호출할 때 객체의 속성을 사용한다.
var kim = { name: "kim", first: 10, second: 20, }; var lee = { name: "lee", first: 10, second: 10, }; // 어느 객체에 속하지 않고 외부에 있는 함수 function sum() { return this.first + this.second; } // sum이라고 하는 객체를 실행한다는 의미( = sum(); ) sum.call(kim);

이렇게 call() 내부에 인자로 kim을 주게 되면, this는 kim이 되는 것이다.


// sum이라고 하는 객체를 실행한다는 의미( = sum(); ) console.log("sum.call(kim)", sum.call(kim)); console.log("sum.call(lee)", sum.call(lee)); // sum.call(kim) 30 // sum.call(lee) 20

sum() 함수가 sum(prefix)처럼 인자를 가지고 어떤 객체의 프로퍼티를 사용한다고 가정해보자.

function sum(prefix) { return prefix + (this.first + this.second); } // sum이라고 하는 객체를 실행한다는 의미( = sum(); ) console.log("sum.call(kim)", sum.call(kim, " => ")); console.log("sum.call(lee)", sum.call(lee, " : ")); // sum.call(kim) => 30 // sum.call(lee) : 20

위에처럼 함수가 어떤 객체를 참조하는지 먼저 괄호에 쓰고, 뒤에 parameter를 추가한다.


  • call()은 함수에 사용할 객체를 매번 지정해줘야 한다.
  • bind()는 함수가 인자를 참조하여 this로 고정하는 새로운 함수를 만드는 것
// 내부적으로 this를 kim으로 하는 새로운 함수 생성 var kimSum = sum.bind(kim, "-> "); console.log("kimSum()", kimSum()); // kimSum() -> 30

kimSum()은 sum의 this를 kim으로 영구적으로 고정한 아예 새로운 함수이다.


  • 함수는 객체여서 메서드를 가질 수 있다.
  • 함수 객체가 만들어지면 prototype 객체도 같이 만들어진다.
  • 함수 객체와 prototype 객체는 연관이 되어있다.
    • 함수의 prototype 프로퍼티는 prototype 객체를 가리킴
    • prototype 객체의 constructor 프로퍼티는 함수 객체를 가리킴
    • 즉 서로 상호참조를 하고 있는 관계
function Person(name, first, second) { this.name = name; this.first = first; this.second = second; } // Person 함수 객체의 프로토타입 객체에 sum 함수를 생성 및 정의 Person.prototype.sum = function () {}; // 객체 kim 생성 var kim = new Person("kim", 10, 20);
  • 객체 kim을 생성하면 parameter로 전달해준 값이 내부에서 정의됨

  • __proto__ 프로퍼티가 kim 객체 내부에 생김

  • 이는 인스턴스를 만든 클래스의 prototype 프로퍼티를 가리킨다.

  • 결국 Person's prototype 객체를 가리키는 것

  • 인스턴스 외부에서 인스턴스의 프로퍼티를 검색(kim.name)할 때

    • 인스턴스 내부에 해당 프로퍼티가 있으면 반환
    • 없으면 __proto__가 가리키는, 즉 Person's prototype 객체 내에 있는지 확인
  • kim.sum()은 kim 인스턴스 내에 없다.

  • __proto__인 Person's prototype 객체의 sum() 메서드를 불러온다.


  • JS 코드에 debugger;를 입력하고 브라우저에 렌더링하면, 해당 부분까지 코드를 진행한 뒤 일시정지된다.
  • 크롬 브라우저의 개발자도구에서 객체의 상태를 자세히 확인할 수 있다.
  • [Sources - Watch]에 객체명을 검색해 상세 내용을 확인하면 된다.