회고록 블로그

[공부 필기] 생활코딩 JavaScript 입문 강의 필기 (2) 본문

2. 프로그래밍 언어 공부/JavaScript

[공부 필기] 생활코딩 JavaScript 입문 강의 필기 (2)

김간장 2021. 3. 22. 16:58

cinnamonc.tistory.com/162

 

[공부 필기] 생활코딩 JavaScript 입문 수업 필기 (1)

오리엔테이션 (1) JavaScript는 처음 웹브라우저를 제어하기 위함으로 고안되었음. (2) 하지만 현재에는 JavaScript를 웹서버에서도 사용할 수 있도록 하는 기술이 등장함 (node.js가 대표적) => 자바스크

cinnamonc.tistory.com

 

처음 배우는 자바스크립트이기 때문에 당장 모든 내용을 다 이해하려고 하지 않았다.

그리고 너무 어려워서 처음부터 다 이해도 못할 것 같다.

다만 강의 들으며 내용은 필기를 해놓으려고 한다. (그래서 이 글을 쓰고 있는 것)

전체 강의를 다 들은 후 다시 처음으로 돌아가서 실습을 하며 문법의 원리를 이해하는 것이 최종 목표이다.

(전체적인 숲을 먼저 보고 나무를 보는 것이 목표)

 

현재 전체적인 숲을 보는 단계임에도 불구하고 필기를 하고 있는 이유는 크게 두가지이다.

1. 나중에 나무를 볼 때(=다시 처음으로 돌아가 강의를 들을 때),

    필기한 내용을 다시 읽어보며 잘못 알고 있었던 부분 정확하게 파악하기 -> 수정/보완하기

2. 강의를 두번째 들을 때, 필기로 인한 시간을 소요하지 않기 위함 (오직 실습에 집중하기 위함)

 

따라서, 현재는 1회 청강 시점이기 때문에 아래 필기(=이해한 내용) 내용에 틀린 점이 있을 수 있다.


유효범위(Scope)

(1) 자바스크립트를 함수형 언어라고 일컫는다

(2) 함수 = 모듈화의 근간

(3) 유효범위(scope) : 변수의 수명

      * 함수의 안과 밖에 동일한 이름의 변수가 선언 되었을 때, 지역(local)변수 > 전역(global)변수 순으로 적용됨

      * 여러 함수에서 똑같은 이름(동일한 기능)의 변수를 사용해야 하는 경우가 있다면 전역변수를 쓰겠지만 그렇지 않다면 지역변수 사용해야 함

(4)  유효범위 효용

            function a(){
                var i = 0;
                // function a의 i는 지역변수
            }
            for(var i=0; i<5; i++){
                // for문 안에 있는 i의 값은 전역변수
                a();
                documnet.write(i);
            }

