반응형

글로벌 변수를 최소화하는 방법

  • 클로저를 이용하는 방법
  • 모듈 / 네임스페이스 패턴을 이용하는 방법

 

클로저를 이용하는 방법

<script>
    (function() {
        var localVariable = "Not Global";
    }());
</script>

위처럼 클로저를 사용해 간단하게 로컬 변수로 바꿔줄 수 있다.

 

모듈 / 네임스페이스 패턴을 이용하는 방법

<script>
    var myModule = (function() {
        var localVariable = "local variable";

        return {
            show: function() {
                alert(localVariable);
            }
        }
    }());

    myModule.show();
</script>

myModule이라는 변수 자체는 글로벌 변수다. 하지만 myModule이외의 다른 변수들은 모두 즉시 호출 함수 안에서 사용하여 글로벌 변수가 아니다. myModule.show();를 통해 간접적으로 내부 함수의 로컬 변수들에 접근하고 사용할 수 있다.

 

즉시 호출 함수로 모듈을 생성하는 예

<script>
    (function() {
        var localVariable = "local variable";

        window.myModule = {
            show: function() {
                alert(localVariable);
            }
        };
    }(window));
    myModule.show();
</script>

위 두 코드는 같은 기능을 수행한다. 이렇게 글로벌 변수를 최소화함으로써 서로 다른 자바스크립트 코드간의 충돌을 최소화하고자 하는 것이 모듈 / 네임스페이스 패턴이다.

 

글로벌 변수의 사용을 최소화하기 위한 방법 기준

  • DOM에 자바스크립트 코드를 넣고 변수에 접근해야 한다. :: 모듈방식
  • 다른 개발자와 상호작용하는 코드를 만든다. :: 모듈방식
  • 자바스크립트 라이브러리를 만들고 싶다. :: 모듈방식
  • 외부에서 접근할 일이 없다. :: 클로저 방식
  • 잘 모르겠다. :: 클로저 방식

위 기준에 따르면 대부분 클로저를 사용해서 글로벌 변수 없이 전체를 로컬 변수로 만들어 사용하는 것이 좋다. 특히 자바스크립트 개발자 커뮤니티에서는 글로벌 변수의 사용 자체를 막기 위해, 그리고 DOM과 자바스크립트의 역할을 명확하게 구분하기 위해 위 기준 중 1번 DOM에 자바스크립트 코드를 넣는 것을 반대하고 있기도 하다.

반응형
반응형

JSON과 AJAX

JSON ( Java Script Object Notation )

  • JavaScript Object Notation이라는 의미의 축약어로 데이터를 저장하거나 전송할 때 많이 사용되는 Data교환 형식
  • Javascript에서 객체를 만들 때 사용되는 표현식을 의미
  • JSON표현식은 사람과 기계가 모두 이해하기 쉬우면서 용량이 작기때문에, 데이터 전송 등에 많이 사용된다.
  • 데이터를 표시하기 위한 단순한 표현 방법

 

AJAX ( Asynchronous Javascript And XML )

  • Javascript를 이용해 서버와 브라우저가 비동기 방식으로 데이터를 교환할 수 있는 통신 기능
  • 브라우저가 가지고 있는 XMLHttpRequest객체를 이용해서 전체 페이지를 새로 고치지 않고 페이지의 일부만을 로드하는 기법

 

JSON파일과 AJAX를 이용한 간단한 통신

HTML

<div class="json_test_wrap">
    <div class="title">JSON and AJAX</div>

    <button id="btn">Click</button>

    <div id="info"></div>
</div>

<script src="../js/main.js"></script>

 

JS

// 카운트
var count = 0;
// 클릭버튼
var btn = document.getElementById("btn");
// 버튼을 클릭했을 때 내용이 나타날 부분
var animal = document.getElementById("info");

