관리 메뉴

Silver Library (Archived)

백준 1330번 JS - closure, node.js template? 본문

CS Library/JavaScript - Data Structure

백준 1330번 JS - closure, node.js template?

Chesed Kim 2021. 7. 19. 17:33
반응형

Q.

두 정수 A와 B가 주어졌을 때, A와 B를 비교하는 프로그램을 작성하시오.

 

Condition.

첫째 줄에 A와 B가 주어진다. A와 B는 공백 한 칸으로 구분되어져 있다.

 

첫째 줄에 다음 세 가지 중 하나를 출력한다.

  • A가 B보다 큰 경우에는 '>'를 출력한다.
  • A가 B보다 작은 경우에는 '<'를 출력한다.
  • A와 B가 같은 경우에는 '=='를 출력한다.

 

Ans.

const fs = require("fs")
const inputData = fs.readFileSync("/dev/stdin").toString().split(" ").map(val=>+val)
const [a,b] = inputData

if (a > b){
    console.log(">")
}
else if (a < b){
    console.log("<")
}
else {
    console.log("==")
}

 

공략.

const fs = require("fs") 까지는 초기화 하는 const 변수로 이해가 가능하다.

다만 inputData 이후 부터, fs.readFileSync 는 처음보는 메소드다.

 

우선 fs 부터 알아볼 필요가 있어보인다. 하지만 fs 도 딱히 유추되는게 없다. 뭘까?

https://balmostory.tistory.com/33

결론만 말하자면, node.js 에서 제공하는 filesystem 이라고 한다.

용도는 : 파일을 불러오는 등의 기능 제공.

 

이는 https://3dmpengines.tistory.com/1855 를 참고해보니,

readFileSync 는 '동기'(정말 동기화의 그것 인가)

readFile 만 있으면 '비동기' 이다.

 

이건 콜백 함수, 그리고 특정 파일을 먼저 읽고 진행시키려면 동기적인 readFileSync 를.

그게 아니면 readFile 로 진행해서 참조하라는 의미로 보여진다.

 

node.js 에서 컴파일을 다음과 같이 소개하고 있다고 한다.

var fs = require('fs');
var input = fs.readFileSync('/dev/stdin').toString().split(' ');
var a = parseInt(input[0]);
var b = parseInt(input[1]);
console.log(a+b);

 

만약 공백으로 구분된 값들이, 여러줄로 들어온다면 아래와 같이 표현한다.

var fs = require('fs');
var input = fs.readFileSync('/dev/stdin').toString().split('\n');
 
var line0 = input[0].split(' ');
var line1 = input[1].split(' ');
var line2 = input[2].split(' ');
...

하지만 이 경우에는, 불편하다고 한다.

생각해보면 맞는 말인게, 일일히 배열에 참조(접근)를 하고 있다.

 

input 인덱스 고려 없이, 들어오는 순서대로 바로바로 실행되게 하는 방법이 있다고 한다.

JS의 closure 를 적극 활용하면 다음과 같은 표현식이 가능하다.

 

const fs = require('fs');
const stdin = fs.readFileSync('/dev/stdin').toString().split('\n');
 
function makeInput(){
    let line = 0;
 
    return function(){
        return stdin[line++];
    };
};
 
const input = makeInput();

문제의 해답에 나온 그 코드다!

'이렇게 return 된 function은, 이제 실행 할 때 마다 stdin 을 한 줄씩 return 한다.' 이다.

 

여기서 ES6 의 arrow function 기법을 사용하면, 다음과 같다.

const fs = require('fs');
const stdin = fs.readFileSync('/dev/stdin').toString().split('\n');
 
const input = (() => {
    let line = 0;
    return () => stdin[line++];
})();

예상하다 시피, arrow function 의 유일한 장점은 '간편함' 과 '축소' 다.

 

보너스.

const stdin = fs.readFileSync('/dev/stdin').toString().split('\n'); 의 경우, 일단 node.js 에서 사용되는 빌트인의 무언가 라는 것 만큼은 확실히 알겠는데, 그래서 저건 언제 쓰고, 왜 쓰지? 이다.

 

<불확실!>

현 시점에서 내릴 수 있는 판단은, 저 stdin 이 핵심이고, readFileSync 가 동기적으로 하나하나 stdin 을 호출 하는 식으로 실행 하여 return 을 하도록 하는 것이, 주된 목적으로 보여진다. 뒤의 toString 이나 split은, 문자 그대로의 목적으로 사료된다.

 

우선, "클로저(closure)를 이용해 특정 함수 내에서만 접근할 수 있는 변수를 만들고, 그 값을 input의 인덱스로 이용." 에서 영감을 얻었다고 했으니, 이 closure 에 대해 한번 읽어봐야 겠다.

 

Accoridng to MDN...

클로저는 함수와 함수가 선언된 어휘적 환경의 조합이다. 클로저를 이해하려면 자바스크립트가 어떻게 변수의 유효범위를 지정하는지(Lexical scoping)를 먼저 이해해야 한다.

 

역시, 렉시컬 스코핑이 나왔다.

즉, closure 는 Lexical environment 와 밀접한 관계가 있다고 볼 수 있을 것 같다.

이건 스코핑의 개념 일부 중 하나로 보여진다.

만약 헷깔려서 돌아왔다면, 이 부분은 시원하게 링크로 보고 가는 것이 좋겠다.

 

아래의 코드블록이 그 예시인데, makeFunc 가 myFunc 변수에(다가)서

displayName 을 return 하는 것이 closure 예시의 핵심으로 보여진다.

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

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

 

그외 단어:

구조 분해 할당 (Destructuring assignment)

 

참조:

https://degurii.tistory.com/108

https://helicopter55.tistory.com/47

'CS Library > JavaScript - Data Structure' 카테고리의 다른 글

백준 2753번 - JS  (0) 2021.07.20
9498 번 JS, 풀어보자.  (0) 2021.07.19
백준 JS 소스코드 템플릿 겸 - 2588 곱셈  (0) 2021.07.19
class in JS  (0) 2021.07.18
Callback in JS?  (0) 2021.07.17