JavaScript

lingodingo·2020년 5월 31일
0

frontend

목록 보기
4/5

1. 정의

JavaScript(JS)는 가벼운 인터프리터 또는 JIT 컴파일 프로그래밍 언어로, 일급 함수를 지원합니다. 웹 페이지의 스크립트 언어로서 제일 유명하지만 Node.js, Apache CouchDB, Adobe Acrobat처럼 많은 비 브라우저 환경에서도 사용하고 있습니다. JavaScript는 프로토타입 기반의 동적 다중 패러다임 스크립트 언어로, 객체지향형, 명령형, 선언형(함수형 프로그래밍 등) 스타일을 지원합니다. - MDN

2. JavaScript의 특징

1. JIT (Just-in-time) Compile

원래의 JavaScript 엔진들은 모두 실시간 인터프리팅을 하고 있었지만, 모질라에서 JIT 컴파일 엔진을 도입하고 나서 JS 성능을 20~40배 넘게 끌어올렸다.

JIT 컴파일러는 실행 시점에서 인터프리트 방식으로 기계어 코드를 생성하면서 그 코드를 캐싱하여, 같은 함수가 여러 번 불릴 때 매번 기계어 코드를 생성하는 것을 방지한다.

[여기]에서 JITC에 대해 더 자세히 알 수 있습니다.

2. 일급 함수

함수를 다른 변수와 동일하게 다루는 언어는 일급 함수를 가졌다고 표현합니다. 예를 들어, 일급 함수를 가진 언어에서는 함수를 다른 함수에 매개변수로 제공하거나, 함수가 함수를 반환할 수 있으며, 변수에도 할당할 수 있습니다. - MDN

const foo = function() {
   console.log("foobar");
}
// 변수를 사용해 호출
foo();

1. 고차함수

함수를 반환하는 함수를 고차 함수라고 부릅니다.

function sayHello() {
   return function() {
      console.log("Hello!");
   }
}
// 이 방법으로도 가능
const myFunc = sayHello();
myFunc();
// 이 방법으로도 가능
sayHello()();

3. Execution context

실행 컨텍스트를 이해하는 것은 자바스크립트가 왜 이렇게 동작하는지 알 수 있습니다.

1. Lexical Scope

WIP

2. Global context

WIP

3. Function context

WIP

4. Closure

1. 정의

클로저는 외부 함수의 변수에 접근할 수 있는 내부 함수입니다.

function init() { // 고차 함수
  var name = "Mozilla"; // name은 init에 의해 생성된 지역 변수이다.
  function displayName() { // displayName() 은 내부 함수이며, 클로저다.
    alert(name); // 부모 함수에서 선언된 변수를 사용한다.
  }
  displayName();
}
init();

위의 예제에서 JS가 아닌 프로그래밍 언어라면 displayName()에서는 변수 name을 쓰지 못한다. 만약 displayName()에서name 변수를 쓰고 싶다면 this.name을 사용하여야 한다.

function makeFunc() {
  var name = "Mozilla";
  function displayName() {
    alert(name);
  }
  return displayName;
}

var myFunc = makeFunc();
//myFunc변수에 displayName을 리턴함
//유효범위의 어휘적 환경을 유지
myFunc();
//리턴된 displayName 함수를 실행(name 변수에 접근)

이 코드는 바로 위의 예제와 완전히 동일한 결과가 실행된다. 하지만 흥미로운 차이는 displayName() 함수가 실행되기 전에 외부함수makeFunc()로부터 리턴되어 myFunc 변수에 저장된다는 것이다.

한 눈에 봐서는 이 코드가 여전히 작동하는 것이 직관적으로 보이지 않을 수 있다. 몇몇 프로그래밍 언어에서, 함수 안의 지역 변수들은 그 함수가 처리되는 동안에만 존재한다. makeFunc() 실행이 끝나면(displayName함수가 리턴되고 나면) name 변수에 더 이상 접근할 수 없게 될 것으로 예상하는 것이 일반적이다.

