JavaScript 이해하기

: 자바스크립트 초급, 그 이후

이종은


이종은

________ is the one programming language
to learn if you can learn only one

ref : itworld.com/article/2868413/

JavaScript

or

JS가 싫은 이유

ref : Douglas Crockford: Really. JavaScript.

The World's Most Misunderstood Programming Language

Kyle Simpson

오늘은
애매한 것을 깨우치는 시간

JS는 어떻게 동작하나요?

누구도 알려주지 않았다

JS 사용법

보다는

JS 이해

왜 그런지 모르지만 저렇게 쓰면 되는구나

아! 그렇기 때문에 저렇게 써야 하는구나!

질문은 언제든지 환영

얘깃거리

몸풀기

JS는 객체지향 언어다?

네! 5개 빼고 전부 객체이다.

객체

key - value 쌍의 모음

RUN
var obj = {
  title : "Advanced JS",
  attendee : 30,
  isBad : function(){
    return false;
  }
}

원시값

primitive type


Primitive Wrapper

string, number, boolean은 primitive wrapper를 통해 쉽게 객체로 변환

RUN
"I am a boy".length;
(3).toFixed(2);
true.toString();

복사

RUN
var p = 1;
var copyOfP = p;
p = 3;
console.log(copyOfP);

var myObject = {};
var copyOfMyObject = myObject;
myObject.foo = 'bar';
console.log(copyOfMyObject.foo);

비교 연산자 == vs ===

RUN
var one= 1, oneString = '1' , t = true;

console.log(one == oneString);
console.log(one == t);
console.log(oneString == t);

console.log(one === oneString);
console.log(one === t);
console.log(oneString === t);

객체 속성 접근방법

var obj = {
    name : 'MyObject'
};
var a = 'name';
console.log(obj.name);
console.log(obj["name"]);
console.log(obj[a]);

여는 중괄호의 위치

RUN
function f1(){
  return {
    name: 'jong'
  };
}

function f2(){
  return 
  {
    name: 'jong'
  };
}

console.log(f1());
console.log(f2());

이벤트 루프

Event Loop

JS는 어떻게 동작하는가?
(Runtime Concept)

이론적인 모델, 실제로 구현은 엔진에 따라 다르게 많이 최적화되어 있음

ref: dev.mozilla.org

RUN
function multiply(a,b){
  return a*b;
}

function square(x){
  return multiply(x,x);
}

square(2);

call stack

one thread == one call stack == one thing at a time

2014.jsconf.eu philip

"Run-to-complete"

한번 시작하면 끝을 봐야한다!
중간에 의도적으로 sleep하고 다른 일을 할 수 없다.

JS Runtime은 동시에 두가지 연산을 못해요?

네, 정말입니다.

이벤트 핸들러

RUN
document.getElementById('myBtn').onclick = function(){
  console.log('myBtn Click');
};

function g(){
  console.log('g');
}

g();

브라우저가 반응 없다가
갑자기 몰아서 응답할때는?

한동안 방응 없는 경우

RUN
document.getElementById('myBtn').onclick = function(){
  console.log('myBtn Click');
};

function g(){ 
  doSomething(); // 엄청 오래 걸리는 작업
}

g();
RUN
setTimeout(function(){

},x)

x초 후 함수를 실행

타이머

RUN
function f(){
  console.log('f - done');
}

function g(){
  setTimeout(function(){
    console.log('g - timeout')
  },3000);
  f();
}

g();
RUN
setTimeout(function(){

},x)

x초 후 함수를 실행

하는 것이 아니라 x초 후에 Queue에 넣음

HttpClient도 Block?

RUN
function f(){
  console.log('f - done');
}

function g(){
  $.ajax({
    url: "test.html"
  }).done(function() {
    console.log('g - ajax - done')
  });
  f();
}

g();

스코프

(scope)

스코프 (Scope)?

전역 변수, 지역 변수

RUN
var g = 3;
function f(){
  var h = 4;
}

'var' scope 결정자

단지 Function scope

어떻게 생겼는지 그려봅시다.

RUN
var msg = 'global';
var gmsg = 'wow';
function f(){
  var msg = 'local';
  return msg + gmsg;
}
f();

즉시 실행 함수

(function(){

})();

인자 전달

// 방법 1
(function(x){

})(a)

