코테에서 언어를 javascript로 선택하니 입력값은 알아서 입력해 주지만, 그걸 받아서 처리하는건 내 몫이다. 

 

정작 console.log(); 로 출력이나 자주 해봤지, cofirm()이나 prompt()를 제외하고

JS에서 입력받는 값을 컨트롤해 본 적이 없었다. 

 

프로그래머스처럼 간단히 핵심 로직만 구현할 수 있게 해주면 좋을텐데,

아쉬움으로 뒤로하고, Js환경에서 코테시 그 입력값을 받아 로직을 처리하기 위한 핵심 부분은 다음과 같다. 

 

아래 예제는 공백을 사이에 두고 두 숫자를 한 라인에 입력 받은 후, 그 합을 출력하는 예제다. 

const readline = require("readline");
const rl = readline.createInterface({
    input : process.stdin,
    output : process.stdout
});
    
let input = [];

rl.on('line', function(line){
	input = line.split(' ').map((number) => Number(number));
})
.on('close', function() {
	console.log(input[0] + input[1]);
	process.exit();
});

 

 

여러 줄을 입력받아 처리할 때는 다음과 같이 작성한다.

 

const readline = require("readline");
const rl = readline.createInterface({
	input : process.stdin,
    output : process.stdout
    });
    
let input = [];

rl.on('line', function(line){
    input.push(line);
})
.on('close', function() {
	// TODO input을 이용한 서비스 로직 작성
	process.exit();
});

 

 

 

pageshow 와 pagehide이벤트를 위한 이벤트 객체 

 

브라우저는 문서를 처음 로드할 때 load 이벤트 다음에 pageshow 이벤트를 발생 시키며, 

문서를 벗어날 때는 pagehide 이벤트를 발생시킨다. 

 

pageshow와 pagehide 이벤트는 window 객체에서 발생하며,

PageTransitionEvent 객체는 두 이벤트와 조합된다. 

 

pageshow와 pagehide는 버블링되지 않고, 취소 가능한 기본 동작도 존재하지 않는다.

(크롬에서 pageshow, pagehide는 디버깅이 안타지던데 이 때문인가..)

 

해당 이벤트 객체의 persisted 프로퍼티의 값은 페이지가 로드 또는 새로고침이 아니라 복원되었을 경우에 true이다.

페이지가 네트워크 또는 디스크 캐시로부터 로드 또는 새로고침 될 때는 false의 값을 가진다.

 

persisted 프로퍼티는  pagehide에선 항상 true이고, pageshow에서만 true/false의 값을 가진다.

 

 

 


load

- 문서와 해당 문서의 외부 리소스들이 모두 로드되었을 때

 

pagehide

- 페이지가 캐시되어 있으며 다른 페이지에 의해 교체되었을 때

 

pageshow

- 페이지가 처음 로드되면 load이벤트 직후에 pageshow이벤트가 발생한다. 해당 이벤트에는 persisted 값이 false이지만, 페이지가 브라우저의 메모리 캐시로부터 복구되었다면 load이벤트가 발생하지 않으며(캐시된 페이지가 이미 loaded상태이기 때문), persisted 프로퍼티 값이 true로 설정된 이벤트객체와 함께 pageshow 이벤트가 발생한다.

 

unload

- 브라우저가 페이지로부터 다른 곳으로 벗어날 때. 페이지의 onunload 핸들러를 등록하면, 페이지가 캐시되지 않는다는 사실에 주의하자. 사용자가 새로고침엇ㅂ이 빠르게 현재 페이지로 되돌아오게 하려면, onpagehide를 대신 사용하는 편이 낫다.

 

 

출처 : 자바스크립트 완벽 가이드 / 데이비드 플레너건 

 

 

 

 

React 공부 시작하려는데, React페이지에서 JavasScript를 다시 보고 올 수 있는 링크를 주는 친절함을 베풀었다.

타고 넘어가 보니 한 페이지에 보기쉽게 JavaScript 정리가 되어있어 한번 쭈욱~ 훑어보고 왔다ㅎㅎ 

 

developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript

 

A re-introduction to JavaScript (JS tutorial)

Why a re-introduction? Because JavaScript is notorious for being the world's most misunderstood programming language. It is often derided as being a toy, but beneath its layer of deceptive simplicity, powerful language features await. JavaScript is now us

developer.mozilla.org

 

--------------------------------------------
표준 내장객체 및 메소드 

Number
String
Boolean
Symbol (new in ES2015)
Object
ㄴ Function
ㄴ Array
ㄴ Date
ㄴ RegExp
null
undefined 

--------------------------------------------

javascript에서 var와 let/const와의 차이점 

일반적으로 자바스크립트에서 var를 이용해서 변수 선언시 블록 범위에 제한이 없지만, 
ECMAscript2015 부터 let과 const 선언을 사용하면 블록 범위 변수를 만들 수 있음. 

--------------------------------------------
제공하는 for 사용법 

for (var i = 0; i < 5; i++) {
  // Will execute 5 times
}

for (let value of array) {
  // do something with value
}

for (let property in object) {
  // do something with object property
}

--------------------------------------------

&& 및 || 연산자는 단락 논리를 사용하므로 두 번째 피연산자를 실행할지 여부는 첫 번째 피연산자에 따라 다릅니다. 
이는 속성에 액세스하기 전에 null 개체를 확인하는 데 유용합니다.

var name = o && o.getName();

--------------------------------------------
switch 문은 숫자 또는 문자열을 기반으로 여러 분기에 사용할 수 있습니다.

--------------------------------------------
Object 
JavaScript 객체는 이름-값 쌍의 단순한 모음으로 생각할 수 있습니다. 따라서 다음과 유사합니다.

Dictionaries in Python.
Hashes in Perl and Ruby.
Hash tables in C and C++.
HashMaps in Java.
Associative arrays in PHP.

객체 생성 방법 두가지.
var obj = new object();
var obj = {}; // *****별이 다섯개 ~

두 방법은 의미상 동일함. 두 번쨰는 객체 리터럴 구문이라고 하며 더 편리하고. JSON 형식의 핵심이며 항상 선호되어야 함. 

접근할때는 .을 이용하여 값에 접근. 

--------------------------------------------

Array 
Array는 특별한 유형의 객체. 객체와 달리 []로 선언. 

var a = new Array();
a[0] = 'dog';
a[1] = 'cat';
a[2] = 'hen';
a.length; // 3

혹은 
var a = ['dog', 'cat', 'hen'];
a.length; // 3

var a = ['dog', 'cat', 'hen'];
a[100] = 'fox';
a.length; // 101

존재하지 않는 인덱스에 접근시 undefined를 반환. 
type of a[90]; // undefined


Array 요소에 접근시, 

for (var i = 0; i < a.length; i++) {
  // Do something with a[i]
}

아래 표기법은 ECMA2015 부터 가능해짐. 
for (const currentValue of a) {
  // Do something with currentValue
}

for..in 루프를 사용하면 배열을 반복할 수도 있지만 배열 요소가 아니라 배열 인덱스를 반복한다.

 

제공하는 메소드 

a.pop() // 마지막 요소를 Remove and returns.
a.push(item) // 마지막에 요소를 추가.
a.shift() // 첫번째 요소를 Remove and returns.
a.unshift(item) // 배열의 시작부분에 요소를 추가.
a.reverse()  // Reverses the arrays.
a.sort([cmpfn]) // 선택적 비교를 이용한 정렬
이외에 slice, concat, 등


----------------------------------------

Funciton

function makePerson(first, last) {
  return {
    first: first,
    last: last,
    fullName: function() {
      return this.first + ' ' + this.last;
    },
    fullNameReversed: function() {
      return this.last + ', ' + this.first;
    }
  };
}

var s = makePerson('Simon', 'Willison');
s.fullName(); // "Simon Willison"
s.fullNameReversed(); // "Willison, Simon"