하지만 위의 예시와 자바스크립트의 경우는 다르다. 그 이유는 자바스크립트는 함수를 리턴하고, 리턴하는 함수가 클로저를 형성하기 때문이다. 클로저는 함수와 함수가 선언된 어휘적 환경의 조합이다. 이 환경은 클로저가 생성된 시점의 유효 범위 내에 있는 모든 지역 변수로 구성된다. 첫 번째 예시의 경우, myFunc은 makeFunc이 실행될 때 생성된 displayName 함수의 인스턴스에 대한 참조다. displayName의 인스턴스는 변수 name 이 있는 어휘적 환경에 대한 참조를 유지한다. 이런 이유로 myFunc가 호출될 때 변수 name은 사용할 수 있는 상태로 남게 되고 "Mozilla" 가 alert 에 전달된다.

2. 어디서 쓰이는데?

클로저는 어떤 데이터(어휘적 환경)와 그 데이터를 조작하는 함수를 연관시켜주기 때문에 유용하다. 이것은 객체가 어떤 데이터와(그 객체의 속성) 하나 혹은 그 이상의 메소드들을 연관시킨다는 점에서 객체지향 프로그래밍과 분명히 같은 맥락에 있다.
결론적으로 오직 하나의 메소드를 가지고 있는 객체를 일반적으로 사용하는 모든 곳에 클로저를 사용할 수 있다.

3. Private variables

JavaScript는 객체지향 언어이다. ES5에서는 prototype으로 객체를 다루어왔고, ES6부터는 Class가 추가되면서 사용하고 있다.

// ES5
function foo() {}
foo.prototype.bar = 3;

console.log( (new foo()).bar ); // 3

// ES6
class foo {
  constructor() {
    this.bar = 3;
  } 
}

console.log( (new foo()).bar ); // 3

문제는 이렇게 작성된 클래스들은 밖에서 언제든지 변경이 가능하다.

var poo = new Foo();
poo.bar = 'Who am I';
console.log(poo.bar); // 'Who am I?'

클래스의 특징 중 하나인 private field를 구현하기가 힘든데, 이를 Closure를 이용하여 구현할 수 있다.

function foo(name) {
  var _name = name;
  return function() {
    console.log(_name);
  };
}

var badFoo = new foo('foofoo');
badFoo.name = 31354; // ???
badFoo._name = 123123; // ???
badFoo(); // 'foofoo'

4. Callback

WIP...

5. Hoisting

1. 정의

함수선언문은 코드를 구현한 위치와 관계없이 자바스크립트의 특징인 호이스팅에 따라 브라우저가 자바스크립트를 해석할 때 맨 위로 끌어 올려진다.

규칙 1. 모든 변수 선언(할당 X)만이 끌어 올려진다.

function foo() {
  console.log(x);	// undefined <-- 에러 아닐까?
  var x = 30;		// 할당
  console.log(x);	// 30
}

이 코드는 자바스크립트가 다음과 같이 해석한다.

function foo() {
  var x;		// 선언(호이스팅)
  console.log(x); 	// 할당 안되었으니 undefined
  x = 30;		// 할당
  console.log(x);	// 30
}

규칙 2. 함수 선언문(할당 X)으로 된 함수도 가장 위로 끌어 올려진다.

foo();	// hello
function foo() {
  console.log('hello');
}

위의 코드도 자바스크립트가 다음과 같이 해석한다.

function foo() {
  console.log('hello'); 
}
foo();	// hello

그러나 다음과 같이 할당된 구문이라면 끌어 올려지지 않는다.

j();	// syntax error
var j = function foo() {
  console.log('hello');
};

이 코드는 다음과 같이 바뀌기 때문이다.

var j;	// '선언'만 끌어올려진다.
j();	// ?
j = function foo() {	// 할당은 이제서야
  console.log('hello');
};

2. 이거 왜 씀?

이 호이스팅이 생각보다 도움이 될 때가 많다. React에서 Component를 만들 때, 쓸 데 없는 초기화 작업을 밑에서 해주고 위에서 그냥 불러주는 형식으로 깔끔하게 작성하기가 가능해진다

const ComponentA: FC<> = () => {
  // initState함수를 바깥에도 선언하는 방법이 있지만,
  // 내부 변수를 이용해야하는 경우 바깥에 뺄려고 하면 파라미터가 길어진다.
  // 이건 사람마다 코딩 스타일이 다르므로 이런게 있다고만 알자
  const [state, setState] = useState(initState());
  
  function initState() {
   	return '초기 state 입니다 ^-^'; 
  }
  
  ...
};

3. Critical Rendering Path에서의 JavaScript

WIP

profile
Frontend developer

0개의 댓글