btn.addEventListener("click", function() {
    var ourRequest = new XMLHttpRequest();

    ourRequest.open('GET', '../json/jsonData.json');
    
    ourRequest.onload = function() {
        if(ourRequest.status >= 200 && ourRequest.status < 400) {
            var ourData = JSON.parse(ourRequest.responseText);
            renderHTML(ourData);
        } else {
            console.log('err');
        }
    };
    ourRequest.send();
    ++count;
    // 내용 나오면 버튼 삭제
    if(count === 1) {
        btn.remove();
    }
});

function renderHTML(data) {
    var stringHTML = "";

    for(var i = 0; i < data.length; i++) {
        stringHTML += "<p> 이름은 " + data[i].name + ' 종류는 ' + data[i].species + ".</p>";
    }

    animal.insertAdjacentHTML('beforeend', stringHTML);
}

 

JSON

[
  {
      "name": "다롱이",
      "species": "고양이",
      "favFood": "통조림"
  },
  {
      "name": "메론",
      "species": "당나귀",
      "favFood": "당근"
  },
  {
      "name": "민트",
      "species": "강아지",
      "favFood": "사료"
  }
]

 

버튼을 클릭하면 JSON내용을 불러오고 버튼이 삭제

 

반응형
반응형

글로벌 변수의 선언 방법

  • 글로벌 스코프에서 var키워드를 써서 변수 선언
  • 상위 스코프에서 같은 변수명으로 선언되지 않고 var키워드 없이 바로 변수 사용하는 경우
  • window객체가 재선언되지 않은 스코프에서 window.global과 같이 속성 추가
  • window객체가 재선언되지 않은 스코프에서 window["global"]과 같이 속성 추가

위 방법들은 각 조건에 따라 글로벌 변수가 선언된다.

<script>
    // 글로벌 스프에서 글로벌 변수 정의
    var myGlobal = "global";

    // 하위 스코프에서 var키워드 없이 글로벌 변수 정의
    (function() {
        myGlobal2 = "global";
    }());

    // window객체를 재정의
    (function() {
        var window = {
            popup: function() {
                window.open("http://shiro21.tistory.com");
            },
            alert: function() {
                alert("I'm not the true alert");
            },
            open: function(url) {
                alert("I know where you are going ..." + url);
            }
        };

        window.alert();
        window.popup();
    }());
</script>

window객체를 재정의한 부분에서는 window객체를 변조하여 window.open()함수를 원래의 팝업창을 띄우는 용도가 아닌 다른 용도로 사용하는 예이다. 이렇게 하면 다른 개발자들과 협업하면서 개발한 소스코드가 서로 충돌날 수도 있으니, window라는 변수명은 사용하지 말아야한다.

 

글로벌 변수 선언 방법의 차이

각각의 글로벌 변수 선언 방법에 어떤 차이가 있는지 봤을때 가장 대표적으로 다른점은 변수가 선언되는 시기다.

 

글로벌 스코프에 var키워드를 써서 정의

<script>
    console.log("1: " + varExists + " , " + window.hasOwnProperty("varExists")); // undefined , true
    var varExists = "Define a glbal variable with var keyword";
    console.log("2: " + varExists); // Define a glbal variable with var keyword
</script>

첫번째 결과는 undefined가 나오고, 두번째 결과는 String값이 나타난다. 그리고 글로벌 객체인 window는 이미 var키워드로 정의한 변수를 가지고 있음을 알 수 있다.

 

var키워드 없이 글로벌 변수 정의

<script>
    console.log("Exists?: " + window.hasOwnProperty("noVar")); // Exists?: false
    console.log("1: " + noVar);
    noVar = "Define a global variable without var keyword";
    console.log("2: " + noVar);
</script>

이렇게 변수를 var키워드 없이 사용하면, 실제로 noVar = "...";구문이 실행되기 전에는 변수가 window의 속성으로 정의되어 있지 않다.

