반응형

프론트쪽을 개발하다가 최근에 버그를 발견하고 포스팅 남겨본다.

            var endDate = new Date(date).getTime();
            var now = new Date().getTime();
            var diff = parseInt((endDate-now)/(24*3600*1000));

            //if ((!Object.is(diff, -0)) && (diff <= 7)) {  => 이게 맞는방식
            if ((diff >= 0) && (diff <= 7)) {   => 버그 생성 방식
                return true;
            } else {
                return false;
            }

위의 코드는 두 날짜를 비교하는 코드이다.

diff는 두 날짜의 차이를 숫자로 나타내 주는데 현재 날짜가 endDate보다 크다면 -0을 반환하게 된다.

만약 위와 같이 diff가 0보다 클 경우라고 조건을 주게 되면 -0일 경우 포함이 안될거라고 생각하지만....그렇게 생각한다면 경기도 오산이다.

자바스크립트에서는 다음과 같이 0과 -0이 같다고 생각한다.

따라서 값을 비교할 때는 위의 코드에서 주석처리된 것과 같이 처리해주어야 한다.

 

자세한 설명은 아래의 stackoverflow의 글을 참고하도록 하자

stackoverflow.com/questions/7223359/are-0-and-0-the-same

 

Are +0 and -0 the same?

Reading through the ECMAScript 5.1 specification, +0 and -0 are distinguished. Why then does +0 === -0 evaluate to true?

stackoverflow.com

 

반응형
반응형

객체를 복사 할 때 단순하게 '=' 연산자로 값을 주입하게 되면 얕은복사(Shallow Clone)가 이루어진다.

예를 들어, a객체가 있고 b 객체가 있을 때 b=a라고 주입하고 a 값을 변경하여도 우리는 b는 기존 a값을 가지고 있을거라 생각한다.

하지만 b도 변경된 a값과 동일하게 변경되게 된다.

따라서 자바스크립트에서 객체의 값을 복사할 때는 깊은 복사(Deep Clone)이 되도록 해주어야 한다.

b = JSON.parse(JSON.stringify(a))

와 같이 JSON 객체의 메소드를 이용하여 깊은 복사가 되게끔 해주자.

JSON.stringify는 자바스크립트 객체를 먼저 JSON문자열로 변환시키고 JSON.parse는 JSON문자열을 자바스크립트 객체로 변환시킨다.

JSON문자열로 변환했다가 다시 객체로 변환하기에 기존 객체에 대한 참조가 사라져 깊은 복사가 이루어지게 된다.

반응형
반응형

자바스크립트로 날짜 처리를 하다가 처음 알게 된 사실이 있어 포스팅 해본다.

var date = new Date();
//Fri Sep 25 2020 17:08:38 GMT+0900 (대한민국 표준시) {}

var month = date.getMonth() 
// 당연히 month 는 9일거라고 예상하지만....8이나온다.

이유는 다음과 같다.

Definition and Usage
The getMonth() method returns the month (from 0 to 11) for the specified date, according to local time.
Note: January is 0, February is 1, and so on.

ref : www.w3schools.com/jsref/jsref_getmonth.asp

위의 문서를 보면 알겠지만 자바스크립트에서 getMonth는 0~11까지의 값을 반환한다.

다시말해 1월이면 0을 반환하고 2월이면 1을 반환하며 12월이면 11을 반환한다.

따라서 getMonth()로 달을 뽑아 사용할 때는 date.getMonth() + 1을 해주어야 정확한 값이 된다.

 

 

 

반응형
반응형

for passing Parent pass data to child, child component shoud set props and binding name 

Parents html

if (selectedId == i) is not exist, when click button, all modal will be open

 <tr v-for="(item, i) in adList">
     <td>{{ item.id }}</td>
     <td>{{ item.adName }}</td>
     <td><button type="button" class="btn btn-primary" @click="createAdParameterModal(item, i)">파라미터확인</button>
         <modal-ad-param-info v-if="selectedId == i && showAdParameterModal" :item="item" v-on:close="closeAdParameterModal"></modal-ad-param-info>
     </td>
</tr>

Method

        createAdParameterModal : function(index) {
            this.selectedId = index;
            this.showAdParameterModal = true;
        },

 

Modal(modal-ad-param-info) props : item (in html code binding name)

let createAdParameterModalTpml = `
    <div class="modal_wrapper requestRanking">
       <div class="modal_body">
            <div class="modal_contents">
                <div>
                    <span v-for="datasource in item.dataSourceNames">{{ datasource }}<br></span>
                </div>
                <button class="btn btn-outline-danger" @click="closeModal">닫기</button>
            </div>
       </div>
    </div>
`;

export default {
    template: createAdParameterModalTpml,
    props: ['item'],
    methods: {
        closeModal: function () {
            this.$emit('close');
        }
    }
};