----------------------------------------

prototype  

Java 가 class를 이용해 객체를 생성한다면, JavaScript는 prototype을 이용해 객체를 생성한다.


prototype을 이용하면 runtime에 기존 객체에 메서드를 추가할 수 있음.

-----------------------------------------

prototype을 이용한 문자열 거꾸로 출력.

 

var s = 'Simon';
s.reversed(); // TypeError on line 1: s.reversed is not a function

String.prototype.reversed = function() {
  var r = '';
  for (var i = this.length - 1; i >= 0; i--) {
    r += this[i];
  }
  return r;
};

s.reversed(); // nomiS

-----------------------------------------

클로저 ..? 너는 다음 기회에 

 

10.JavaScript 개발자가 알아야할 33개 컨셉 10. setTimeout, setInterval and requestAnimationFrame


1. setTimeout

set timeout은 자바스크립트에서 나온 개념이 아니라 브라우저와 노드js에서 가져온 개념이다. 

하는 일은 일정 시간이 흐른후에 함수를 실행시킬 때 사용한다.

좀더 세부적인 설명을 하자면, setTimeout은 시간이 지난 후에 기능을 메시지큐에 붙여준다.

함수를 자동으로 부르는 것이 아니라, 함수를 메시지 큐에 넣고, 스택이 비게되면, 자바스크립트가 실행하는 것이다.

바로 이뤄질 수도 있고, 자바스크립트가 바쁘면 천천히 실행 할 수도있다.. 그래서 time specific하다고 볼 수 없다.

 

사용법은 매우 간단하다. 첫번째 인자가 함수이고, 세번째 인자로 시간을 넣어주면된다.  3초 후 실행시킨다면 3000을 두번째 인자로 전달하면된다. 

 

기억해야 할 것은 저 3000(3초)이라는 숫자는 함수를 큐에 올리기 까지 최소한의 대기시간이며,

준비가되면 자바스크립트가 부르는 것이다.

즉, 확실한 시간이 아니고 브라우저 상황 자바스크립트 상황에 따라 지연이 될 수 있다.

하지만 뭐 그리 큰 지연은 아니니 무시해도 된다고한다..

 

setTimeout( () => console.log("Hi"), 3000)

setTimeout( console.log, 3000, 'Hi') 도 위와 동일하게 동작한다.

 

중요한 것은 우리가 직접 함수를 부르지 않고, 함수를 setTimeout에게 주고, 그 다음 setTimeout이 함수를 부르는 것이다.


그리고 떄로는 setTimeout에게 맏겨놓은 작업을 취소하고 싶을 때가 있다.

 

그럴때는 setTimeout을 변수 안에 넣으면 된다. 

 

timeout 변수에 setTimeout함수를 셋팅하고, console.log로 timeout함수를 실행시켜보면 숫자가 리턴되는데,

 선언한 timeout에 대한 ID 값이 리턴된 것이다. 

위 코드는 10초 후에 Hi를 출력하는 것이고, ID를 가지고 있는것을 확인할 수 있다.

 

생성한 타임아웃 작업을 취소하고 싶을 때는 clearTimeout에 해당 setTimeout변수를 셋팅해주면된다.

clearTimeout(timeout);

 

2. setInterval

일정 시간마다 함수를 실행시킬 때 사용하며, setTimeout과 동일한 인자를 사용한다. 

const timeout = setInterval(console.log, 10000, 'Hi');

이렇게 하면 10초 마다 Hi가 출력되는 것이다.

 

setInterval함수도 마찬가지로 clearInterval 함수에 변수를 인자로 넘겨줌으로써 실행을 종료시킬 수 있다.

clearInterval(timeout);

 

setTimeout과 setInterval모두 함수를 직접 사용하지 말고 함수의 이름을 넣어준다는 것이 중요하다.

그것들을 취소하고 싶을 때 clear을 이용하면 되기 때문이다.

 

3. requestAnimationFrame

 

