class-properties 클래스 필드

차유림·2021년 11월 18일
0

// 과거
class Counter extends Component {
  constructor(props) {
    super(props);
    this.state = {
      counter: 0
    };
  }
  ...
}
  
// 요즘
class Counter extends Component {
  state = {
    counter: 0
  };  
  ...
}

리액트 클래스형 컴포넌트를 사용할 때,
예전에는 constructor 내부에서 this.state를 설정해야 했는데
요즘은 constructor 없이 바로 state를 사용할 수 있는 이유가
class-properties 문법 덕분이었다.

class-properties는 mdn에서 Class fields와 같은데
JS에서는 아직 표준은 아니고 실험적단계(stage3)이다.

CRA에서는 babel을 사용해서 class-properties 문법을 지원하기 때문에
리액트에서 바로 사용할 수 있었던 것이다.

babel 문서를 살펴보자.

class Bork {
  //Property initializer syntax
  instanceProperty = "bork";
  boundFunction = () => {
    return this.instanceProperty;
  };

  //Static class properties
  static staticProperty = "babelIsCool";
  static staticFunction = function() {
    return Bork.staticProperty;
  };
}

let myBork = new Bork();

//Property initializers are not on the prototype.
console.log(myBork.__proto__.boundFunction); // > undefined

//Bound functions are bound to the class instance.
console.log(myBork.boundFunction.call(undefined)); // > "bork"

//Static function exists on the class.
console.log(Bork.staticFunction()); // > "babelIsCool"

위에서 class 내부에 바로 선언한 프로퍼티의 경우,
인스턴스 객체 myBork의 인스턴스 프로퍼티가 된다!

이전 글에서처럼 프로토타입을 그려보자면 다음과 같다.
(프로토타입 프로퍼티와 헷갈렸는데
class 내부에서 바로 선언한 프로퍼티 = 인스턴스 프로퍼티
static 프로퍼티 = 정적 프로퍼티
Bork.prototype.- 으로 작성해줘야 프로토타입 프로퍼티이다.)

프로토타입체인

이때, babel이 컴파일 하는 두가지 방법이 있는데
{ "setPublicClassFields": true } 라면 assignment표현식
아니라면 Object.defineProperty을 사용한다.


// assignment expressions 사용
var Bork = function Bork() {...};
Bork.a = "foo";

// Object.defineProperty 사용
Object.defineProperty(Bork, "a", {
  configurable: true,
  enumerable: true,
  writable: true,
  value: "foo",
});

삽질

class Bork {
  //Property initializer syntax
  instanceProperty = "bork";
  boundFunction = () => {
    return this.instanceProperty;
  };

  //Static class properties
  static staticProperty = "babelIsCool";
  static staticFunction = function() {
    return Bork.staticProperty;
  };
}

let myBork = new Bork();

//Property initializers are not on the prototype.
// 프로토타입 메서드라, 인스턴스 메서드이다!!!
console.log(myBork.__proto__.boundFunction); // > undefined

//Bound functions are bound to the class instance.
console.log(myBork.boundFunction.call(undefined)); // > "bork"

//Static function exists on the class.
console.log(Bork.staticFunction()); // > "babelIsCool"

myBork.boundFunction.call(undefined)
에서 왜 call(undefined)를 하는지 이해가 안가서
명세랑, mdn을 찾아보았다.

우선 ecmascript 명세 보기

call 명세

NOTE2 에서 화살표함수인 경우 thisArg는 step4에서 무시된다고 나와있다.

맞다. 화살표함수(mdn)는 this바인딩이 없어
call, apply, bind method를 사용할 수 없었다(효과x).
화살표함수에서 this를 사용하면 렉시컬스코프의 this가 사용될 뿐..
call, apply 사용할 경우 this는 무시되고
인자만 전달할 수 있다.

예시에서 call(undefined)를 한 이유는,
this가 myBork 인스턴스에 바인딩되어있는걸 보여주기 위해서였다.

profile
🎨프론트엔드 개발자💻

0개의 댓글