따라서 noVar변수에 접근하려고 하면 정의되지 않은 변수라는 레퍼런스 에러가 일어난다. 이것은 var키워드로 정의한 변수는 최초 소스의 파싱 단계에서 미리 글로벌 변수로 정의되어 undefined로 값이 설정되지만, var키워드를 이용하지 않으면 해당 구문이 직접 실행되는 순간에 글로벌 변수를 window객체의 속성으로 추가하기 때문이다.

 


추가내용

 

if구문 안에 변수를 정의하는 예

<script>
    function optimizedFunc(flag) {
        if(flag) {
            var lotsOfVariables1, lotsOfVariables2, lotsOfVariables3;
            console.log("1: " + lessVariables);
        } else {
            var lessVariables;
            console.log("2: " + lotsOfVariables1);
        }
    }
    optimizedFunc(true);
    optimizedFunc(false);
</script>

여기서 알 수 있는 점은 함수의 소스코드인 code전체를 기준으로 변수를 정의하기 때문에 "var키워드로 정의하는 변수의 위치는 의미가 없고, 변수의 초기화 위치만 의미가 있다"는 점이다. 따라서 코드 중간이나 if등으로 분기할 때 var키워드로 변수를 따로 구분하여 정의하는 것은 성능에 아무런 영향을 미치지 않는다.

위 함수에서 보면 if문의 첫 번째 분기에는 여러 변수가 정의되어 있고, 두 번째 분기에서는 변수를 조금 사용하기 때문에, if문의 분기별로 따로 변수를 정의하면 메모리나 성능을 효율적으로 사용할 수 있을 것 같은 느낌이지만, '실행 환경'이라 하면 새로운 스코프가 생성되는 함수로 들어갈 때 해당하고, if구문은 해당 사항이 없다.

따라서 optimizedFunc()함수 안으로 들어갔을 때, 이미 첫 번째 분기의 여러 변수와 두 번째 분기의 적은 변수들이 모두 정의되기 때문에 내부적으로 메모리의 효율은 줄어들지 않는다.

 

자바스크립트 문법 검사기 JSLint 바로가기

 

변수는 함수가 처음 시작할 때, 하나의 var키워드 아래에 전부 다 묶어서 정의하라

 

반응형
반응형

for문과 역 for문

for (var i = 0; i < length; i++)와 같은 형태의 for 반복문을 단순 for 반복문이라고 한다.

0으로 시작해서 length 바로 전까지 반복 실행하는 이유는 배열의 인덱스가 0에서 시작하기 때문이다.

<script>
    var array = ['포도', '사과', '바나나', '망고'];
    
    for (var i = 0; i < array.length; i++) {
    	alert(array[i]);
    }
</script>

 

반면에 요소를 출력할 수도 있다. 이러한 반복문을 역 for반복문이라고 한다.

<script>
    var array = ['포도', '사과', '바나나', '망고'];
    
    for (var i = array.length -1; i >= 0; i--) {
    	alert(array[i]);
    }
</script>

이러한 단순 for반복문, 역 for반복문 같은 형태를 많이 사용하지만 다른 형태도 많이 사용된다. 꼭 초기식에서 선언한 변수를 조건식이나 종결식에 사용할 필요는 없다.

 

브라우저의 성능을 측정하는 프로그램 (1초동안 반복문이 몇 회 반복되는지 표시해 브라우저의 성능을 측정한다.)

<script>
    var startTime = new Date().getTime();
    
    for (var cps = 0; new Date().getTime() < startTime + 1000; cps++) {}
    alert('초 당 연산 횟수: ' + cps);
</script>
반응형
반응형

window객체

자바스크립트는 브라우저 환경에서 돌아가도록 만들어졌다. 그래서 글로벌 영역을 다른 언어와는 조금 다르게 구현하고 있다.

그런데 글로벌 영역도 하나의 변수로 정의하여 사용하고 있다.

 

글로벌 객체( Global Object )