vue.js(vuejs) v-for안에서 modal창 띄우다가....삽질을 너무 마니해서 기록해본다.

반응형
반응형

[ Javascript ] 자바스크립트 ajax 크로스도메인 이슈(CORS)

특정 서버의 API를 테스트해야하는 페이지를 작업중 크로스도메인 이슈에 맞닥뜨리게 되었다.
예전 고객센터시스템 개발할 때 자주접하던 이슈였기에 쉽게 해결할 수 있을 줄 알았으나....꽤나 삽질을 많이 했다.
그래서 겸사겸사 정리하며 다시 한 번 머리에 각인!

1. 크로스도메인이슈 (CORS, Cross Origin Resources Sharing)

jQuery 1.5.0이후 버전부터는 이러한 crossdomain을 원천 봉쇄해버렸다.
테스트페이지(웹) -> 쿠키매칭시스템API호출
 http://alpha-adserver.toast.com/ -> http://cm-exchange.toast.com

크로스 도메인은 서로 다른 도메인 간 호출로 위와 같이 호출하게되면 크로스도메인이슈가 발생하게 된다.
보통 서브도메인만 다른 경우의 사이트끼리의 정보 교환은 document.domain만 맞추어 주면 해결이 가능하다.
ex)
1. abc.toast.com
2. def.toast.com
사이트끼리의 정보 교환은 해당페이지 스크립트에 document.domain='toast.com' 설정시 해결가능

하지만 이번 경우에는 브라우져 -> 서버간의 호출로 다음과 같은 문제로 해결이 힘든 상황.
따라서 javascript, ajax로 요청시 다음과 같은 에러가 발생
스크린샷 2018-07-25 오후 5.16.21.png
이렇게 외부로 요청이 안되는 것은 자바스크립트 엔진 표준 스펙의 동일 출처 정책(SOP, Same-Origin Policy)이라는 보안 규칙이 있기 때문


2. 동일 출처 정책 (SOP, Same-Origin Policy)

웹어플리케이션 보안 모델에서 중요한 개념중 하나
해당 정책으로 인해 자바스크립트(XMLHttpRequest)로 다른 웹페이지 접근시 같은 출처(same origin)의 페이지에만 접근 가능하다.
같은 출처라는 것은 Protocol, Host명, Port가 같다는 것을 의미
쉽게 말해, 웹페이지의 스크립트는 그 페이지와 같은 서버에 있는 주소로만 ajax요청을 할 수 있다는 것이다.
스크린샷 2018-07-25 오후 5.19.29.png


3. CORS 작동 방식

스크린샷 2018-07-25 오후 5.21.56.png
Preflight request(사전요청) - 요청하려는 URL이 외부 도메인일 경우 웹 브라우저는 preflight요청을 먼저 날린다.
preflight요청은 실제로 요청하려는 경로와 같은 URL에 대해 OPTIONS 메서드로 요청을 미리 날려보고 요청 할 수 있는 권한이 있는지 확인한다.
CORS요청을 편법없이 처리하기 위해서는 클라이언트 처리만으로는 어렵고 서버측에서 preflight요청을 처리하는 기능이 필요하다.


4. CORS 해결할 수 있는 방법.

1) 웹 브라우저 실행옵션이나 플러그인인을 통한 동일출처 정책 회피(크롬 --disable-web-security옵션을 추가하여 실행)

-> 테스트하는 컴퓨터마다 설정해야하는 번거로움으로 X

2) jsonp(json with padding)를 통한 해결

JSONP는 HTML의 script 요소로부터 요청되는 호출에는 보안상 정책이 적용되지 않는다는 점을 이용한 우회 방법
다시 한번 확실히 하자면, script 요소는 src를 호출한 결과를 javascript를 불러와서 포함시키는 것이 아니고 실행시키는 태그입니다.

다음과 같이 dataType만 변경해서 보내면된다??? nono 서버에서 수정해줘야 함...(일반적인 웹사이트에서는 dataType만 jsonp로 고치면 된다는 식으로 말하고있음...)

$.ajax({
    type: 'GET',
    url: url,
    dataType: 'jsonp',   //cross-domain 이슈를 회피하기 위해 jsonp요청을 한다.
    success: callback    //callback이란 함수를 나의 success function에 매핑시켜 콜백요청을 처리할 것이다.
});

or

$.getJSON(url + "?callback=?", data, callback);</span>

RESPONSE의 경우
callback({'kingbbode', age:28})

이처럼 Callback 함수명으로 감싸져서 오는데 서버에서 위와같이 감싸진 형태의 Text로 내려주어야한다!!!!
Text로 내려진 데이터가 Javascript로 실행되는 과정을 Jquery에서 지원하여 Success 함수로 연결시켜 주는 것이다.

정확한 서버구현과 내용은 참고 : jsonp참고페이지

**-> 서버를 건드릴거면 Accss-Control-allow-origin만 설정해주는 것이 훨씬 간편... **

