반응형

Prototype이란 ?

프로토타입은 사전적 의미로 '원형'이다. 이 말을 그대로 자바스크립트에 투영해서 무엇의 원형을 나타내는지 생각하면 된다.

 

Javascript에서의 객체 생성

자바스크립트가 채택하고 있는 자바의 몇 가지 문법 중 대표적인 것은 new키워드이다. new키워드는 ECMAScript6 이전에 class키워드가 없었던 자바스크립트 문법에는 적합하지 않아서, 자바와 조금 다른 방식으로 채택하고있다. 자바에서는 class를 정의하지만, 자바스크립트에서는 function을 정의한다. 

 

Function을 통한 new키워드 활용

function Person(name, blog) {
    this.name = name;
    this.blog = blog;
}

var shiro = new Person("shiro21", "shiro21.tistory.com");
alert(shiro.name);

 

위 코드를 객체지향 관점에서 봤을때, 자바스크립트에서 function은 자바의 class와 생성자를 합쳐놓은 개념이다.

객체를 생성할 때 function을 사용하는 방식은 다른 언어와 많은 차이가 있다. 따라서 ECMAScript6에서는 다른 언어와의 이질감을 줄이고, 객체지향을 조금이라도 더 지원하기 위해 class키워드를 새로 만들기도 했다.

 

class를 이용한 new키워드 활용

class Person {
    constructor(name, blog) {
        this.name = name;
        this.blog = blog;
    }
}

var shiro = new Person("shiro21", "shiro21.tistory.com");
alert(shiro.name);

class키워드를 이용하면 자바 등의 다른 객체지향 언어와 유사하게 클래스를 정의할 수 있다. 그런데 class키워드를 사용하면 내부적으로 특수한 function으로 정의한다는 점이다. 

아래를보면 class Person의 내부 정의를 function Person정의와 다르게 하고 있는 것을 확인할 수 있다.

class키워드가 function과 다른 점은 함수처럼 바로 실행하면 에러가 발생한다는 점이다. 그리고 함수 정의와는 다르게 현재 스코프에 진입했을 때 바로 사용할 수 있는 것이 아니라, 해당 class키워드로 클래스를 선언하는 소스가 실행되고 난 이후에 객체를 생성할 수 있다.

 

this에 대하여

앞 코드에서 function을 이용한 new키워드를 보면 생성자 함수 안에 this를 통해 객체를 초기화하고 있는 것을 확인할 수 있다. 일반적인 객체지향 프로그래밍 언어의 관점에서 보면 당연한 표현이지만, 자바스크립트에서의 this는 조금 다르게 동작하는 경우가 많다.

 

함수를 호출하는 방법

  1. 일반 함수로의 호출
  2. 멤버함수로의 호출
  3. call()함수를 이용한 호출
  4. apply()함수를 이용한 호출

 

일반적인 함수 호출 예

function say(something) {
    alert(something);
}

say("Hello World");

 

멤버함수 호출 예 :: 객체의 속성으로 함수를 호출 ( 함수가 객체의 멤버변수로 설정되었을때 호출하는 방법 )

    var shiro = {
        say: function(member) {
            alert(member);
        }
    };

    shiro.say("shiro");

 

call()과 apply()를 이용한 함수 호출 예 :: function객체의 기본 함수이므로 앞의 일반 함수를 호출 할 때 동일하게 호출

function say(something) {
    alert(something);
}

say.call(undefined, "Hello World");
say.apply(undefined, ["Hello World !!"]);

call()과 apply()함수의 차이는 함수로 넘겨줄 인자를 따로따로 넘겨주느냐, 배열로 넘겨주느냐의 차이만 있고 나머지는 크게 다르지 않다.

 

함수 호출 방법에 따른 this의 변화

    function whatsThis() {
        return this.toString();
    }

    var shiro = {
        what: whatsThis,
        toString: function() {
            return "[object shiro]";
        }
    };

    console.log(whatsThis());
    console.log(shiro.what());
    console.log(whatsThis.call());
    console.log(whatsThis.apply(shiro));

    console.log(shiro.what.call(undefined));
    console.log(shiro.what.call(shiro));

 

아래는 각 호출 방법에 따른 결과이다.

 

  1. 일반함수: this = window
  2. 멤버함수: this = shiro
  3. call, 인자없음: this = window
  4. apply, 첫번째 인자 shiro: this = shiro
  5. 멤버함수 call, 인자없음: this = window
  6. 멤버함수 call, 첫번째 인자 shiro: this = shiro

결과를 보면 1번은 일반적으로 함수가 호출될 때 내부적으로 call()함수로 변형되어서 처리되는데, 이때 call()함수의 첫번째 인자를 undefined로 넘겨주어 this의 기본값으로 window가 들어가게 된다.

따라서 call()이나 apply()함수를 이용한 함수 호출에서는 첫 번째 인자로 설정한 객체가 this로 설정되며, 인자가 넘어가지 않을 때는 일반 함수 호출과 같이 글로벌 객체인 window가 this로 설정된다.

 

2번은 같은 멤버함수 호출인 경우에는 내부적으로 call()함수를 호출할 때 첫번째 인자로 멤버함수를 보유한 객체를 넘겨준다. 2번 예에서는 첫번째 인자로 shiro가 넘어가기 때문에 this는 shiro가 된다.

하지만 같은 함수라도 멤버함수가 호출되는 방법이 다르면 this는 또 변경된다.

 

멤버함수를 다른 방법으로 호출하는 예