글로벌 객체는 단 하나만 유일하게 존재하며, 어떠한 컨텍스트가 실행되기 전에 먼저 생성된다.

  • 글로벌 객체는 내부적으로 생성자가 없으며, new를 이용해서 생성자로서 사용할 수 없다.
  • 글로벌 객체는 내부적으로 call함수가 없으며, 글로벌 객체를 함수로서 호출할 수 없다.
  • 글로벌 객체의 prototype은 구현 방법에 따라 달라질 수 있다.
  • 글로벌 객체는 추가로 표준에 명시되어 있는 이 속성들 이외에도 추가 속성들이 정의될 수 있으며, 글로벌 객체 자신을 다시 속성으로 가지는 것도 포함될 수 있다. ( EX : HTML DOM에서 window속성은 글로벌 객체 자신을 나타내는 속성 )

실행 전 단계에 객체가 생성되어, 이 객체에는 덮어쓸 수 있으나 루프로 돌 수는 없는 기본 내장된 속성들을 가지고 있다. 그리고 생성자가 없어서 new로 생성할 수 없으며, 함수로 호출할 수도 없고 프로포타입도 없다. HTML DOM환경에서 이 객체는 window속성을 가지고 있으며, 이것이 Global object 그 자체를 나타낸다고 정의하고 있다.

따라서 HTML DOM환경에서 글로벌 영역의 window속성으로 접근하면 글로벌 객체에 접근하는 것과 마찬가지로 글로벌 영역에 있는 속성들에 접근할 수 있는  것이다. 이렇게 보면 window는 window.window등과 같이 재귀적인 모습을 갖추고 있는것을 알 수 있다.

 

window === window.window인 재귀적인 모습을 볼 수 있다. 그리고 window객체는 global object 그 자체이므로, window객체는 글로벌 변수로 선언한 모든 변수를 속성으로 갖는다.

<script>
    console.log(window === window.window); // true
    console.log(window === window.window.window); // true 
</script>

 

window 객체를 통한 글로벌 변수 접근

<script>
    var myGlobal = "am i in window?";
    console.log(myGlobal); // am i in window?
    console.log(window.myGlobal); // am i in window?
</script>

글로벌 변수를 정의하고 window의 속성으로 그대로 접근하여 출력하면 위처럼 출력된다.

객체의 속성에 접근하는 방법에서 배열의 인덱스처럼 사용해서 접근하는 방식이 가능하다는 것을 떠올리면, window객체의 효율성은 매우 높아질 것이다.

 

글로벌 변수 접근 방법

<script>
    var myGlobal = "am i window?";
    var myVariableName = "myGlobal";
    
    console.log("1. " + myGlobal); // 1. am i window?
    console.log("2. " + window.myGlobal); // 2. am i window?
    console.log("3. " + window["myGlobal"]); // 3. am i window?
    console.log("4. " + window[myVariableName]); // 4. am i window?
</script>

이렇게 서로 다른 접근 방식을 응용하면, 다른 것보다도 eval()함수를 사용할 수 밖에 없던 사황에서도 굳이 eval()함수를 사용하지 않아도 된다.

 

글로벌 변수를 이용한 단순 반복 처리 예

<script>
    var button1 = document.getElementById("button1");
    button1.dosomething = "Do something same with many buttons, Clicked button1";

    var button2 = document.getElementById("button2");
    button2.dosomething = "Do something same with many buttons, Clicked button2";

    var button3 = document.getElementById("button3");
    button3.dosomething = "Do something same with many buttons, Clicked button3";

    var button4 = document.getElementById("button4");
    button4.dosomething = "Do something same with many buttons, Clicked button4";
</script>

 

window객체를 이용한 처리 방안

<script>
    var i;
    for(i = 1; i < 5; i++) {
        window["button" + i] = document.getElementById("button" + i);
        window["button" + i].dosomething = "Do something " + i;
    }
</script>

 

window객체를 통한 글로벌 함수 호출