3) 중간에 proxy서버를 두는 방법

-> 배보다 배꼽이 더큰 상황...

4) jquery.ajaxPrefilter()

ajax요청전 내부적으로 $.ajaxPrefilter()를 거친다. 따라서 ajaxPrefilter()내부를 변조하면 cross-domain문제를 해결할 수 있다. 라는 느낌?
밑의 코드는 통신 자체를 'jsonp'로 속여 보내는 방식으로 처리가능하다고 하는데 나의 경우는 정상동작 안함...(http://igna.tistory.com/20?category=430584)

$.ajaxPrefilter('json', function(options, orig, jqXHR) {
    if (options.crossDomain && !$.support.cors) return 'jsonp'
});

$.ajax({
    type: 'GET',
    crossDomain: true,
    url: url,
    dataType: 'json',
    success: function(data, textStatus, xhr) {        $('#bidValue').val(JSON.stringify(data));
}});

5) 서버에서 Accss-Control-allow-origin 설정을 통한 요청 허용

API컨트롤러에 다음과 같은 애노테이션 선언
특정 도메인만 허용하고 싶은 경우에는 별도 config로 설정 후 사용
참고 : 스프링에서 cors설정

@CrossOrigin("*")

>> 결국에는 서버에 Accss-Control-allow-origin으로 특정 도메인을 풀어주는 것으로 해결

ref :  http://enterkey.tistory.com/409


반응형
반응형

[ jQquery ] jQuery(제이쿼리) 플러그인으로 쿠키 다루기


자바스크립트로도 쿠키를 control할 수 있으나~! jQuery Plugin을 이용하면 훨씬 더 직관적으로 쉽게


쿠키를 컨트롤 할 수 있다.


# 자바스크립트로 쿠키의 특정값을 가져오는 경우


# jQuery Plugin을 사용해서 쿠키 특정값을 가져오는 경우



위에서 보듯 자바스크립트를 이용할 때보다 jQyery를 이용하는 방법이 훨씬 직관적이면서 쉬운것을 볼 수 있다.



사용방법


* cdn으로 jquery.cookie.js를 import해준다. (당연히 jQuery는 import되어 있어야겠죠?) 소스코드를 받아 프로젝트에 내장하는걸 권장

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.js"></script>


위의 스크립트를 import해주면 플러그인의 기능을 손쉽게 사용할 수 있다.


[ 쿠키저장 ] - 쿠키는 브라우저가 열려 있는 동안만 유지

$.cookie('key', 'value');


[ 쿠키만료일 지정 ] 

$.cookie('key', 'value', {expires: 값});


[ 쿠키삭제 ] - 특정도메인이 있는 쿠키의 값인 경우 도메인을 명시해주지 않으면 제대로 삭제되지 않는다. 

* expires기간을 오늘 이전 날짜로 셋팅해주면 자동으로 지워진다.

* 쿠키 설정시 domain과 path를 설정했을 경우 삭제시에도 동일하게 옵션으로 전달해야 삭제가능

$.cookie('BID', '', {domain : "toast.com", expires: new Date(2016, 10, 29, 11, 00, 00)});

혹은 다음처롬도 삭제 가능하다.

$.removeCookie('BID', {path: '/',domain: 'toast.com'});


[ 특정시간만료시 삭제 & secure를 true로 설정시 https를 통해서만 쿠키값을 전송가능하다 ] 

$.cookie(visits, 10, {expires: new Date(2019, 10, 29, 11, 00, 00), secure: true});


자바스크립트를 사용하든 jQuery플러그인을 선택하든 선택은 자유:)

반응형
반응형

 



 자바스크립트를 처음 접하게 됬을 때 함수 표현식(밑에 설명)으로 선언된 함수를 보며 이건 뭐지? 하는 생각을 했었습니다. 자바스크립트는 함수를 정의하는 세 가지 방법이 있는데 이를 모르고 있다면 처음 접하셨을 때 많이 당황할 수 있습니다. 오늘은 자바스크립트에서 함수를 정의하는 방법과 함수를 호출하는 패턴 그리고 익명 함수에 대해 알아보도록 하겠습니다. 



1. 먼저 자바스크립트에서 함수란???

 자바스크립트에서 함수는 문장을 실행할 수 있는 고유한 스코프(scope)다. (scope에 대한 설명은 ver2 참고)

 자바스크립트에서 함수를 설명 할 때 "자바스크립트에서 함수는 first-class object(또는 citizen, value)다"는 정의를 알고 갈 필요가 있다. 대부분이 first-class object라는 단어에 대해 생소하실 텐데 여기서 말하는 first-class object는 다음과 같은 의미들을 포함합니다.


 1) first-class object는 변수에 저장할 수 있어야 한다.

 2) first-class object는 함수의 파라미터로 전달할 수 있어야 한다.

 3) first-class object는 함수의 반환값으로 사용할 수 있어야 한다.

 4) first-class object는 자료 구조에 저장할 수 있어야 한다.


 위와 같은 조건들을 충족시키는 객체를 first-class object라 하고 자바스크립트 함수를 의미합니다. 한 마디로 "자바스크립트에서 함수는 first-class object다"라고 생각하시면 될 것 같습니다. 이와 같이 자바스크립트에서 함수는 객체를 의미하고 함수는 변수, 배열, 객체에 저장될 수 있다는 뜻을 내포하고 있습니다. 또한 함수에 전달될 수도 함수에서 반환될 수도 있습니다. 