- 아래 코드는 무한 로딩되는 결과를 초래함

  * function a가 사용하는 변수 i는 전역변수 이기 때문.

     for문에서 i의 값을 하나씩 증가시킨다 해도 a 함수를 실행시키면 i는 0이 계속 되어버리고 무한 굴레에 빠짐

            function a(){
                i = 0;
            }
            for(var i=0; i<5; i++){
                // for문 안에 있는 i의 값은 전역변수
                a();
                documnet.write(i);

더글라스 크락포드의 '자바스크립트 핵심 가이드'를 읽어보기를 권장

 

(5) 전역변수 사용 지양, 지역변수 사용 권장

      * 만약 전역변수 사용해야 한다면 아래 코드와 같이 하나의 큰 객체(MYAPP)를 만들고 해당 객체의 속성(calculator, coordinate)으로 변수를 관리하는 방법 사용

      * 객체에 속성(객체 안에 들어있는 변수)을 선택할 때에는 객체명.속성명으로 씀

var MYAPP = {}
// MYAPP은 객체
MYAPP.calculator = {
	'left' : null,
    'right' : null
}
// MYAPP 객체의 속성인 calculator를 선언하고 초기화
MYAPP.coordinate = {
	'left' : null,
    'right' : null
}
// MYAPP 객체의 속성인 coordinate
...

위의 로직 자체를 function() 함수로 정의하고, (함수 이름 없이) 바로 호출하려면? => function() 입력 후 마지막에 괄호로 묶어줌

function(){
	var MYAPP = {}
	// MYAPP은 객체
	MYAPP.calculator = {
		'left' : null,
    	'right' : null
	}
	// MYAPP 객체의 속성인 calculator를 선언하고 초기화
	MYAPP.coordinate = {
		'left' : null,
    	'right' : null
	}
	// MYAPP 객체의 속석인 coordinate
	...
}()

(6) 전역변수를 완전히 없애고 지역변수만 이용하고 싶다면 아래와 같이 사용

    * (5)번의 마지막 코드에서 함수를 한번 더 괄호로 묶어주면? => var MYAPP은 전역변수가 아닌 지역변수가 됨 (완전히 전역변수를 사용하지 않을 수 있음)

(function(){
	var MYAPP = {}
	// MYAPP은 객체
	MYAPP.calculator = {
		'left' : null,
    	'right' : null
	}
	// MYAPP 객체의 속성인 calculator를 선언하고 초기화
	MYAPP.coordinate = {
		'left' : null,
    	'right' : null
	}
	// MYAPP 객체의 속석인 coordinate
	...
}())

    * 만약 이름있는 함수로 정의한 후 함수를 호출 하면? => myappfn이라는 함수명도 사실은 '변수 안에 함수가 들어가 있는 것'이기 때문에 myappfn이 전역변수가 되어버림

function myappfn(){
	var MYAPP = {}
	// MYAPP은 객체
	MYAPP.calculator = {
		'left' : null,
    	'right' : null
	}
	// MYAPP 객체의 속성인 calculator를 선언하고 초기화
	MYAPP.coordinate = {
		'left' : null,
    	'right' : null
	}
	// MYAPP 객체의 속석인 coordinate
	...
}
myappfn();

(7) 유효범위 대상: 자바스크립트는 함수만 유효범위 제공함 (정적유효범위, 렉시컬)

      * 많은 언어들은 블록({} 등) 안에서 유효범위를 제공하지만 자바스크립트는 함수로 유효범위 제공함

 

      * e.g.) JAVA : for문 중괄호 안에서 문자열 변수를 선언하고 for문 밖에서 해당 문자열 변수를 호출하면 에러가 발생

         => JAVA에서는 for문 안에서 선언된 변수는 for문의 지역변수이기 때문에 선언된 영역 안에서만 사용 가능 (전역변수 아님)

      * JavaScript : 아래와 같은 경우 name이 전역변수

         => JavaScript에서는 함수 안에서 선언된 변수만 지역변수 (for, while문 안에서 선언된 변수는 전역변수)

(8) 정적 유효범위, 렉시컬 스코프 => 함수가 정의될 때(=선언될 때) 유효범위를 갖음

      * 함수가 사용(=호출)될 때, 변수를 바라보는 것이 아님 (정의될 때 변수를 바라봄)

      * 따라서 아래 코드는 10이 출력되는게 아니라 5가 출력됨

var i = 5;

function a(){
    var i = 10;
    b();
}
function c(){
    var i = 15;
    b();
}
function b(){
    document.write(i);
}

a(); //결과 5
c(); // 결과 5

      * 함수 b가 호출될 때 함수 b의 엄마(?)는 a 함수이자 c 함수임

      * 만약 함수를 호출할 때 변수 등이 결정된다면 a와 c함수를 호출(= a();, c(); )하고

         a함수와 c함수 안에서 b함수가 호출(= b(); ) 되므로 이 순간 변수가 결정되어야 함

         (즉, a 함수를 호출하면 10이 출력되고, c 함수를 호출하면 15가 출력되어야 함)

      * 즉, 함수가 사용(=호출)되는 시점에 변수가 결정되었다면

         위의 코드와 같은 경우 a와 c 함수들 안에 있는 지역변수 i에 따라 b 함수의 결과가 달라졌을 것임

          => 이를 "동적유효범위"(dynamic scope) 라고 함

      * 하지만 자바스크립트는 정적 유효범위(또는 렉시컬 스코프)를 따름

         b함수의 코드를 작성하고 저장한 그때(?) 변수가 결정됨 (b함수가 선언 및 정의된 그 시점)

         => 따라서 5가 출력됨

 

참고사항.

     함수 안에서, 변수명 앞에 var을 붙이면 지역변수가 되고

     변수명 앞에 var을 붙이지 않으면 전역변수가 되어버림 

 

 

함수(Function)

(1) 자바스크립트에서는 함수도 객체(object)임 => 다시 말해서 함수는 일종의 "값"임

      * var a = 'value' 처럼 함수(function)도 어떠한 변수에 담을 수 있음

