[JS] 자바스크립트의 클래스

baegyeong·2024년 8월 18일

Java Script

목록 보기
8/9
post-thumbnail

코어자바스크립트 ch7. 클래스를 읽고 정리한 내용입니다.


static

정적 메서드는 클래스의 인스턴스 없이 호출이 가능하다.

const StaticMethodCall = function () {}

StaticMethodCall.staticMethod = function () {
	return "정적 메서드";
}

console.log(StaticMethodCall.staticMethod()); // "정적 메서드"
class StaticMethodCall {
  static staticMethod() {
    return "정적 메서드";
  }
}

console.log(StaticMethodCall.staticMethod()); // "정적 메서드"

정적 메서드에서 정적 메서드에 접근 시, this 를 사용하여 접근할 수 있다.

하지만 비정적 메서드가 정적 메서드에 접근 시, 키워드 this를 써서는 직접적인 접근을 할 수 없다.

const StaticMethodCall = function () {}

StaticMethodCall.staticMethod = function () {
	return "정적 메서드";
}

StaticMethodCall.prototype.anotherMethod = function () {
	return this.staticMethod() + "또다른 메서드 호출" // this.staticMethod is not a function
}

const example = new StaticMethodCall()
console.log(example.anotherMethod()) // // this.staticMethod is not a function
  • es6 클래스
    class StaticMethodCall {
      static staticMethod() {
        return "정적 메서드";
      }
      
      anotherMethod(){
    	  return this.staticMethod() + "또다른 메서드 호출" // this.staticMethod is not a function
    	}
    }
    
    const example = new StaticMethodCall()
    console.log(example.anotherMethod()) // this.staticMethod is not a function
  • this 키워드는 메서드가 호출될 객체에 바인딩된다.
  • 정적 메서드는 클래스의 생성자 내부에 저장된다. 클래스의 프로토타입 내부에 저장되지 않으므로 바인딩된 객체가 접근할 수 없다.
  • 즉, 클래스에 직접 속하기 때문에 클래스 이름을 통해서만 접근할 수 있다.
  • 따라서 객체에 바인딩 되서 실행될 필요가 없는 메서드에 한해서 정적 메서드를 활용할 수 있겠다.

정적 메서드 활용 예시

정의하려는 메서드가 인스턴스가 아닌 클래스와 관계를 맺을 수 있다면 정적으로 선언한다.

class User {
  constructor(firstName, lastName, id) {
      this.firstName = firstName,
      this.lastName = lastName,
      this.id = id
	}
	
	static delete({ id }) {
	  // 사용자 제거
	}
}

User.delete(user1);

static property

데이터를 클래스 수준에서 저장하고자 할 때 사용한다.

const Chat = function () {}

Chat.messgae = "Have a great day!"

console.log(Chat.messgae) // "Have a great day!" 
class Chat {
	static message = "Have a great day!";
}

console.log(Chat.message) // "Have a great day!"

정적 메서드의 메모리 할당

  • static 메서드는 클래스에 속하므로, static 메서드의 메모리는 한 번만 할당된다.
  • 프로그램이 종료될 때까지 garbage collector가 수거하지 않는다.
    • static으로 할당된 영역이 크다면 GC의 효율이 떨어진다.

클래스가 구체적인 데이터를 지니지 않게 하기

var Grade = function () {
  var args = Array.prototype.slice.call(arguments);
  for (var i = 0; i < args.length; i++) {
    this[i] = args[i];
  }
  this.length = args.length;
};

Grade.prototype = [];
var g = new Grade(100, 80);

클래스에 있는 값이 인스턴스의 동작에 영향을 준다.

  • Grade.prototype에 어떤 배열을 연결하느냐에 따라 인스턴스의 동작에 영향을 준다.

즉, 클래스가 구체적인 데이터를 지니지 않게 해야한다.

sol) 클래스 구현 후 프로퍼티들을 일일이 지우고 더는 새로운 프로퍼티를 추가하지 않게 한다.

var extendClass1 = function (SuperClass, SubClass, subMethods) {
  SubClass.prototype = new SuperClass();
  for (var prop in SubClass.prototype) {
    if (SubClass.prototype.hasOwnProperty(prop)) {
      delete SubClass.prototype[prop];
    }
  }

  if (subMethods) {
    for (var method in subMethods) {
      SubClass.prototype[method] = subMethods[method];
    }
  }

  Object.freeze(SubClass.prototype);
  return SubClass;
};
var Grade = function () {
  var args = Array.prototype.slice.call(arguments);
  for (var i = 0; i < args.length; i++) {
    this[i] = args[i];
  }
  this.length = args.length;
};

var g = extendClass1(Grade, function () {
    Grade.apply(this, arguments);
});

var myGrade = new g(100, 80);
console.log(myGrade); // {0: 100, 1: 80, length: 2}
  • Grade의 프로퍼티를 모두 제거하고, 동결함으로써 클래스가 구체적인 데이터를 지니지 않게 막았다.

    새로운 데이터를 할당하려고 하면 할당되지 않는다.

  • 하지만 이 코드는 기존에 가능했던 push 마저 되지 않는다.

    • Grade의 메서드로 push가 없으며, __proto__로 접근을 한다고 해도 상위에 Array를 상속받고 있지 않기 때문에 push를 호출하면 에러가 발생한다.
  • 그러나 length의 삭제는 가능하다.

    • Object.freeze를 했으니 삭제가 되면 안되지 않나?
    • g의 프로토타입을 동결시켰으니, g로 생성된 인스턴스는 객체는 동결되지 않았다.
  • 인스턴스 객체의 프로퍼티도 동결하려면

    var g = extendClass1(Grade, function () {
        Grade.apply(this, arguments);
        **Object.freeze(this);**
    });

Object.create와 new

Object.create

지정된 프로토타입 객체 및 속성을 갖는 새 객체를 만든다.

new보다 프로토타입을 명시적으로 지정하는 데 특화되어 있는 느낌을 받았다.

Object.create(proto[, propertiesObject])
  • proto: 프로토타입 객체
  • propertiesObject: 속성 설명자 지정
var person = {
    greeting: function() {
        return "Hello, " + this.name;
    }
};

var john = Object.create(person, {
    name: {
        value: "John",
        writable: true,
        enumerable: true,
        configurable: true
    },
    age: {
        value: 30,
        writable: false,
        enumerable: true,
        configurable: false
    },
    email: {
        get: function() {
            return this._email;
        },
        set: function(value) {
              this._email = value;
        },
        enumerable: true,
        configurable: true
    }
});

console.log(john.name);  // John
console.log(john.greeting());  // Hello, John
john.age = 31;  // 변경 X
console.log(john.age);  // 30
john.email = "john@example.com";
console.log(john.email);  // john@example.com

new

사용자 정의 객체 타입 또는 내장 객체 타입의 인스턴스를 생성한다.

생성자 함수의 prototype 속성이 새 객체의 프로토타입이 된다.

생성자 함수의 호출이 필요하다.

Object.create() vs new

// Object.create 사용
var proto = {
  greet: function () {
    console.log("Hello!");
  },
};

var obj1 = Object.create(proto);
obj1.greet(); // "Hello!"
// new 키워드 사용
function Constructor() {
  this.name = "John";
}

Constructor.prototype.greet = function () {
  console.log("Hello, " + this.name + "!");
};

var obj2 = new Constructor();
obj2.greet(); // "Hello, John!"

Object.create()는 생성자를 호출하려면 별도로 설정이 필요하다.

0개의 댓글