<script>
    function myGlobalFunction() {
        alert("Global function invoked");
    }

    window["myGlobalFunction"]();
    window["myGlobalFunction"].call();
</script>

이렇게 일반적인 글로벌 함수로 정의한 함수에도 접근할 수 있으므로, 조건에 따라 서로 다른 함수에 접근해야 할 때 유용하게 사용 가능하다.

글로벌 변수로 선언한 변수들이 window객체의 속성으로 들어가 있는 것을 확인할 수 있고, 반대로 window객체의 속성으로 변수나 함수를 선언하면, 글로벌 변수나 함수가 되므로 양방향으로 요긴하게 사용할 수 있다.

 

window객체를 통한 글로벌 함수 정의

<script>
    (function() {
        window.myGlobalFunction = function() {
            alert("Global function");
        }
    }());

    myGlobalFunction();
    myGlobalFunction.call();
</script>

 

반응형
반응형

글로벌 변수 정의

글로벌 변수는 선언하면 어디서든지 접근할 수 있는 변수이다.

 

글로벌 변수의 예

<script>
	var myGlobal = "This is a global variable";
</script>

이렇게 별 처리 없이 script안에 var를 쓰면 글로벌 변수가 지정된다.

 

글로벌 변수로 인한 오작동의 예

<script>
    function add() {
    	sum = 0;
        for(i = 0; i < 11; i++) {
        	sum = sum + i;
        }
        return sum;
    }
    
    sum = 0;
    for(i = 0; i < 10; i++) {
    	sum = sum + add();
    }
    
    console.log(sum);
</script>

위 코드에서 add()함수의 sum과 i는 글로벌 변수이다. 즉 add()함수 안에 있는 i와 sum은 글로벌 영역에 있는 변수들을 참조한다.

이는 함수 외부에 있는 루프에도 영향을 미치기 때문에, add()함수가 처음 호출될 때 글로벌 변수인 i의 값은 11이 된다.

따라서 위 로직은 결과적으로 한 번밖에 실행되지 않았기 때문에 550이 아닌 55라는 결과가 출력된다.

 

var를 쓰지않아서 글로벌 변수가 되었다고 생각할 수도 있다.

var키워드를 쓰지 않으면 현재보다 상위의 스코프를 탐색하면서 sum변수가 있는지 검사하는 단계를 반복해서 거치게 된다. 이러한 검사가 글로벌 영역까지 다다라서 그곳에도 변수가 정의되어 있지 않다면, 그때 비로소 글로벌 영역에 변수를 정의한다.

 

var키워드를 사용하지 않는 변수 접근의 예

<script>
    var getVariable = "global";
    (function() {
    	var getVariable = "immediate function";
        insideFunction();
        console.log("2. Immediate function: " + getVariable); // Immediate function: Will I be Global?
        
        function insideFunction() {
        	console.log("1. Inside function: " + getVariable); // Inside function: immediate function
            getVariable = "Will I be Global?";
        }
    }());
    
    console.log("3. Global: " + getVariable); // Global: global
</script>

insideFunction내부에서 getVariable변수를 var키워드 없이 사용하고 있지만, 글로벌 변수 getVariable에 설정한 "global"이 출력되지 않고 클로저 안에서 정의한 "immediate function"값이 출력된다. 

또한, getVariable변수를 설정했지만, 글로벌 변수인 getVariable까지 도달하지 않았다. 따라서 var키워드 없이 변수를 사용하면 글로벌 변수라는 말은 정확하게 보면 특정 상황에서만 맞고 자바스크립트를 활용하는 많은 상황에서는 틀린말이 되는 것을 알수가 있다.

 

 

반응형
반응형

글로벌 변수

글로벌 변수는 함수 외부에서 선언된 변수로, 프로그램 전체에서 접근할 수 있는 변수이다.

 

글로벌 변수의 예

1번. 기본

// 기본
<div id="div">DIV</div>
<button id="button">BUTTON</button>

 