2. 함수를 정의하는 세 가지 방법  

  1 ) 함수 생성자 방식

 함수 생성자 방식은 함수 선언과 더불어 new 키워드를 통해 함수 객체를 생성하는 방법으로 마지막 매개변수는 함수의 로직(몸체 코드)부분을 의미하며, 그 외의 매개 변수는 인수가 됩니다.



 2 ) 함수 선언문 방식

 함수 선언문 방식은 우리가 주로 함수를 사용할 때 쓰는 방법으로 많이들 익숙하리라 생각 됩니다. 



 3 ) 함수 표현식 방식

 함수 표현식 방식은 변수를 선언하고 그 변수에 함수를 할당하고 있는 모습을 볼 수 있습니다. c나 c++, java와 같은 언어에서는 차마 볼 수 없는 광경입니다. 따라서 위의 함수를 선언하는 위의 세 가지 방법을 다 모르고 있을 경우 많이 당황하실 우려가 있습니다. 

저 코드를 실행하면 console.log를 통해 4, 4, 4가 찍히게 됩니다. 어떤 방식을 사용하든 문제는 없지만 함수 생성자 방식은 함수이 몸체 부분을 문자열로 작성해 주어야 되기 때문에 많이 불편하여 자주 사용되지 않는 편입니다. 



 3. 함수를 호출하는 네 가지 패턴

 함수는 다음과 같은 네 가지 시나리오나 패턴을 사용해 호출할 수 있습니다.

  1 ) 함수 패턴

 함수를 객체의 속성이 아닌 함수(fucntion)로서 호출할 때를 일컫는다.

 


  2 ) 메소드 패턴 

 함수를 객체의 속성(Property)에 저장하는 경우 이 함수를 메소드라고 부르고 이를 통해 함수를 호출하는 것을 메소드 패턴이라 한다. 


 3 ) 생성자 호출 패턴

 함수를 new라는 전치연산자와 함께 호출하는 것을 말한다. 생성자 호출 패턴을 사용하는 경우 호출한 함수의 prototype (자바스크립트에서 Function() 인스턴스를 만들 때 자바스크립트가 인스턴스에 부여하는, 이름이 "prototype"이고 기본값이 객체인 속성일 뿐이다. )속성의 값에 연결되는 (숨겨진)링크를 갖는 객체가 생성되고, 이 새로운 객체는 this에 바인딩된다.(자바스크립트의 prototype은 중요하므로 이에 대해서는 ver.4에서 포스팅하도록 하겠다) 


 console.log를 통해 찍히는 내용을 보자.




 4 ) apply()와 call() 패턴

 

 call()과 apply()의 차이점은 호출할 함수에 매개변수를 전달하는 방식이다. apply()는 배열방식으로 매개변수를 전달한다.



 4. 익명 함수

 익명 함수(anonymous function)란 이름이 없는 함수를 뜻한다. 익명 함수는 대부분 다른 함수에 매개변수로서 전달되는 경우가 많다.



 #다른 프로그래밍 언어와 달리 자바스크립트에서는 매개변수를 생략햐도 아무런 문제가 없다. 심지어 함수 선언 시 매개변수를 정의한 경우에도 문제가 없다. 전달하지 않은 인수에는 undefined 값이 저장된다. 물론, 인수를 전달하지 않으면 함수 내의 코드가 올바르게 동작하지 않을 수 있다.


 # 반대로 추가 매개변수(함수 선언 시 정의하지 않은 매개변수)를 함수에 전달해도 에러가 발생하지 않는다. 추가로 전달한 매개변수는 함수에 자동으로 추가되는 arguments 객체(함수로 전달된 매개변수를 저장하고 있는 배열 비슷한 객체)를 통해 접근할 수 있다.  



참조 

자바스크립트를 깨우치다 - 코디 린들리



 


반응형
반응형

 

 저번 포스팅에서 자바스크립트 언어의 특징을 시작으로 가장 기본적이면서도 중요한 내용들에 대해 알아보았다. (참고, [자바스크립트]자바스크립트 이것만은 꼭 알고가자(Part 1)) 이번 두번 째 자바스크립트 포스팅에서는 자바스크립트에서의 Scope와 Hoisting, Scope Chain, Closure에 대해 정리해보도록 하겠습니다.. 포스팅 내용중에 잘못된 부분이 있거나 개선할 점이 있다면 댓글로 의견 남겨주시면 감사하겠습니다.