Return 값

// 방법 1
var result = (function(){
  return 4;
})();

// 방법 2
var result = function(){
  return 4;
}();

방법2는 뒤에 괄호를 눈여겨 보지 않으면 오해의 소지가 있다.

호이스팅

(Hoisting)

함수 선언문

RUN
f();
function f(){
  console.log('please');
};

익명 함수 표현식

RUN
f();
var f = function (){
  console.log('please');
};
RUN
function f(){
  console.log(a);
  return;
}
RUN
function f(){
  console.log(a);
  return;
  var a=3;
}

선언문 var은 항상 상단에 모아라

선언문 vs. 표현식

// 기함수 선언문
function me(){

}

// 기명 함수 표현식
var a = function me(){

};

Q. global? local?

RUN
function foo() {
  var a = b = 0;
}

Scope Chain

gmsg는 어떻게 찾은거지?

RUN
var msg = 'global';
var gmsg = 'wow';
function f(){
  var msg = 'local';
  return msg + gmsg;
}
f();

찾는데 걸리는 시간

RUN
var msg = 'global';
var gmsg = 'wow';
function f(){
  var msg = 'local';
  for(var i=0;i<100000;i++){
    msg+=gmsg;
  }
  return msg;
}
f();

this

(누구냐 넌?)

RUN
console.log(this);
RUN
function(){
  console.log(this);
}
RUN
var value = 'global';
var obj = {
  value : 'local',
  foo : function(){
    console.log( this.value );
  }
}
obj.foo();
RUN
function MyObj(){
  console.log(this);
}
var obj = new MyObj();

Q. 결과는?

RUN
var value = 'global';
var obj = {
  value : 'local',
  foo : function(){
    console.log( this.value );
  }
}
var foo2 = obj.foo;
foo2();

예외 : call, apply

RUN
var value = 'global';
var obj = {
  value : 'local',
  foo : function(){
    console.log( this.value );
  }
}
var foo2 = obj.foo;
foo2.call(obj);
foo2.apply(obj);

메모리 GC

메모리 관리 기본 3단계

  1. 필요할 때 할당한다.
  2. 사용한다. (읽기, 쓰기)
  3. 필요없어지면 해제한다.

MDN

JS gabage collector

ref: html5rocks

gabage collector 동작 방식

RUN
function f(){
  var arr = new Array(1000);
}
f();

ref count의 한계

RUN
function f(){
  var o = {};
  var o2 = {};
  o.a = o2; 
  o2.a = o;
  
  return "azerty";
}

f();

mark and swipe

닿을 수 없는 오브젝트 = 더 이상 필요 없는 오브젝트

클로저

(closure)

RUN
var outerValue = 'ninja';
var later;

function outerFunction(){
  var innerValue = 'samurai';
  
  function innerFunction(){
    console.log(innnerValue);
    console.log(outerValue);
  }
  
  later = innerFunction;
}

outerFunction();
later();

실습 1. 손으로 그려보면서 결과 예측

RUN
var nodes = document.getElementsByTagName('button');
for (var i = 0; i < nodes.length; i++) {
   nodes[i].addEventListener('click', function() {
      console.log('You clicked element #' + i);
   });
}

실습 2. 정상적으로 동작하도록

callback 패턴

함수를 다른 함수의 인자로 전달 할 수 있다?

자바스립트에서 함수는 1급 클래스이다.

function find(callback){
  var found;
  // 무언가를 찾아서 found에 저장
  if(found){
    callback(found);
  }
}

function hide(node){
  node.style.display= "none";
}

find(hide);

callback HELL

RUN
step1(function (value1) {
  step2(value1, function(value2) {
      step3(value2, function(value3) {
          step4(value3, function(value4) {
              // value4를 다루는 작업 수행
          });
      });
  });
});

promise

RUN
Q.fcall(promisedStep1)
.then(promisedStep2)
.then(promisedStep3)
.then(promisedStep4)
.then(function (value4) {
    // value4를 다루는 작업 수행
})
.catch(function (error) {
    // 위 step에서 발생하는 모든 에러 처리
})
.done();

promise - Q