이전에 화면에서 뭔가 움직이게 하려면 사람들은 setInterval을 사용했다. 

그러나 interval에 의지할 수 없고(time specific이 아니니까) 또한 CPU나 그래픽카드가 느리면 interval이 느려질 수 있다는 단점이 존재한다. 

그래서 requestAnimationFrame이 나온 것이라 한다.

 

requestAnimationFrame은 브라우저 화면이 렌더링 되기 전에 함수를 실행시키기 떄문에, 따로 시간 값을 인자로 넘길 필요가 없으며 오직 CallBack Fn만을 인자로 넘겨서 사용한다. 

애니메이션 작업을 많이 하지 않는이상 자주 쓸 일은 없는 함수이다..

const sayHi = () => {
	console.log('Hi');
    requestAnimationFrame(sayHi);
};

requestAnimationFrame(sayHi);

위 코드를 실행하면 Hi가 console에 아주 빠르게 출력이 되기 시작하고, 다른 탭으로 이동하면 크롬은 그걸 실행시키지 않는다. 해당 스크린을 리페인팅하는 것이 아니기 때문이다. 

다시 해당 탭으로 돌아가면 다시 실행이 시작되는 것을 확인 할 수 있다. 

 

무언가 최대한 빠르게 실행하고 싶을 때, requetAnimationFrame을 사용해보면 될것이다.

 

- iframe을 이용한 유튜브 동영상 삽입방법 

 

<div class="video_area">
    <!-- 비디오 요소가 들어 갈 위치 -->
</div>

<script type="text/javascript">
    // 비디오 api 선언
    var tag = document.createElement('script');
    tag.src = "https://www.youtube.com/iframe_api";
    var firstScriptTag = document.getElementsByTagName('script')[0];
    firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

    // 유튜브 api module
    function onYouTubeIframeAPIReady() {
        var playerModule = function (videoObj) {
            this.player;
            this.$videoWrap = $('#' + videoObj.playerId + '').parent('.video_area');
            this.playerId = videoObj.playerId;
            this.videoId = videoObj.videoId;
            //this.posterSrc = videoObj.posterSrc;

            this._init();
        };

        playerModule.prototype._init = function () {
            this.$videoWrap.prepend(this.posterTemplete());
            var that = this,
                $btnPlay = that.$videoWrap.find('.playBtn'),
                videoTop = that.$videoWrap.offset().top,
                viewTop = $('.contents').find('h1').length > 0 ? $('.contents').find('h1').offset().top : 0,
                videoPlayer;

            var onPlayerReady = function (event) {
                
                $btnPlay.on('click', function () {
                    that.toggleKlass({
                        el: that.$videoWrap,
                        klass: 'playing'
                    });
                    event.target.playVideo();
                });
            }

            var onPlayerStateChange = function (event) {
                if (event.data == 0) that.toggleKlass({
                    el: that.$videoWrap,
                    klass: 'playing'
                });
            }

            // 유튜브 api 실행
            this.player = new YT.Player(that.playerId, {
                videoId: that.videoId,
                playerVars: {
                    rel: 0,
                    playsinline: 1,
                    disablekb: 1
                },
                events: {
                    'onReady': onPlayerReady,
                    'onStateChange': onPlayerStateChange
                }
            });
        };
        playerModule.prototype.posterTemplete = function () {
            var imgSrc = this.posterSrc ? this.posterSrc : '//img.youtube.com/vi/' + this.videoId + '/maxresdefault.jpg';
            var templete = '<div class="poster_area">' +
                '<span class="img"><img class="poster" src="'+imgSrc+'" alt=""></span>' +
                '<a href="javascript:;" class="playBtn"> <span class="playIco medium"></span> </a>' +
                '</div>';
            return templete;
        };
        playerModule.prototype.toggleKlass = function (obj) {
            obj.el.hasClass(obj.klass) ? obj.el.removeClass(obj.klass) : obj.el.addClass(obj.klass);
        };

        $(document).ready(function() {
            /* S : 2020-01-17 추가 */
            if($('#youtube_vod').size() > 0) {
                $('.video_area').removeClass('playing');
            }
            $('.video_area').html('<div id="youtube_vod"></div>');
            /* E : 2020-01-17 추가 */
            
            var video = new playerModule({
                playerId: 'youtube_vod', // tag id
                videoId: 'z_Bfl7jy9P4', // 유튜브 비디오 id, ex) 유튜브 소스코드 복사후 해당ID 복사 <iframe width="1280" height="720" src="https://www.youtube.com/embed/해당ID" ></iframe>
            });
        });

        $(window).bind("popstate", function (event) {
            if($('#youtube_vod').size() > 0) {
                $('.video_area').removeClass('playing');
            }
            $('.video_area').html('<div id="youtube_vod"></div>');
            
            var video = new playerModule({
                playerId: 'youtube_vod', // tag id
                videoId: '유튜브 비디오 id', // 유튜브 비디오 id
            });
        });
    }