(2) 자바스크립트 함수가 다른 언어의 함수와 차이점 : 함수 자체가 값(value)이 될 수 있음

      * var a = function() {} // 함수가 값이기 때문에 변수나 객체에 담길 수 있음

      * 아래 예제에서 b(=key)는 일종의 변수와 같은 역할을 함 (= 속성이라고 함)

     이 b라는 객체의 속성(property)에 담겨진 값(value)이 함수일 때, 이 함수를 메소드(method) 라고 부름

          - 함수(function)와 구분해서 부름

a = {
	b:function() {
    }
};
// a는 객체이고 객체 안에는 함수가 들어있음 (b는 key, function() {}는 value)

(4) 함수는 다른 함수의 인자(argument)로 전달될 수 있음, 리턴값으로 전달될 수도 있음

        var num1 = 3;
        var num2 = 2;

        function cal(mode) {
            var funcs = {
                'plus' : function(number1, number2) {return number1+number2},
                'minus' : function(number1, number2) {return number1-number2}
            }
            return funcs[mode];
        }

        document.write("<p>"+cal('plus')(num1, num2)+"</p>");
        // cal이라는 객체 안에 있는 'plus'라는 속성(property)의 값(value)이 함수이기 때문에 괄호 필수
        document.write("<p>"+cal('minus')(num1, num2)+"</p>");