1. 자바스크립트에서의 Scope는???

 스코프(Scope)란 범위를 뜻하는 단어로서 자바스크립트에서 변수의 종류에 따라 어느 범위까지 참조가 가능한지에 대한 의미쯤으로 생각하면 되겠다. 크게 전역 스코프(global scope), 지역 스코프(local scope, "함수 스코프"라고도 불림)로 구분된다. 



 1) 전역 스코프(global scope)란 말 그대로 global 영역에 선언된 전역변수가 스크립트 내의 모든 구간에서 사용될 수 있음을 의미한다. 밑의 그림을 보자.

 

 그림을 보면 먼저 글로벌 전역 변수를 선언한 것을 볼 수 있다. var global = 1로 설정한 값은 해당 스크립트의 어떤 영역에서도 사용이 가능하다. 물론 함수안에서도 전역변수를 사용할 수 있는 것을 예제를 통해 알 수 있다. console.log()로 값을 찍어 보면 선언하고 나서 찍었을 때와 함수에서 글로벌 전역변수를 리턴해주는 값 모두 처음 값을 지정해주었던 "1" 이 찍히는 것을 알 수 있다. (참고로 자바스크립트에서는 변수를 선언할 때 타입을 지정하지 않는다. 변수를 사용할 때 무슨 타입이든 var를 사용한다. 또한 변수를 선언할 때 'var'를 입력하지 않으면 전역변수로 인식하기 때문에 전역변수든 지역변수든 모두 'var'를 붙여 일관성을 부여하도록 하자. 밑의 '5)'설명 참고) 





 2) 지역 스코프(local scope, "함수스코프")란 쉽게 말해 해당 함수안에서만 접근가능한 private variable을의미한다. 즉 함수 내에서 var를 사용해 정의된 코드는 지역 스코프에서만 유효하고 해당 함수 내에서 정의된 중첩 또는 자식 함수를 비롯해 해당 함수 내부에서만 사용 가능하다. 

 

 그림을 보면 test()함수안에서 선언된 'local'이라는 지역변수는 함수 외부 {} 밖에서는 그 변수의 유효범위가 끝나버리기 때문에 접근할 수 없는 것을 볼 수 있다. 





 3) 전역변수와 지역변수를 동일한 이름으로 사용하게 되면 어떻게 될까???

 그럼 만약에 전역변수와 지역변수를 동일한 이름으로 사용했을 경우 어떤 문제가 발생할 수 있을까? 자바스크립트에서는 전역 변수 영역에 선언된 변수와 동일한 이름의 지역변수를 사용할 수 있다. 예를 보자.

 

 그림에서 보면 전역변수와 지역변수를 동일한 이름으로 사용을 했을 경우에도 전혀 문제가 되지 않는 것을 볼 수 있다. 보면 test()함수를 실행해 변수의 값을 찍어보면 지역변수의 값(3)이 찍히고 그냥 "global"변수 값을 찍어보면 전역변수의 값인 '1'이 찍히는 것을 확인할 수 있다. 다시말해 전역변수와 지역변수를 동일한 이름으로 사용하여도 각기 다른 변수객체가 만들어 진다는 것을 알 수 있다. 이 부분에 대해서는 밑의 설명들을 참고하길 바란다. (또한 혼란을 막기 위해 이렇게 중첩된 변수 네이밍 사용을 가급적 사용하지 않는 것이 좋다.)





 4) 자바스크립트에는 블록 스코프가 없다. 

 자바스크립트에서는 조건문 ( if() { } )과 반복문( for(){} )은 스코프를 만들지 않으므로 조건문과 반복문 사이에도 변수를 서로 재정의할 수 있다. 

 

 그림에서와 같이 자바스크립트에는 블록 스코프가 없기 때문에 no의 값이 for문에서 바뀌는 것을 확인하였다. 자바스크립트에는 함수, 전역, eval() 스코프만 있음을 명심하자.





 5) 함수 내에서 변수 선언 시 var를 사용해 스코프에서 발생할 수 있는 문제를 피하자.

 위에서 잠깐 설명했다 시피 자바스크립트는 변수를 선언할 때 따로 타입을 지정하지 않고 var를 사용해 선언하게 된다. var 키워드 없이도 변수를 선언할 수 있는데 이는 함수 안에서 선언한다 하더라도 전역 변수의 스코프를 갖게 된다. 

 

 그림과 같이 첫 번째는 test()함수 안에 var를 사용해 지역변수로 선언하고 함수 범위 밖에서 'boo' 지역변수에 접근했을 때는 접근할 수 없지만 두 번째에서는 var 키워드를 사용하지 않고 'boo'를 선언하였기 때문에 전역변수로 인삭하게 되고 test()함수 밖에서도 접근할 수 있게 된다. 따라서 함수 내에서 변수를 선언할 때에는 항상 var를 사용하도록 하자. 그렇지 않으면 스코프 때문에 혼란스러워지는 문제가 발생할 수 있기 때문이다. 