// 글로벌 변수 예
<script>
    var element = document.getElementById('div');
    insertHTML = '<b>Hello World</b>';
    
    element.innerHTML = inserHTML;
</script>

 

2번. 이벤트 핸들러 할당

<script>
    var element = document.getElementById("div"),
    button = document.getElementById("button"),
    insertHTML = "<b>Hello World</b>";

    button.onclick = function() {
        element.innerHTML = insertHTML;
    };
</script>

 

3번. 글로벌 변수를 사용하여 AJAX를 활용

<script>
    var element = document.getElementById("div"),
    insertHTML = "<b>Hello World</b>";
    xhr = new XMLHttpRequest();
    button.onclick = function() {
        xhr.open("GET", "http://shiro21.tistory.com/");
        xhr.onreadystatechange = function() {
            if(xhr.readyState === 4 && xhr.status === 200) {
                element.innerHTML = xhr.responseText;
            }
        };
        xhr.send();
    };
</script>

 

글로벌 변수를 자제해야 하는 이유

  • 브라우저에서 돌아가는 모든 소스와 데이터는 클라이언트 측에서 돌아가므로 해킹이나 보안에 취약할 수 있다.
  • 다른 라이브러리를 사용하거나, 큰 프로젝트로 소스를 나누어서 관리할 때 충돌이 일어날 수 있다.

 

클로저를 활용하여 로컬 변수를 활용

<div id="wrapper">
    <div data-cb="1">Click DIV</div>
    <div data-cb="2">Click IMG</div>
    <div data-cb="delete">delete</div>
</div>
<div id="appendDiv"></div>
<script>
    (function() {
        var appendDiv = document.getElementById("appendDiv"),
        callback = {
            "1": (function() {
                var div = document.createElement("div");
                div.innerHTML = "#1";
                return function() {
                    return div.cloneNode(true);
                };
            }()),
            "2": (function() {
                var img = document.createElement("img");
                img.src = "https://via.placeholder.com/100x100";
                return function() {
                    return img.cloneNode(true);
                };
            }()),
            "delete": function() {
                appendDiv.innerHTML = "";
            }
        };

        function append(e) {
            var target = e.target || e.srcElement || event.srcElement,
            callbackFunction = callback[target.getAttribute("data-cb")];
            appendDiv.appendChild(callbackFunction());
        }
        document.getElementById("wrapper").addEventListener("click", append);
    }());
</script>

 

이렇게 간단한 변수명들은 쉽게 다른 코드와 충돌할 수 있기 때문에 보호해 주는 것이 좋다.

반응형
반응형

new String과 String

기본형의 형태를 알아보는 연산자 : typeof

객체에 대해 어떤 객체인지 확인하는 연산자 : instanceof

 

instanceof연산자는 typeof와는 달리 이항 연산자로 인자를 2개 받으며, 왼쪽에 받는 인자가 오른쪽에 받는 인자의 인스턴스인지 확인하고, 결과로 true 또는 false를 반환한다.

즉, 변수가 해당 클래스의 인스턴스인지 확인한느 키워드이다.

 

new를 통한 객체 생성

<script>
   function Person(name, blog) {
       this.name = name;
       this.blog = blog;
   }
   var unikys = new Person("unikys", "https://shiro21.tistory.com");
 
   console.log(unikys instanceof Person); // true
   console.log(typeof unikys); // object
</script>

instanceof의 연산결과로 unikys객체가 생성자인 Person을 통해서 생성되었고, Person은 object를 확장하고 있다는 것을 확인할 수 있다.

그리고 typeof의 결과로는 object를 반환한다는 것을 확인할 수 있다. 

이렇게 두 연산자의 동작은 유사해 보이지만 차이가 있다.

instanceof연산자는 기본형에 대해 동작하지 않는다는 점이다.

 

기본적인 instanceof 결과