※ 위의 예제에서 "return funcs[mode]"는 "return funcs.mode"로 변경할 수 없음

     (단, return funcs.plus 혹은 return funcs.minus는 가능함(오류가 발생하지 않음)

      -> 오류가 발생하기 때문 (cal은 fucntion이 아니라고 함..)

      -> 원인을 찾아보니 객체의 값에 접근하는 방법은 두가지 인데 (객체명.key와 객체명[key])

           "객체명.key"로 접근하는 방법은 key가 반드시 속성명만 들어올 수 있다고 함 (변수명은 들어올 수 없다고 함)

           하지만 "객체명[key]"는 변수명이 입력되어도 된다고 함.

             => 즉, 아래와 같은 코드를 말함

var obj = {
    'plus' : function(num){ return num+1; },
    'minus' : function(num){ return num-1; }
}
var mode = 'plus';
var number = 3;

console.log(obj.minus(number));
// 객체의 값에 접근하는 방법 첫번째 : obj.plus, obj.minus (문자열이지만 따옴표 없음 주의)
console.log(obj['plus'](number));
// 객체의 값에 접근하는 방법은 두번째 : obj['plus'], obj['minus'] (따옴표 있음 주의)


// 직접 속성(property)명을 적지 않고 속성값을 변수(mode)에 넣고 변수로 접근해보기
console.log(obj.mode(number)); // obj.mode와 같이 접근할 때에는 변수명(mode)을 쓸 수 없음 (에러 발생)
console.log(obj[mode](number));

실행결과
문제의 코드를 주석처리하면 문제해결됨

 

(5) 함수는 배열 안에도 들어갈 수 있음

      * 함수가 값(value)이기 때문에 가능

        var arr = [
            function(input){return input + 10},
            function(input){return input * input},
            function(input){return input / 2}
        ];

        var input = 1;
        for(var i=0; i<arr.length; i++){
            input = arr[i](input); // 배열 안에 있는 값이 함수이기 때문에 () 괄호 필수
            document.write(input+"<br/>");
        }
        document.write(input);

(6) 이렇게 변수, 매개변수, 리턴값에 들어갈 수 있는 데이터를 first-class citizen 또는 first-class object (또는 first-class entity) 로 부름

 

  <콜백>  

※ 값으로서의 함수와 밀접하게 연결되어 있는 것이 콜백

※ 어떠한 함수가 수신하는 인자(argument)가 "함수"인 것이 콜백.

 

(7) numbers는 객체이고, sort()는 메소드임. 자바스크립트가 기본적으로 가지고 있는 기능이므로 내장객체, 내장메소드라고 함(built-in object, built-in method)

      * 사용자가 만드는 객체, 메소드는 사용자 정의 객체/사용자 정의 함수라고 함

      * 내장 메소드 sort()는 브라우저가 만들어질때부터 기본적으로 가지고 있는 기능임

      * sort() 함수는 아래와 같이 사용됨

        (하지만, 이 경우에는 숫자로 인식되는 것이 아니라 문자열로 인식이 되어서 아스키코드 값으로 정렬됨)

var numbers = [20, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1];
numbers.sort();

(8) 숫자로 인식해서 정렬할 때에는 아래와 같이 사용

            var numbers = [20, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1];
            var sortfunc = function(a, b){
                console.log(a, b);
                // 버블정렬로 추정
                return a-b;
                // a>b이면 return값이 양수(1)
                // a<b이면 return값이 음수(-1)
                // a=b이면 return값이 0 으로 반환되는 것을 사용자가 기준으로 잡았기 때문에
                // 자바스크립트가 그 기준에 맞춰 정렬을 수행함
            }
            console.log(numbers.sort(sortfunc));
            // sortfunc가 콜백(callback) 함수임

      * 여기에서 sortfunc이 callback 함수임

     * sort라는 함수가 sortfunc이라는 콜백함수를 인자(argument)로 받아서 사용하는데,

       이 경우에 sort가 원래 동작하던 방법이 sortfunc를 인자로 받게 되면서 변경됨


※ sort 메소드에 대한 이해가 좀 더 필요해보여서 구글링 해봤음

     - 자바스크립트에서의 sort 함수 : 자바스크립트 배열(array)의 내장되어 있는 함수임 (=built-in function)

     - 이 sort()라는 메서드는 배열의 요소들을 적절한 위치로 정렬하고 반환(return)하는 역할을 함

     - 이때 sort()라는 메서드가 작동되는 방법은 이러함 (이건 sort 메서드를 만들 때 이렇게 동작하도록 코드를 짠 것)

1. 배열의 요소들을 a와 b라는 변수에 하나씩 넣음
2. 만약 a가 b보다 작다면 (a < b 이면) "-1"을 리턴(return)함
3. 만약 a가 b보다 크다면 (a > b 이면) "1"을 리턴(return)함
4. a와 b가 같으면 "0"을 리턴(return)함
5. 0보다 작으면 a를 b보다 낮은 색인으로 정렬함 (= a가 앞에 옴)
6. 0을 반환하면 위치를 바꾸지 않음
7. 0보다 큰 경우 b를 a보다 낮은 인덱스로 정렬함 (= b가 앞에 옴)
8. 이렇게 정렬이 완료될 때까지 반복함

     - 이제부터 개인적인 추측..

        * 위의 동작 방법으로 추측해보건데 정렬 기법(버블, 선택, 힙, 퀵 등) 중 '버블 정렬' 방법을 쓰고 있는 것 같음

           (자세한 내용은 버블정렬을 찾아보기)

         * 위에서 sort()를 사용하지 않고 굳이 동일하게 동작하는 sortfunc()을 사용한 이유는

            sort()를 사용 했을 때 '문자열로 인식되어 아스키코드 값 기준으로 정렬'되었기 때문인 것 같음

sort에 대한 MDN 설명 (출처 아래 참고)

         * 즉, sortfunc()은 sort()와 동일한 방법으로 동작 하되

            배열의 요소들을 '문자열이 아닌 숫자'로 인식할 수 있도록 하기 위해서 사용자가 만든 함수인 것 같음

         * sort()의 인자(argument)에는 함수를 넣을 수 있고,

            이 함수는 사용자가 sort()와 동일한 동작을 하게 만들 수도 있고, 내림차순 정렬을 하게 만들 수도 있는 등등 다양한 것 같음

 

참고: developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/sort

 

Array.prototype.sort() - JavaScript | MDN

Array.prototype.sort() sort() 메서드는 배열의 요소를 적절한 위치에 정렬한 후 그 배열을 반환합니다. 정렬은 stable sort가 아닐 수 있습니다. 기본 정렬 순서는 문자열의 유니코드 코드 포인트를 따릅

developer.mozilla.org


※ 콜백에 대한 이해가 좀 더 필요해서 구글링 해왔음

      - 콜백은 '나중에 호출'한다는 점이 핵심인 것 같음

      - 콜백은 "매개변수로 함수를 전달하고, 다른 명령들이 실행을 끝낸 뒤 실행"되는 것을 말한다고 함 (아래 참고링크2의 글 중 일부 발췌)

      - 구체적으로 사용법은 "매개변수"로 함수를 넘겨주고, 해당 함수를 안에서 사용하면 됨 (= 이 함수는 콜백함수라고 함)

      - 콜백은 다음 명령으로 넘어가기 전에 요청에 대한 응답을 기다려야하거나(응답을 받는게 아님), 딜레이가 시작되도록 해야 하는 상황 -> 그리고 응답을 받거나 딜레이가 끝나면 특정 행동(해당 값을 어딘가에 저장, 경고창 울림 등등 작업을 콜백함수에 적음)을 실행되도록 할 때 사용함

 

 

※ 콜백에 대해 잘못 알고 있었던 부분

      - 콜백함수를 이용해서 -> 비동기적으로 처리하고 있는 코드를 -> 처음부터 끝까지 동기적으로 처리하게 할 수 있게 되는건 아닌 것 같음

 

 

※ 콜백함수에 대한 이해를 쉽게 풀어보기

      - 자바스크립트는 비동기적 처리를 함

        (Why? 만약 '동기적 처리'를 하고, 코드 안에 함수가 100개 있으며, 각 함수당 딜레이가 5초씩 있다고 하면

          "1번 함수 실행하고 -> 5초 기다리고 -> 1번 함수 끝나고 -> 2번 함수 실행하고 -> 5초 딜레이 -> 2번 함수 끝나고 -> ..."

          이렇게 실행하게 되고 그러면 웹 프로그램 하나 실행하는데 수십, 수백분이 걸릴 것이기 때문) (참고자료3 내용 참고)

      - 비동기적 처리를 하기 때문에 발생하는 문제도 있음

        * 예를 들어, 서버에게 어떤 값을 요청하고 -> 응답 받은 값을 자바스크립트 변수에 저장하며 -> 최종적으로 그 변수를 alert으로 출력하는 자바스크립트 코드가 있다고 가정

        * 이때 서버가 내 요청에 대한 응답을 주는데 10초가 걸렸음 (가정)

        * 자바스크립트는 비동기적 처리를 하므로 그 10초를 기다려주지 않고 쭉쭉 다음 코드(변수를 alert으로 출력하는 코드)를 실행시켜버림

        * 그렇게 10초가 지나고 서버로부터 값을 응답받아 변수에 저장함

        * 하지만 이미 '변수를 alert으로 출력하는 코드'는 실행되어버림

      - 위와 같이 비동기적 처리로 인해서 원하지 않는 방향으로 코드가 진행되버림

         => 이걸 해결하기 위한 방법이 콜백함수를 사용하는 것

        * 위와 같은 상황을 해결하려면 '변수를 alert으로 출력하는 코드'는 '응답 받은 값을 변수에 저장'한 후에 실행되어야 함 (이 부분은 동기적 처리가 된 것처럼 보이게 해야함)

        * '변수를 alert으로 출력하는 코드'를 콜백함수 안에 집어넣고

        * 서버로 부터 값을 응답받으면 콜백함수를 실행하도록 코드를 재구성함

     * 코드로 이해하기 위해서 별도로 글을 작성함 :

cinnamonc.tistory.com/174

 

[공부 복습] 생활코딩 JavaScript 입문 강의 복습 (2)

관련 글 : cinnamonc.tistory.com/168 [공부 필기] 생활코딩 JavaScript 입문 강의 필기 (2) cinnamonc.tistory.com/162 자바스크" data-og-host="cinnamonc.tistory.com" data-og-source-url="https://cinnamonc...

cinnamonc.tistory.com


 

참고자료1. hees-dev.tistory.com/33

 

[Javascript] callback(콜백) 개념 이해하기

Javascript로 개발을 하신다면 'callback'이라는 키워드를 한 번쯤 들어보셨을 것이라 생각합니다. 과연 callback이란 무엇일까요? 1.callback이란? javascript에서는 callback 함수는 다른 함수의 매개변수로 함

hees-dev.tistory.com

 

참고자료2. medium.com/@oasis9217/%EB%B2%88%EC%97%AD-javascript-%EB%8F%84%EB%8C%80%EC%B2%B4-%EC%BD%9C%EB%B0%B1%EC%9D%B4-%EB%AD%94%EB%8D%B0-65bb82556c56

 

[번역] JavaScript: 도대체 콜백이 뭔데?

이 문서는 Brandon Morelli의 JavaScript: What the heck is a Callback? 을 번역한 것입니다. 잘못된 부분이 있는 경우 알려주시면 감사하겠습니다.

medium.com

 

참고자료3. joshua1988.github.io/web-development/javascript/javascript-asynchronous-operation/

 

자바스크립트 비동기 처리와 콜백 함수

(중급) 중급 자바스크립트 개발자가 되기 위한 자바스크립트 비동기 처리와 콜백 함수 이해하기. 콜백 지옥과 해결 방법 등

joshua1988.github.io


 

(9) 콜백은 비동기 처리에서 유용하게 사용됨

      - e.g. 비동기 처리에서 발생하는 문제점 (위에서 언급함)을 해결할 수 있음

      * 작업을 처리할 때, '앞의 작업'이 끝날 때까지 기다린 후 '다음 작업'을 하는 것이 '동기적 처리'

      * 작업을 처리할 때, '앞의 작업'이 진행 중일 동안 그 다음(next)에 있는 작업을 처리 하고 있고 -> '앞의 작업'이 끝나면 그 작업도 마저 처리해버리는 것이 '비동기적 처리'

      * Asynchronus(비동기) JavaScript and XML = Ajax

         - 보통 페이지의 정보를 갱신할 때에는 페이지 전체를 다운로드 받아서 브라우저가 해석해서 출력하는게 일반적이지만

         - 일부분만 갱신하고 싶을 때 Ajax를 사용함

          - 웹이 단순 문서에서 벗어나 더 많은 동작을 할 수 있도록 결정적인 단서를 제공한 기능이 Ajax임

      * Ajax는 비동기적인 제어를 함

          - 비동기적인 제어 덕분에 사용자가 채팅목록 화면에서 '오픈채팅 홈'을 클릭하는 동안 채팅방을 본다거나, 스크롤을 내린다거나, 채팅을 보낸다거나 등등이 가능함

     * 함수를 매개변수(parameter)로 전달하는 방법(=콜백)을 통해서 get이라는 메소드의 동작 방법을 바꿔버림

        e.g. $.get(~~~~~)

     * 유지보수를 하기 쉬운 코드 작성, 고난이도 기능을 구현할 때 사용하므로 잘 이해해두면 도움이 됨

 

클로저(closure)

(0) 내부함수가 외부함수의 맥락(context)에 접근할 수 있는 것을 가리킴

      * 자바스크립트 이용한 고난이도 테크닉 구사하는데 필수적인 개념임 

         e.g. 큰 코드, 많은 코드를 작성할 때, 많은 사람과 협업할 때 등등

(1) 어떠한 함수 안에서만 사용하는 함수가 있을 수 있음

      * 함수 안에 함수를 선언하는 방법 사용함

function outter(){				// 외부함수
	function inner(){  			// 내부함수
    	var title = 'coding everybody';
        alert(title);
    }
    inner();
}
outter();

      * inner 함수는 내부함수, outter 함수는 외부함수 (inner을 둘러싸고 있는 함수가 외부함수)

      * 즉, outter라는 함수 안에 지역변수 inner를 만들고, 그 변수에 함수를 할당한 것과 동일

         e.g. var inner = function() { ~~~~~ }

      * 특정 함수 안에서만 사용해야하는 함수가 있을 때 사용

         - outter 함수 바깥에 inner 함수를 정의하면 응집성이 떨어지고, 중간에 무언가 끼여들수도 있음

function outter(){
    var title = 'coding everybody';
	function inner(){
        alert(title);
    }
    inner();
}
outter();

      * 위의 코드는 에러 없이 결과가 출력됨

      * 내부함수 inner :

         자신의 내부에 없는 지연변수를 사용하려고 하면 inner 함수를 감싸고 있는 함수(=outter)에서 필요한 변수를 찾음

          => 즉 내부함수는 외부함수의 지역변수에 접근할 수 있음

          => 이러한 것을 클로저라고 함

 

(2) 클로저는 독특한 특징이 있음

     * 내부함수가 외부함수의 지역변수를 이용하고 있다고 했을 때,

        외부함수가 종료(return 값주고 끝남) 되었더라도 그 안에 있는 내부함수가 살아있다면 이미 사라진 외부 함수의 지역변수에 접근 가능함

     * 즉 아래의 코드가 에러없이 출력 가능하다는 얘기

        => outter 함수가 return 된 순간 지역변수였던 title이 사라지는데, inner() 함수로 title에 접근해도 에러가 발생하지 않음

function outter(){
    var title = 'coding everybody';
    return function(){
        alert(title);
    }
}

inner = outter();
inner();

 

(3) 클로저의 실용적인 예제 : private variable (아무나 정보를 수정하지 않도록 방지하는 것)

      * 클로저를 이용해서 private 변수를 쉽게 변경하지 못하도록 할 수 있음

      * 아래의 예제 참고

          - 결론 : ghost 라는 객체가 접근할 수 있는 title 값만 변경할 수 있음 (matrix 객체가 접근할 수 있는 title은 변경 불가)

             => private variable

          - get_title과 set_title의 메소드는 누구나 접근할 수 있음, 누구나 사용할 수 있음 (=public)

          - 변수 title은 factory_movie의 지역변수이고, 이미 factory_movie 함수는 소멸했기 때문에

             클로저 덕분에 get_title과 set_title을 통해서만 접근 후 변경 가능함 (=private 변수)

          => title 변수는 아무나 수정할 수 없음

      * 즉, 다른 fuction, 객체 등 에서 또 "title"이라는 변수를 사용한다고 하더라도 factory_movie에 있는 title에는 영향을 주지 않음

        (여기에서의 title은 오직 get_title, set_title을 통해서만 변경할 수 있음)

      * private 변수를 사용하고자 할 때(외부에서 함부로 접근하지 못하게 만들어야 할 때) 클로저 이용

function factory_movie(title){
    // 1) 매개변수 title은 함수의 지역변수
    return {
        // 2) 아래 함수는 내부함수에 해당
        get_title : function() {
            return title; //4) 내부함수가 외부함수(factory_movie)의 지역변수(title)에 접근
        },
        set_title : function(_title){
            title = _title;
        }
    }
}

ghost = factory_movie('Ghost in the shell'); // 3) 외부함수(factory_movie) 값 리턴 후 소멸
matrix = factory_movie('Martix');

console.log("처음 : ", ghost.get_title());
console.log("처음 : ", matrix.get_title());

ghost.set_title('공각기동대');
console.log('공각기동대로 변경 완료하였습니다.');

console.log("변경 후 : ", ghost.get_title());
console.log("변경 후 : ", matrix.get_title());

※ private 속성 : 객체의 외부에서는 접근할 수 없는 외부에 감춰진 속성이나 메소드를 의미 <-> public 속성

 

(4) 클로저에 대해서 공부할 때 예제로 많이 사용되는 아래의 코드를 유의할 것 (자주 발생하는 실수 유형)

var arr = []
for(var i = 0; i < 5; i++){
    arr[i] = function(){
        return i;
    }
}
for(var index in arr) {
    console.log(arr[index]());
}

실행결과

는 동일한 값이 5번 출력되었음을 의미함

      *0부터 4까지 숫자가 출력되기를 기대했으나 실제로는 5가 다섯번 출력

      * 스크롤 압박이 심해져서 별도로 아래 글에 이어서 적기로 했음

cinnamonc.tistory.com/174

 

[공부 복습] 생활코딩 JavaScript 입문 강의 복습 (2)

관련 글 : cinnamonc.tistory.com/168 [공부 필기] 생활코딩 JavaScript 입문 강의 필기 (2) cinnamonc.tistory.com/162 자바스크" data-og-host="cinnamonc.tistory.com" data-og-source-url="https://cinnamonc...

cinnamonc.tistory.com

      * 해결하는 방법은 아래와 같이 코드를 수정

var arr = [];
for(var i=0; i<5; i++){
    arr[i] = function(id){
        return function(){
            return id;
        }
    }(i);
}

console.log('i의 값 출력 : ', i);
for(var index in arr){
    console.log('arr 값 순차적으로 출력 : ', arr[index]());
}

      * 현재는 const와 let을 이용할 수 있는 것 같음

         => 역시나 스크롤 압박이 심해져서 별도로 아래 글에 이어서 적기로 했음

cinnamonc.tistory.com/174

 

[공부 복습] 생활코딩 JavaScript 입문 강의 복습 (2)

관련 글 : cinnamonc.tistory.com/168 [공부 필기] 생활코딩 JavaScript 입문 강의 필기 (2) cinnamonc.tistory.com/162 자바스크" data-og-host="cinnamonc.tistory.com" data-og-source-url="https://cinnamonc...

cinnamonc.tistory.com

 

arguments

(0) 함수 안에서 인자와 관련된 정보를 담고 있는 객체

(1) 배열과 유사함 (하지만 배열은 아님)

(2) 기본적으로 자바스크립트의 함수는 매개변수와 인자의 수가 일치하지 않아도 오류가 발생하지 않음

      * 매개변수 : 함수가 정의(선언)된 부분에서 소괄호 안에 있는 변수 e.g. function a(num1, num2) {  ~~~~ 

      * 인자 : 함수를 호출하는 코드 부분에서 소괄호 안에 있는 변수 e.g. a(1, 2)

(3) arguments는 이미 약속되어 있는 변수 이고, 배열과 유사하게 동작함

      * arguments에는 사용자가 전달한 인자의 값이 들어있음

      * 인자의 수를 처음부터 정해놓지 않았을 때 이 arguments를 사용할 수 있음

      * 배열과 같이 [0], [1], [2] 등으로 접근가능 (e.g. arguments[0])

 

(4) arguments.length와 함수명.length는 다른 의미를 가지고 있음

(5) arguments가 하는일은 크게 두가지

      * .length를 이용해서 전달받은 인자(argument)가 몇개인지 확인 가능

      * arguments[0], arguments[1] 등으로 전달받은 인자의 특정 자리에 대한 값을 알수있음

 

함수의 호출

(1) 자바스크립트에서 함수는 일종의 '객체'임

      * 객체는 '속성'(property)을 가지고 있고, 그 속성에는 값(value) 혹은 메소드(method)가 있음

      * 함수도 객체이어서 메소드를 가지고 있음

      * 여기에서는 apply 메소드와 call 메소드를 알아봄

(2) 자바스크립트에는 "Function"이라는 객체가 있음

      * 개인적인 추측

         - 자바스크립트라는 언어는 처음부터 누군가가 만들어 놓은 '표준내장객체'가 있음

            Function도 그 표준내장객체 중 하나인 듯함

         - 이 Function 객체의 속성에는 'arguments', 'length', 'name' 등이 있고

           그 속성에 메소드는 'apply', 'call' 등이 있는 듯함

(3) 함수의 apply 메소드 사용 방법

      * 함수명.apply(null, [인자값1, 인자값2])

          => 이는 함수명(인자값1, 인자값2) 과 동일한 결과 나옴

      * 하지만 보통 null을 사용하지 않고 다른 값을 넣어서 사용함 (굳이 null을 넣기 위해서 apply 메소드를 사용할 이유가 없음)

(4) apply 메소드의 쓰임 : 예제

o1 = {
    val1 : 1,
    val2 : 2,
    val3 : 3
}
o2 = {
    v1 : 10,
    v2 : 50,
    v3 : 100,
    v4 : 25
}

function sum(){
    var sumVal = 0;
    for(name in this){
        sumVal += this[name];
        // this는 정의될 때 결정되지 않고 호출할 때 결정됨
    }
    return sumVal;
}

// 다른 인자는 없고 thisarg(this 인자)만 o1, o2로 설정함
console.log(sum.apply(o1)); // 결과 6
console.log(sum.apply(o2)); // 결과 185

      * 위 예제 추가 내용

         => sum.apply(o1)sum.apply(o2)가 실행되는 그 순간에는 o1.sum과 o2.sum으로 동작함

               (아래의 코드와 같아진다는 말)

         => this는 "내가 속한 객체" (or 내가 생성할 인스턴스)를 가리키는 참조 변수이기 때문에

              sum 함수가 o1과 o2라는 객체에 속하도록 하기 위해서 각 객체에 sum이라는 메소드를 추가해준 것.

o1 = {
    val1 : 1,
    val2 : 2,
    val3 : 3
    sum : sum // sum 메소드
}
o2 = {
    v1 : 10,
    v2 : 50,
    v3 : 100,
    v4 : 25
    sum : sum //sum 메소드
}

      * +추가> apply 라는 메소드는 첫번째 인자에 this의 인자값(=this의 값을 뭘로 할건가요?)을 넣고 두번째 인자에 함수의 인자값(=함수가 호출할 때 전달해줘야 하는 인자가 무엇인가요?)을 넣어야함

 

※ 참고사항.

     * this는 "'내가 속한 객체 or 내가 생성할 인스턴스'를 가리키는 참조 변수"를 의미

     * 그리고 기본적으로 apply 메소드의  첫번째 인자가 null이면 'window'임 (기본값 window)

Comments