</script>

 

아래 popstate를 바인딩 시킨 이유는, safari나 firefox환경에서 historyback 시,

BFCache로 인해 동영상이 무음으로 재생되면서, 볼륨조절이 먹통이 되는 현상을 해결하기 위해 추가 되었다.

09. Message Queue and Event Loop

 

Messaege Queue와 Event Loop 이해에 앞서 알아 두어야 하는 것은 Javascript는 non blocking언어라는 것이다. 

(phthon의 경우 blocking언어.)

 

- Non blocking언어

Javascript는 Non blocking언어이지만 alert function의 경우에는 block이 가능하다. 

alert('blabla');
console.log('123');

위 코드를 실행하면,

alert가 뜨고 해당 alert창을 닫기 전까지 console.log는 실행되지 않는다. 

alert를 만나면 다음 프로세스를 수행하지 않고 차단(block)된다는 것이다. 

따라서 alert는 blocking function인 것인데, Javascript언어 자체는 non blocking언어이다. 

 

자바스크립트가 non blocking언어 이기 때문에 Events와 callbacks이 사용 가능한 것이다.

예를 들어 버튼을 만들고 Add event listener 로 click 에 대한 callback 이벤트를 걸 수 있다.

 


-Queue와 Event loop

 

setTimeout{
	console.log('hi'), 0
};
console.log('bye');

setTimeout을 이용하여 0초 후에 hi를 출력하도록 하고, 다음으로 bye를 출력하도록 하는 소스이다.

 

위 코드를 실행하면 결과는 기대와 다르게 bye가 먼저 출력되고 이후에 hi가 먼저 출력된다.

그렇다며 그 이유는 무엇인가?

 

이번 절의 Queue와 Event Loop는 이 현상에 대한 이유를 이해하는 것이 핵심이라고 한다. 

 

위 코드를 실행하면 내부적으로 다음과 같은 프로세스가 실행된다.

1. 먼저 명령이 Stack에 순서대로 들어온다. 

2. 두번째 단계에서 setTimeout은 브라우저의 WEB API를 이용하여 호출되기 때문에  Web API zone으로 이동 되고,

다음 명령인 console.log 문장이 바로 실행된다. 떄문에 bye가 먼저 찍히는 것이다.

3. bye는 먼저 실행되어 stack을 빠져나가고, Web API는 setTimeout안의 내용을 0초 후에 Queue로 보낸다. 

4. 마지막으로 Queue에 들어온 내용은 다시 Stack으로 보내져서 최종적으로 hi가 출력되는 것이다.

 

이것이 Queue와 event Loop에 대한 핵심 내용이다.. 라는 것이 노마드 코더의 설명이다. 

동영상마다 러닝타임이 10분정도다 보니 매번 설명이 충분하지 못한 느낌이 드는것은 어쩔수 없는 것인가,,,

08.IIFE, Modules

주제는 IIFE, MOdules and Namepaces이지만 강의에서 Namespaces의 내용은 하지 않는다고 하여 pass~

 