<script>
   console.log(true instanceof Boolean); // false
   console.log(true instanceof Object); // false
 
   console.log([0, 1] instanceof Array); // true
   console.log({name:"shiro"} instanceof Object); // true
 
   var color1 = new String("red");
   var color2 = "red";
 
   console.log(color1 == color2); // true
   console.log(color1 instanceof String); // true
   console.log(color2 instanceof String); // false
   console.log(color2 instanceof Object); // false
 
   console.log(color1 === color2); // false
   console.log(color1.constructor === String); // true
   console.log(color2.constructor === String); // true
</script>

true or false같은 값은 기본형이기 때문에 Boolean객체의 instanceof가 false로 나타난다.

하지만 [ ]처럼 배열을 생성하는 표현식은 내부적으로 new Array()와 같은 동작을 하게 되므로 instanceof Array가 true이다.

 

String관련 객체와 기본형을 봤을때 ==로 비교하면 true이다. 

그런데 new String()으로 생성한 문자열은 instanceof String이 true지만, 그냥 큰따옴표로 생성한 문자열은 false다. 이것으로 문자열이 같은지 ==연산자로 비교하면 true로 서로 같은 값이라는 결과가 나오지만, 내부적으로 보면 서로 다르다는 것을 알 수 있다.

그래서 ===연산자로 비교를 하면 false를 반환한다.

==연산자는 두 피연산자가 다른 형태일 때 대부분 비교를 위해 형변환이 일어나서 같은 값으로 판단하지만, ===연산자는 형변환이 일어나지 않는 엄격한 비교를 수행하여 다른 값으로 판단하기 때문이다.

따라서, color1은 String의 인스턴스이고, color2는 기본형이므로 서로가 다르다는 결과를 알 수 있다.

 

반응형
반응형

자바스크립트의 변수

자바스크립트는 객체를 기반으로 이루어진 언어이다. 기본형 변수들을 제외하면 모든 객체는 Object를 확장하는 형태를 취하며, 모든 함수는 내부적으로 Object를 사용하고 있다. 따라서 자바스크립트에서 변수는 함수를 포함한 모든 종류의 객체를 자유롭게 받아서 처리할 수 있다.

 

자바스크립트의 기본형

 

  • Number(숫자)
  • String(문자)
  • Boolean(이진 값)
  • undefined
  • null
  • symbol

 

연산자 typeof

  • typeof

 

typeof란 ?

특정 변수가 어떤 형태인지 확인하는 연산자. 입력값 하나를 받는 단항 연산자로, 함수가 아니라서 괄호 없이 사용된다.

EX : typeof myVariable;

반환값 의미
undefined 정의되지 않은 값 또는 해당 값을 가진 변수
Boolean true / false값 또는 해당 값을 가진 변수
Number 숫자 값 또는 해당 값을 가진 변수
String 문자열 값 또는 해당 값을 가진 변수
Object 객체 또는 해당 값을 가진 변수
function 함수 또는 해당 값을 가진 변수
symbol Symbol()함수로 생성한 키

 

표현식에 따른 변수형

<script>
    console.log(typeof 3); // number
    console.log(typeof "string"); // string
    console.log(typeof {}); // object
    console.log(typeof []); // object
    console.log(typeof function() {});  // function
    console.log(typeof null); // object
</script>

 

 

typeof연산자가 값을 구하는 순서

:: typeof 연산자 문법 = typeof 단항표현식

  1. val은 typeof연산자에 입력된 단항표현식의 값
  2. 만약 val의 종류가 레퍼런스(Reference)라면
    a. 만약 val의 레퍼런스를 참조할 수 없으면 'undefined'반환
  3. val값을 실제 값 또는 참조하는 값으로 설정

 

반응형
반응형

클로저 실제 활용 예

:: 클로저를 가장 많이 사용하는 것은 자바스크립트 라이브러리나 모듈에서 private으로 나의 변수를 보호하고 싶을 때나 static변수를 이용하고 싶을 때이다. 그리고 일상적으로 콜백 함수에 추가적인 값들을 넘겨줘서 활용하거나 처음에 초기화했던 값을 계속 유지하고 싶을 때도 유용하게 사용할 수 있다.

 