2. 자바스크립트 Hoisting 이란???

 'hoist = 끌어올리다' 라는 뜻으로 자바스크립트에서는 변수 선언과 함수 선언은 해당 유효범위의 가장 최상위로 끌어 올려짐을 의미합니다. 예제를 통해 좀 더 쉽게 살펴보도록 하겠습니다. 

 

 그림을 보게 되면 처음 console.log에서는 undefined를 찍어내는 것을 파악할 수 있습니다. 이와 같은 이유는 자바스크립트 엔진에 의해 아래와 같이 해석되기 때문입니다.

 

 이렇게 'name' 변수의 선언부만 호이스팅 되기 때문에 발생합니다. 자바스크립트의 호이스팅은 함수나 변수의 선언부만 최상위로 끌어올리게 되고 초기화과정은 기존의 위치에서 실행되게 됩니다. 다시 말해 변수의 선언이 초기화나 할당시에 발생하는 것이 아니고, 유효범위의 최상위로 호이스트 되는 것입니다. 유효 범위 안에서 변수에 할당한 값을 활용하고 싶을 때에는 항상 유효범위의 최상위에 선안하고 값을 초기화 해주도록 하는 것이 자바스크립트의 호이스팅기능으로 인해 발생할 수 있는 문제들을 조금이나마 줄여줄 것 입니다.





 3. 자바스크립트의 Scope chain

 자바스크립트는 변수를 찾을 때 스코프의 계층 구조에 기반한 검색 체인을 거슬러 올라가며 추적하게 됩니다. 예제를 통해 좀 더 쉽게 살펴보도록 하겠습니다.

 

 그림에서 보면 console.log를 통해 "scopeChain"을 찍어 내는 모습을 볼 수 있습니다. console.log를 func2 스코프에 쓰여있지만 실제로 자바스크립트 scope chain을 통해 전역 스코프의 scopeChain 변수에 접근에 값을 출력하게 됩니다. func2 함수 스코프 내에 포함되어 있지 않은 scopeChain 값을 찾는 과정은 먼저 func2 함수에서 scopeChain 라는 변수를 찾게 되고, 이 값이 없으면 func2 의 부모 함수인 func1에서 검색을 하게 되고 여기에도 없으면 func1 의 부모 함수가 없기 때문에 전역 스코프에서 값을 찾게 됩니다. 전역 스코프에서 scopeChain을 발견하게 되면 이 값을 func2로 전달하게 되는 것을 자바스크립트의 scopeChain의 핵심 역할 입니다. 만약 전역 스코프에도 해당 내용이 정의되어 있지 않았다면 자바스크립트는 undefinded를 반환하게 됩니다. 



명확한 이해를 위해 예제를 하나 더 살펴보도록 하겠습니다.

 

 그림에서 보듯이 console.log는 func2에서 수행되고 있으면 "number1 + number2 + number3"의 연산을 수행하게 됩니다. 각각의 변수들은 각기 다른 스코프에서 선언이 되었습니다. 자바스크립트는 scope chain을 통해 해당 변수들을 찾게 되고 number3, number2, number1의 순서로 chain을 통해 접근하여 값을 func2 함수로 전달하여 연산을 수행하게 됩니다. 이렇듯 func2 함수에서 참조한 변수는 지역 스코프에 없을 경우 스코프 체인에서 변수를 검색하게 되며 스코프 체인을 검색할 때는 가장 처음 발견한 값을 반한하게 됩니다. (예를 들어 위에 number1, number2 의 명칭을 number3으로 변경해 주게 되면 console.log에는 9가 찍히게 됩니다.)


 이렇듯 스코프 체인을 검색할 때는 가장 처음 발견한 값을 반환하게 되므로 상위 범위에 대해서는 검색을 하지 않고 연산을 수행하여 9가 찍히게 됩니다. 



###스코프 체인은 함수를 실행한 위치가 아닌 정의한 위치에 의해 결정되어 집니다. 이를 가리켜 문법적 스코핑(lexical scoping)이라고도 합니다. 스코프 체인은 함수를 호출하기 전에 이미 만들어지며, 이 덕분에 우리는 클로저(closure)를 만들 수 있게 됩니다. 





 4. 자바스크립트 Closure

 

 Closure는 scope chain과 매우 밀접하게 연관되어 있기 때문에 scope chain의 이해가 우선시 됩니다. 그림에서 보면 sequencer 내부 함수에 ++seq를 반환하고 있는 것을 볼 수 있습니다. 이는 일반적으로 다른 언어에서는 유효범위를 벗어난 쓸 수 없는 변수이지만 자바스크립트에서는 scope chain을 통해서 연결이 가능하게 됩니다. 내부 함수는 자신이 선언된 환경에 대한 연결을 갖게 됩니다. 다시 말해 foo() 함수가 클로져를 갖게 됩니다. 클로져는 두개의 것으로 이루어진 특별한 오브젝트로 첫 번째는 함수, 두 번째는 그 함수가 만들어진 환경을 가지게 됩니다. 그 함수가 만들어진 환경은 함수가 만들어질 때 사용할 수 있었던 변수들로 이루어지고 이 경우에 foo()함수는 sequencer의 내부 함수와 seq 변수를 포함하는 클로져가 됩니다. 