const secretUsers = ["park", "lee", "kim"];
console.log(secretUsers);

위와 같은 문장을 실행하면 브라우저에서 Array에 접근이 가능하다. 

브라우저에서 접근이 가능하다는 것은 해당 Array를 마음대로 변형하는 것도 가능하다는 것이다. 

아래와 같이.

 

 

위의 secretUsers Variable은 공개되어 있다. Private이 아니다.

브라우저에 있고, 접근할 수 있다는 것이다. 

 

어떤 경우, 자바스크립트는 주고 싶지만, 나의 variable에는 영향을 끼치는 것을 원하지 않는 경우가 있다. 

비밀모드로 만들어야 한다는 것인데, 

그럴때 사용하는 것이 IIFE이다. 

 

바로 아래와 같이 함수를 만들고 해당 함수를 부르는 것이다. ()()

(function(){
	const secretUsers = ["park", "lee", "kim"];
	console.log(secretUsers);
})()

혹은

(() => {
	const secretUsers = ["park", "lee", "kim"];
	console.log(secretUsers);
})()

 

위와 같이 IIFE를 사용하면 해당 variable에 대한 접근이 불가능 한 것을 확인할 수 있다.


- Module

 

html페이지에서 외부 스크립트 파일을 가져와 사용해야 할때,

<script src="경로/스크립트파일명.js"></script> 와 같은 방식으로 사용한다. 

 

하지만 각각의 스크립트 파일들을 하나의 모듈로서 포함시켜 사용하기 위해서는, 

위와같은 문장으로는 에러를 발생시킨다.

type 속성을 추가하여 "module"값을 지정해주면 해결된다.

 

<script type="module" src="경로/스크립트파일명.js"></script>

 

 

 

07.Expression vs. Statement

 

- Expression

Expression returns a value

무언가 결과(Value)를 return하는 문장

 

ex1) 5 + 11  > 16이라는 결과를 return하므로 Expression

ex2) 

function add(a, b) {

 return a+b;

}

console.log(add(5,6)); 

 > add(5,6) 도 11이라는 결과를 return하므로 Expression

 

자바스크립트는 Expression을 value로 대체하고, 작업을 계속 진행한다.

 


- Statement

 

Statement는 명령. 혹은 지시이다. 

ex1) 예를 들어 아래와 같은 코드블럭은 아무것도 리턴하지 않는다. 지시. 명령이다.

if(true) {

}

ex2) 아래와 같은 문장은 에러를 발생시킨다. return되는 Value가 없는 Statement를 Variable로 저장할 수 가 없기 때문이다.

const thing = if(true) {
}

 

 

결론. Variable로 저장할 수 있는 건 Expression이다.

Expression은 Value를 리턴한다. 

Statement는 그냥 명령이다. 

if, else, for, while...  등등

 


function Expression vs. function declaration

 

 

const awesome = add(1,5);


function add(a,b) {	// << 함수의 선언식(function declaration)
	return a+b;
}

console.log(awesome)

위 문장은 에러를 발생시키지 않는다. 

라인 1에서는 존재하지 않던 함수를 사용했고, 결과는 6이 반환된다.

이것이 가능한 이유는

자바스크립트가 코드를 보면, 모든 declaration(함수의 선언식)을 상단으로 가져온다. 

이것이 자바스크립트에서 존재하는 hoisting이라는 프로세스이다.

때문에 위와 같은 코드가 에러를 발생시키지 않는 것이다. 

 

 

반면에, 아래와 같은 코드는 에러를 발생시킨다.

const awesome = add(1,5);

const add = (a, b) => a + b;	// << 함수의 표현식(function expression)

console.log(awesome)

이유는 함수의 표현식은 hoisting이 되지 않기 때문에, 1번 라인에서 add는 존재하지 않는 것이 되기 때문이다. 

 

이것이 함수의 선언문과 표현식의 가장 중요한 차이점이다. 

 

+ Recent posts