RUN
function requestOkText(url) {
    return Q.Promise(function(resolve, reject, notify) {
        var request = new XMLHttpRequest();
        
        request.open("GET", url, true);
        request.onload = onload;
        request.onerror = onerror;
        request.onprogress = onprogress;
        request.send();
        
        function onload() {
            if (request.status === 200) {
                resolve(request.responseText);
            } else {
                reject(new Error("Status code was " + request.status));
            }
        }
        
        function onerror() {
            reject(new Error("Can't XHR " + JSON.stringify(url)));
        }
        
        function onprogress(event) {
            notify(event.loaded / event.total);
        }
    });
}

ref: Q

Object Oriented

(JS로 클래스)

글로벌을 더립히지 마라

RUN
function Parent() {}
function Child() {}

var some_var = 1;

var module1 = {};
module1.data = {a: 1, b: 2};
var module2 = {};

네임스페이스 패턴

RUN
var MYAPP = {};

MYAPP.Parent = function(){};
MYAPP.Child = function(){};

MYAPP.some_var = 1;

MYAPP.modules = {};

MYAPP.modules.module1 = {};
MYAPP.modules.module1.data = {a: 1, b: 2};
MYAPP.modules.module2 = {};

여러개의 파일에서..

RUN
//방법 1
var MYAPP = {};

//방법 2
if(typeof MYAPP === "undefined"){
  var MYAPP = {};
}

//방법 2-1
var MYAPP = MYAPP || {};

실습 : 비공개로 만들기

RUN
// 객체생성 방법1
var myModule = {
  name : 'literal',
  getName : function(){
    return this.name;
  }
}
console.log(myModule.name);
RUN
// 객체생성 방법2
function Gadget(){
  this.name = 'new Func';
  this.getName = function (){
    return this.name;
  };
}
var toy = new Gadget();
console.log(toy.name);

실습 : 비공개로 만들기 (A1)

RUN
// 객체생성 방법1
var myModule = {
  name : 'literal',
  getName : function(){
    return this.name;
  }
}
console.log(myobj.name);
RUN
var myModule = (function(){
  var name = 'literal';
  return {
    getName : function(){
      return name;
    }
  }
})();
console.log(myModule.name);
console.log(myModule.getName());

실습 : 비공개로 만들기 (A2)

RUN
// 객체생성 방법2
function Gadget(){
  this.name = 'new Func';
  this.getName = function (){
    return this.name;
  };
}
var toy = new Gadget();
console.log(toy.name);
RUN
function Gadget(){
  var name = 'new Func';
  this.getName = function (){
    return name;
  };
}
var toy = new Gadget();
console.log(toy.name);    
console.log(toy.getName());   

메모리를 생각해보면..

RUN
function Gadget(){
  var name = 'new Func';
  this.getName = function (){
    return name;
  };
}
var toy = new Gadget();
var toy2 = new Gadget();
var toy3 = new Gadget();
var toy4 = new Gadget();

new 할때마다 getName이 메모리에 할당된다.

getName은 변하지 않고 모든 인스턴스가 똑같은 동작을 하는데?

function Gadget(){
  var name = 'new Func';
  this.getName = function (){
    return name;
  };
}
var toy = new Gadget();
var toy2 = new Gadget();
var toy3 = new Gadget();
var toy4 = new Gadget();
RUN

        

prototype

RUN
function MyObj(){
  this.doSomething = function (){
    console.log('done');
  };
}
MyObj.prototype = {
  doSomethingInProto : function (){
    console.log('doneInProto');
  }
}

var obj = new MyObj();
obj.doSomething();
obj.doSomethingInProto();

var obj2 = new MyObj();
RUN
function MyObj(){
  this.doSomething = function (){
    console.log('done');
  };
}
MyObj.prototype = {
  doSomething : function(){
    console.log('doneInProto');
  }
}

var obj = new MyObj();
obj.doSomething();

var obj2 = new MyObj();

그외

(tip, 도구..)

strict mode

"use strict"

더 많은 예외를 발생시켜
코딩실수나 안전하지 않은 방식,
혼란스러운 방식 원천 차단

ref1, ref2: ejohn.org

setInterval의 비밀?

RUN
var cnt = 0;
setInterval(function(){
  cnt++;
  console.log(cnt);
},1000);

참고 자료

인용에 해당할 경우는 각 페이지 하단 우측에 링크를 넣었습니다.
그외 참고자료는 아래와 같습니다.

감사합니다.