[글을 쓰며]  

 자바스크립트 이것만은 알고가자 (Ver 2)를 포스팅하면서 어떻게 하면 좀 더 다른 누군가가 내 글을 봤을 때 '해당 내용들에 대해 쉽게 이해할 수 있을까'라는 고민을 많이 하게 됬다. 그로 인해 깨달은 것은 내가 그 내용에 대해 완벽히 파악하고 있지 못하다면 쉽게 설명하기 힘들다는 것과 내가 이해하는 내용을 글로 쉽게 옮겨 내는 것 또한 많은 노력이 필요하다는 것이다. 앞으로 글을 쓸 때 앞의 2가지 깨달음을 잊지 않고 포스팅을 해나가도록 하겠다. 



[참조]

자바스크립트를 깨우치다 - 코디 린들리 지음










반응형
반응형

회사에 들어와 처음 웹프로그래밍을 접하면서 자바스크립트에 대한 지식이 전무한 상태에서 무작정 남들이 작성한 코드를 토대로 감으로 프로그래밍을 했었다. 그 당시는 교육이수 중이라서 프로젝트 개발 시간도 부족한 나머지 따로 자바스크립트를 공부할 시간을 갖지 못했었다. 그래서였는지 조그마한 프론트 기능을 추가했을 때 사소한 문제들에 자주 부딪혔던 기억이 있다. 아직도 자바스크립트 공부가 많이 필요하지만 그 중 사소한 실수를 줄여 소중한 시간을 아낄 수 있는 기초 문법들에 대해 알고 넘어가 보려 한다.

 자바스크립트??? 객체기반언어, 인터프린터 언어 자바스크립트는 브라우저 기반에서 실행되는 객체 기반 언어이다. 또한 인터프린터 언어로 컴파일 언어와는 반대로 컴파일 과정이 생략되고 실행 중에 바로 한줄 한줄 번역 해 가며 실행된다. 이렇듯 한줄 한줄 변환되기 때문에 컴파일 언어보다 실행 속도가 당연히 떨어지게 된다. 또한 디버깅 혹은 에러를 잡아 내기가 컴파일 언어보다 힘들다. 하지만 인터프리트 언어는 장점 또한 가지고 있는데 한줄 한줄 해석되는 언어이다보니 자신의 프로그램을 수정하거나 보완한 경우, 전체를 완선히 새로 'Recompile'할 필요가 없어 코드를 수정하고 실행해 즉각 테스트가 가능해진다. (작업중인 jsp파일의 소스코드를 수정하고 웹페이지를 통해 즉시 확인해 볼 수 있는 이유) 또한 웹 브라우저의 Script 엔진이 직접 코드를 해석하여 처리하므로 적은 시스템 부하와 환경에 독립적인 장점을 가지고 있다.

 자바스크립트의 특징은???첫번 째, 자바스크립트는 객체 기반 언어로서 상속과 클래스가 존재하지 않는다.두번 째, 자바스크립트는 인터프리터 언어로서 클라이언트 웹 브라우저에 의해 해석되고 실행된다.세번 째, JavaScript는 HTML 문서 내에 기술되고 HTML 문서와 함께 수행된다.네번 쨰, JavaScript는 HTML에 연산, 제어 등 프로그래밍적인 요소를 추가하고, 클라이언트의 자원을 활용할 수 있게 한다.


 HTML에서 자바스크립트의 위치는??? <head>??<body>??? 보통 JSP에서 스크립트의 파일을 <head>에 모아두는데 학습을 하다 보니 head에 모아두는 것이 좋지 않다는 걸 알게 되었다. 보통 브라우저는 HTML 태그를 위부터 아래로 순서대로 읽어가며 DOM Tree를 만들고 바로바로 화면에 렌더링을 한다. 그런데 도중에 <script>태그를 만나면 렌더링을 일단 중지하고 스크립트를 실행하고 나서 다시 렌더링을 시작하게 된다. 문제는 여기서 발생한다. 만약 선언되어 있는 스크립트 중에 실행하는데 오래걸리는 스크립트가 있을 경우 화면 렌더링은 그 시점에서 멈추게 되는데 이로인해 사용자는 제대로 로딩되지 않은 공백 화면을 오래 마주하게 되는 문제가 생길 수 있다. (이로인해 많은 사용자들이 뒤로가기 버튼을 누르거나 다른 페이지로 넘거가게 된다) 하지만 스크립트를 <body> 가 닫히기 전에 넣어주게 되면 이러한 문제를 해결할 수 있다.</body>바로 직전이나 </html>후에 스크립트를 넣어주게 되면 DOM이 다 로딩되고 수행되기 때문에 복잡한 로직 수행이 수반된 스크립트나 이벤트 처리들을 다수 포함하고 있는 스크립트는 <body>가 닫히기 전에 명시해 주는 것이 좋다. 하지만 <body>사이에서 <script>를 찾는 것이 번거롭거나 불편하다고 느낄경우 처음 head에 스크립트를 선언시 defer기능을 통해 문서가 다 로딩 된 후 스크립트를 읽도록 하는 기능도 지원하는 것으로 알고 있다.(추가적인 부분은 구굴에 찾아보길 바란다)


 자바스크립트에서 기본 타입은??? 자바스크립트에서는 크게 Number, String, Boolean, Object, Null, Undefined의 타입이 존재한다. Object타입안에는 Function, Array, Date, RegExp(정규식)이 존재한다. 자바스크립트에서 사용되는 대부분의 데이터 타입은 객체로 존재하며 그에 따른 사용 또한 객체 기반이 될 수 밖에 없다.


 자바스크립트에서 Nan은 무엇인가??? 자브스크립트를 짜다가 Nan이라는 단어를 접하고 이게 뭐지 했던 때가 있었다. Nan은 Not a Number의 약자로 말그대로 해당 하는 값이 숫자가 아니라는 뜻이다. 자바스크립트에서 해당 데이터가 NaN인지 검사해주는 isNaN()이라는 내장 객체가 존재하는데 isNaN()은 NaN인지 여부를 검사하는 함수임으로 NaN일 때 true를 반환한다.


 자바스크립트에서 Null과 Undefined의 차이는???자바스크립트를 작성하다 보면 Undefined를 자주 접하게 될 것이다. 처음 Undefined를 접하게 되면 Null과 같은건가 하는 생각을 하게 되는데 둘은 다르다는 것을 알고 있어야 한다. 이 둘에 대한 차이를 정확히 이해하지 않고 스크립트를 작성하게 될 경우 사소한 부분에서 에러와 함께 시간을 많이 빼앗기게 될 것이다. 자바스크립트에서 null은 값이 없음을 나타내고 Undefined는 초기화(선언) 되지 않았거나 값이 할당되지 않았음을 나타낸다. Null은 개발자가 의도적으로 비어있는 값을 부여한 것이고 Undefined는 애당초 어떠한 값도 할당 되지 않은 것이다. 자바스크립트는 변수의 선언과 초기화를 동시에 하지 않아도 되는데 선언만 하고 초기화 되지 않은 변수는 초기화되지 않았거나 값이 할당되지 않았음을 표현하는 undefined라는 값을 할당받게 된다. 정리하자면 NULL은 변수가 참조하는 객체가 없음(null)을 나타내고 Undefined는 그 변수가 참조하는 객체를 아직 지정하지 않음(not Initialized)을 뜻하고 Undefined값을 가지는 변수는 할당을 통해 값을 가지고 이 값을 해제할 때 null타입이 되는 것이다.