var newWhat = shiro.what;

console.log(newWhat()); // [object window]

이렇게 this는 함수나 스코프 기반으로 결정되는 것이 아닌 호출방법에 따라 변경된다.

반응형
반응형

상위 스코프 체인의 변수를 사용하는 일반적인 예

HTML

<div id="divMouseover">Mouse over Highlight</div>
<div id="divFloatingContent">Floating</div>

JS

(function() {
    var divMouseover = document.getElementById("divMouseover"),
        divFloatingContent = document.getElementById("divFloatingContent");
    
    divMouseover.onmouseover = function() {
        var xhr = new XMLHttpRequest();
        divMouseover.style.backgroundColor = "#FF0000";
        divMouseover.style.color = "white";
        divMouseover.style.fontSize = "14px";
        xhr.open("GET", "../myweb/pages/test.php");
        xhr.onload = function() {
            divFloatingContent.innerHTML = xhr.responseText;
            divFloatingContent.style.display = "block";
        };
        xhr.send();
    };
    divMouseover.onmouseout = function() {
        divMouseover.style.backgroundColor = "#FFFFFF";
        divMouseover.style.color = "black";
        divMouseover.style.fontSize = "12px";
        divFloatingContent.style.display = "none";
    };
}());

위 코드는 특정 div에 마우스포인터가 놓이면 해당 div의 스타일을 바꾸고, 관련 내용을 AJAX로 서버에 요청해서 보여주는 코드이다.

 

상위 스코프 체인의 변수를 로컬 변수로 정의하여 사용하는 예

(function() {
    var divMouseover = document.getElementById("divMouseover"),
        divFloatingContent = document.getElementById("divFloatingContent");
    
    divMouseover.onmouseover = function() {
        var xhr = new XMLHttpRequest(), localDivMouseover = divMouseover;
        localDivMouseover.style.backgroundColor = "#FF0000";
        localDivMouseover.style.color = "white";
        localDivMouseover.style.fontSize = "14px";
        xhr.open("GET", "../myweb/pages/test.php");
        xhr.onload = function() {
            var localDivFloatingContent = divFloatingContent;
            localDivFloatingContent.innerHTML = xhr.responseText;
            localDivFloatingContent.style.display = "block";
        };
        xhr.send();
    };
    divMouseover.onmouseout = function() {
        var localDivMouseover = divMouseover
        localDivMouseover.style.backgroundColor = "#FFFFFF";
        localDivMouseover.style.color = "black";
        localDivMouseover.style.fontSize = "12px";
        divFloatingContent.style.display = "none";
    };
}());

로컬 변수로 정의해서 사용하면 변수를 여러 번 조회하지 않고 한 번만 조회하고, 나머지는 전부 다 로컬 변수를 조회한다.

이처럼 변수가 별로 없는 상황에서도 로컬 변수에 접근하는 것이 약 4 ~ 6%정도 더 좋게 나타난다.

 

이러한 스코프와 마찬가지로, 변수 속성 또한 한 단계를 들어갈 때마다 컴퓨팅 자원이 조금씩 소모된다. 따라서 이 또한 마찬가지로 로컬 변수로 끌어올 수 있다면 로컬 변수로 정의하여 사용하는 것이 좋다. 위에서는 .style과 같이 접근하는 것들이 그러한 예이다.

(function() {
    var divMouseover = document.getElementById("divMouseover"),
        divFloatingContent = document.getElementById("divFloatingContent");
    
    divMouseover.onmouseover = function() {
        var xhr = new XMLHttpRequest(),
        divMouseoverStyle = divMouseover.style;

        divMouseoverStyle.backgroundColor = "#FF0000";
        divMouseoverStyle.color = "white";
        divMouseoverStyle.fontSize = "14px";
        xhr.open("GET", "../myweb/pages/test.php");
        xhr.onload = function() {
            var localDivFloatingContent = divFloatingContent;
            localDivFloatingContent.innerHTML = xhr.responseText;
            localDivFloatingContent.style.display = "block";
        };
        xhr.send();
    };
    divMouseover.onmouseout = function() {
        var divMouseoverStyle = divMouseover.style
        divMouseoverStyle.backgroundColor = "#FFFFFF";
        divMouseoverStyle.color = "black";
        divMouseoverStyle.fontSize = "12px";
        divFloatingContent.style.display = "none";
    };
}());

이전 코드처럼 divMouseover.style에 여러번 접근하는 것이 아닌 처음부터 divMouseover.style을 변수에 할당하여 접근하면, 객체의 속성을 재귀로 탐색하는 단계를 생략할 수 있어서 성능을 개선할 수 있다.

 

정리

  • 자바스크립트도 다른 프로그래밍 언어처럼 글로벌 변수의 사용은 자제하는 것이 좋다.
  • window객체는 글로벌 스코프의 변수들을 속성으로 가지고 있다.
  • var키워드를 사용하지 않고 변수를 사용하면 글로벌 변수가 될 위험성이 있다.
  • 스코프가 생성되면 var키워드 하나에 변수들을 정의하면 좋다.
  • 글로벌 변수의 사용을 최소화하기 위해 클로저나 모듈 패턴을 사용하면 된다.
  • 상위 스코프에 있는 변수나 속성의 속성을 여러번 접근하는 경우 로컬 변수에 할당해서 사용하면 좋다.

 

반응형
반응형

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값을 실제 값 또는 참조하는 값으로 설정

 

반응형

+ Recent posts