아래 코드는 div에 버튼이 눌릴때마다 다른 내용을 추가하는 코드이다.

:: Add div를 누르면 text가 적혀있는 div가 생성되고 Add img를 누르면 이미지가 추가된다.

<div id="wrapper">
    <button data-cb="1">Add div</button>
    <button data-cb="2">Add img</button>
    <button data-cb="delete">Clear</button>
    Adding below...<br />
    <div id="appendDiv"></div>
</div>

 


<script>
    (function() {
        var appendDiv = document.getElementById("appendDiv");
        document.getElementById("wrapper").addEventListener("click", append);

        function append(e) {
            var target = e.target || e.srcElement || event.srcElement;
            var callbackFunction = callback[target.getAttribute("data-cb")];

            if(callback[target.getAttribute("data-cb")] !== undefined) {
                appendDiv.appendChild(callbackFunction());
            }
        };
        var callback = {
            "1": (function() {
                var div = document.createElement("div");
                div.innerHTML = "Adding new div";
                return function() {
                    return div.cloneNode(true);
                }
            }()),
            "2": (function() {
                var img = document.createElement("img");
                img.src="https://blog.kakaocdn.net/dna/dZtolT/btryJh3q8bc/AAAAAAAAAAAAAAAAAAAAAEf6AotcjC2-sZUo3ZBpReFYxTqq4dLXk8Jp036Vcqbe/tfile.svg?credential=yqXZFxpELC7KVnFOS48ylbz2pIh7yKj8&expires=1759244399&allow_ip=&allow_referer=&signature=QBbvbd2rFIHPmOAbqu4PWvqgpAI%3D";
                return function() {
                    return img.cloneNode(true);
                }
            }()),
            "delete": function() {
                appendDiv.innerHTML = "";
                return document.createTextNode("Cleared");
            }
        };
    }());
</script>

 

클로저를 활용한 부분들

var appendDiv = document.getElementById("appendDiv");

appendDiv를 미리 가져와서 한번의 초기화만으로 이후 함수들이 계속 접근이 가능하게 해준다.

var div = document.createElement("div");

var img = document.createElement("img");

 

각 콜백 함수들이 추가할 HTML엘리먼트를 만들어준다.

 

위 코드에서 어떤 버튼이 눌리는지는 DOM에 입력된 data-*속성을 이용해서 어떤 콜백 함수를 호출할지 결정해준다. 각 콜백 함수의 상위 클로저에서는 자바스크립트로 노드를 만들어뒀다가 콜백 함수가 호출되면 해당 노드를 복사해 appendDiv에 지속해서 추가하는 방식으로 동작한다.

 

이렇게 최초 초기화된 고정적인 값이나 변수를 자주 이용하는 경우, 클로저를 통해 최초 초기화해두고 콜백 함수에서 지속해서 참조하는 것이 퍼포먼스상 유리하게 작용할 수 있으며, 객체의 속성이 자유롭고 쉬운 자바스크립트에서는 이러한 디자인 패턴이 효율적이다.




위 코드에서 참고하고 활용할 수 있는 예들

  • 클로저로 한 번만 DOM을 탐색하고 appendDiv를 계속 보관하여 활용하기
  • div, img등 노드/템플릿을 자바스크립트로 만들어두고 필요할 때마다 복제 생성하여 활용하기
  • 하나의 div에만 이벤트 핸들러를 설정하여 관리할 수 있는 이벤트 델리게이션 패턴
  • 이벤트가 발생한 대상 엘리먼트를 크로스 브라우저에서 가져오기
  • callback변수를 활용하여 대상에 따라 동적으로 콜백 함수 호출하기
  • HTML5의 스펙에 맞는 사용자 정의 data-속성 사용하기

 

반응형

+ Recent posts