자바스크립트에서 ===???프로그래밍을 하면서 '=='는 많이 접해보았을 것이다. 무엇을 비교할 때 많이 사용하는데 자바스크립트에서 멋도 모르고 '=='를 다른 언어에서 쓰던것 처럼 쓰게되면 큰코 다치는 날이 올 것이다.간단히 설명하자면 ==는 값만으로 체크를 하는 것이도 ===은 변수의 타입과 값을 모두 체크하여 비교하는 것이다.ex) x=3이라고 가정x==5 (false)x==3 (true)

x==="3" (false)x===3 true)가 되게 된다. 그럼 x=="3"을 하게 되면 결과는 어떻게 될까??? 상식대로라면 false를 뱉어야 하지만 true가 되게 되는데 자바스크립트의 ==는 형변환은 시도해 비교하게 되기 때문에 이와 같은 상황이 발생한다. 따라서 무작정 ==와 ===를 사용하게 되면 나중에 큰 문제에 직면하게 될 것이다. 반드시 차이를 정확히 이해하고 사용하기 바랍니다.


⊙ 자바크립트를 공부하는 입장으로서 가장 기본적인 내용에 대해 알아보았다. 다음 포스팅 '자바스크립트 이것만은 알고가자(Ver. 2)'에서는 자바스크립트에서의 Scope, Hoisting, Scope Chain, Closure에 대해서 알아보도록 하겠습니다.





반응형

+ Recent posts