Programming/Web Programming2017. 7. 18. 16:12

JavaScript #5 – 함수 지향 (Function-Oriented)

 

클로저 (Closure)

내부 함수가 외부 함수의 Context에 접근할 수 있는 것을 가리킴.

JavaScript는 함수 안에서 또 다시 함수를 선언할 수 있음. 외부함수 안에 선언된 함수를 내부함수라고 할 때, 외부함수의 지역변수에 내부함수는 접근할 수 있음.


이러한 관계에서 외부함수가 실행이 끝나서 소멸된 이후에도 내부함수가 소멸된 외부함수의 변수에 접근할 수 있는 메커니즘을 클로저라고 함.

 

function outter(){

    var title = 'coding everybody'; 

    return function(){       

        alert(title);

    }

}

inner = outter();

inner();



위 코드를 살펴보면 inner에는 outter의 결과가 대입되는데, 그 결과가 이름 없는 함수임. inner(); 명령을 실행할 때는 이미 outter 함수의 실행은 끝났기 때문에 outter 함수의 지역변수인 title은 소멸되어야 하지만, 실행 결과는 title의 문자열인 ‘coding everybody’가 그대로 나온다. 이는 title이 소멸되지 않았음을 의미함.

이를 통해 의부함수는 외부함수의 지역변수를 사용하는 내부함수가 소멸되기 전까지 소멸하지 않는 것을 알 수 있음. 이런 특성이 바로 클로저’.

더 복잡한 예시:

 

function factory_movie(title){

    return {

        get_title : function (){

            return title;

        },

        set_title : function(_title){

            title = _title

        }

    }

}

ghost = factory_movie('Ghost in the shell');

matrix = factory_movie('Matrix');

 

alert(ghost.get_title());

alert(matrix.get_title());

 

ghost.set_title('공각기동대');

 

alert(ghost.get_title());

alert(matrix.get_title());

 





Ghost 변수와 matrix 변수는 각각 factory_movie 함수의 리턴값으로 객체를 받고 있음. 둘 다 title이라는 factory_movie의 지역변수를 사용하지만 alert 결과에서 볼 수 있듯이 각각 다른 결과를 보여주고 있음. 이를 통해 외부 함수가 실행될 때마다 새로운 지역변수를 포함시키는 클로저가 생성되어, ghost matrix에 있는 title은 완전히 독립된 개체가 되었음을 알 수 있음.

JavaScript Private 속성을 지원하지 않음. 하지만 위의 factory_movie 함수의 지역변수 title은 함수 안에서 정의된 메소드에 의해서 만들어진 객체만이 값을 읽고 수정하는게 가능하다는 클로저의 특성을 이용해 Private 속성을 구현할 수 있음.

 

다음 예시를 보자.


var arr = []

for(var i = 0; i < 5; i++){

    arr[i] = function(){

        return i;

    }

}

for(var index in arr) {

    document.write(arr[index]()+'<br/>');

}



0, 1, 2, 3, 4가 출력될 것이라고 예상하기 쉬움. 하지만 for문은 함수가 아님. 그렇기 때문에 for문에 있는 i값에 함수 function이 접근할 수 없기 때문에, for문이 모두 돌고 난 뒤 5가 된 i값이 한번에 적용된 것. 원래 의도대로 출력되게 하려면 다음과 같이 바꿔야함.


var arr = []

for(var i = 0; i < 5; i++){

    arr[i] = function(id) {

        return function(){

            return id;

        }

    }(i);

}

for(var index in arr) {

    document.write(arr[index]()+’<br/>’);

}



 

Arguments

함수에는 arguments라는 숨겨진 유사 배열이 있음. 함수를 호출할 때 입력한 인자가 담겨 있음.


function sum(){

    var i, _sum = 0;   

    for(i = 0; i < arguments.length; i++){

        document.write(i+' : '+arguments[i]+'<br />');

        _sum += arguments[i];

    }  

    return _sum;

}

alert('result : ' + sum(1,2,3,4));



Arguments는 함수 안에서 사용할 수 있도록 그 이름이나 특성이 약속되어 있는 arguments 객체의 인스턴스임. 배열과 비슷하지만 배열은 아님. arguments[0]은 함수에 전달된 첫 번째 인자를 알아낼 수 있음.

매개변수와 관련해 두 가지 수가 있음. 하나는 함수.length, 다른 하나는 arguments.length. 함수.length는 함수에 정의된 인자의 수를, arguments.length는 함수에 전달된 실제 인자의 수를 의미함.

 

function zero(){

    document.write(

        'zero.length : ', zero.length+'<br/>',

        'arguments : ', arguments.length+'<br/>'

    );

}

function one(arg1){

    document.write(

        'one.length : ', one.length+'<br/>',

        'arguments : ', arguments.length+'<br/>'

    );

}

function two(arg1, arg2){

    document.write(

        'two.length : ', two.length+'<br/>',

        'arguments : ', arguments.length+'<br/>'

    );

}

zero();

one('val1', 'val2');

two('val1');



 

함수 호출


function func(){

}

func();


JavaScript는 함수를 호출하는 특별한 방법을 제공함. JavaScript에서 함수는 객체임. 위 예시 코드에서 함수 func Function이라는 객체의 인스턴스임. 따라서, func Function이 가지고 있는 메소드들을 상속하고 있음. 그 중 Function.apply Function.call을 활용해봄.

 

function sum(arg1, arg2){

    return arg1+arg2;

}

alert(sum.apply(null, [1,2]))



---


o1 = {val1:1, val2:2, val3:3};

o2 = {v1:10, v2:50, v3:100, v4:25};

function sum(){

    var _sum = 0;

    for(name in this){

        _sum += this[name];

    }

    return _sum;

}

document.write(sum.apply(o1));

document.write('<br/>');

document.write(sum.apply(o2));



Sum 함수는 내부에서 객체의 속성을 열거할 때 사용하는 for in 문을 이용해서 객체 자신의 값을 열거한 후에 각 속성의 값을 지역변수 _sum에 더한 후 리턴하고 있음.

메소드 apply의 첫 번째 인자는 함수가 실행될 맥락임. 객체의 메소드로 sum을 만들고 호출한 뒤에 만들었던 sum 역할을 하는 메소드를 삭제한다고 생각하면 됨. sum이 객체 소속의 메소드가 된다는 것은 ‘sum에서 this의 값이 전역객체가 아니라 객체가 된다는 뜻임. 일반적으로 객체지향 언어에서는 하나의 객체에 소속된 함수는 그 객체의 소유물임. 하지만 JavaScript에서는 함수는 독립된 개체로 존재하고, apply call 메소드를 통해 다른 객체의 소유물인 것처럼 실행할 수 있음.

만약 apply의 첫 인자로 null을 전달하면 apply가 실행된 함수 인스턴스는 전역객체를 context로 실행하게 됨. 브라우저의 경우는 함수가 실행된 window가 될 것임.

 

'Programming > Web Programming' 카테고리의 다른 글

JavaScript Basic #7  (0) 2017.07.22
JavaScript Basic #6  (0) 2017.07.21
JavaScript Basic #4  (0) 2017.07.18
JavaScript Basic #3  (0) 2017.07.16
JavaScript Basic #2  (0) 2017.07.15
Posted by BinZIP
Programming/Web Programming2017. 7. 18. 02:34

JavaScript #4 – 함수 지향 (Function-Oriented)


유효범위

유효 범위란 변수의 수명을 의미. 함수 밖에서 선언한 변수는 전역 변수(global variable)이 되고,안에서 선언하면 지역변수(local variable)이 됨.


var vscope = 'global';

function fscope(){

    var vscope = 'local';

    alert('함수안 '+vscope);

}

fscope();

alert('함수밖 '+vscope);




함수 안에서 vscope를 새로 정의하면 전역 변수 vscope는 제쳐두고 함수 안에서의 vscope를 새로 생성함. 이러한 사실은 다음 코드를 실행해보면 알 수 있음.


var vscope = 'global';

function fscope(){

    vscope = 'local';

    alert('함수안'+vscope);

}

fscope();

alert('함수밖'+vscope);




함수 안에서 vscope의 값을 ‘local’로 바꾸어 주었기 때문에 밖에서 전역변수 vscope를 호출해도 ‘local’이 출력됨.


변수를 선언할 때는 꼭 var을 붙이는 것을 습관화해야 한다. 전역변수를 사용해야 하는 경우라면 그것을 사용하는 이유를 명확히 알고 있을 때 사용하도록 하자.’


불가피하게 전역 변수를 사용해야 할 때는 하나의 객체를 전역변수로 만들고 객체의 속성을 변수로 관리하는 방법 사용.


MYAPP = {}

MYAPP.calculator = {

    'left' : null,

    'right' : null

}

MYAPP.coordinate = {

    'left' : null,

    'right' : null

}

 

MYAPP.calculator.left = 10;

MYAPP.calculator.right = 20;

function sum(){

    return MYAPP.calculator.left + MYAPP.calculator.right;

}

 

전역변수를 사용하고 싶지 않다면 익명 함수를 호출하는 것으로 대체할 수 있음.


(function(){

    var MYAPP = {}

    MYAPP.calculator = {

        'left' : null,

        'right' : null

    }

    MYAPP.coordinate = {

        'left' : null,

        'right' : null

    }

    MYAPP.calculator.left = 10;

    MYAPP.calculator.right = 20;

    function sum(){

        return MYAPP.calculator.left + MYAPP.calculator.right;

    }

    document.write(sum());

}())

 

JavaScript는 블록범위(중괄호 기준으로)를 기준으로 유효범위를 제공하는데 반해 함수에 대한 유효범위만 제공. , 지역변수는 함수에서만 유효.

JavaScript는 함수가 선언된 시점에서의 유효범위를 가짐.

ð  이러한 유효범위 방식을 정적 유효범위(Static Scoping), 혹은 렉시컬(Lexical Scoping)이라고 함.


var i = 5;

function a(){

    var i = 10;

    b();

}

function b(){

    document.write(i);

}

a();



 

값으로서의 함수

JavaScript에서는 함수도 객체, 즉 일종의 값임. 그러므로 객체의 값으로 포함될수도, 다른 함수의 인자로 전달될수도 있음.


function cal(func, num){

    return func(num)

}

function increase(num){

    return num+1

}

function decrease(num){

    return num-1

}

alert(cal(increase, 1));

alert(cal(decrease, 1));




함수는 함수의 리턴 값으로도 사용 가능하고, 객체로써 포함될 수 있으므로 당연히 배열의 값으로도 사용할 수 있음.


function cal(mode){

    var funcs = {

        'plus' : function(left, right){return left + right},

        'minus' : function(left, right){return left - right}

    }

    return funcs[mode];

}

alert(cal('plus')(2,1));

alert(cal('minus')(2,1));





var process = [

    function(input){ return input + 10;},

    function(input){ return input * input;},

    function(input){ return input / 2;}

];

var input = 1;

for(var i = 0; i < process.length; i++){

    input = process[i](input);

}

alert(input);



 

함수가 값으로 사용될 수 있다는 특성을 사용해 함수의 인자로 전달할 수도 있음. 이는 콜백의 특성.

 

콜백: 다른 코드의 인수로서 넘겨주는 실행 가능한 코드. 콜백을 넘겨받는 코드는 이 콜백을 필요에 따라 즉시 실행할 수도 있고, 아니면 나중에 실행할 수도 있음.

일반적으로 콜백 수신 코드로 콜백 코드(함수)를 전달할 때는 콜백 함수의 포인터 (핸들), 서브루틴 또는 람다함수의 형태로 넘겨준다. 콜백수신 코드는 실행하는 동안에 넘겨받은 콜백 코드를 필요에 따라 호출하고 다른 작업을 실행하는 경우도 있다. 다른 방식으로는 콜백수신 코드는 넘겨받은 콜백 함수를 '핸들러'로서 등록하고, 콜백수신 함수의 동작 중 어떠한 반응의 일부로서 나중에 호출할 때 사용할 수도 있다 (비동기 콜백).

 

값으로 전달된 함수(Callee)는 호출될 수 있다는 점을 이용해 Caller 함수의 동작을 완전히 바꿀 수 있음.



function sortNumber(a,b){

    return b-a;

}

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

alert(numbers.sort(sortNumber));




원래 sort는 숫자를 순서대로 정렬하지만 sortNumber 함수를 인자로 넘겨줌으로써 역순으로 정렬하게 되었다.

시간이 오래 걸리는 작업이 있을 때 이 작업이 완료된 후에 처리해야 할 일을 콜백으로 지정하면, 해당 작업이 끝났을 때 미리 등록한 작업이 실행되도록 비동기 처리를 할 수 있다.


생활코딩의 비동기 처리 강의에서는 이런 예시를 들었다. 글을 작성하면 구독자에게 이메일을 보낸 후 작성완료 문구를 띄우는 홈페이지를 사용한다고 가정한다. 여기서 글을 작성하고 구독자에게 이메일을 보내는 작업을 끝낸 후 작성 완료 문구를 띄우는 것은 일을 순차적으로 처리하는 ‘동기 처리’이다. 그런데 여기서 글을 작성하고 구독자들에게 이메일을 보내는 작업을 예약시키기만 하고 바로 작성 완료 문구를 띄운다. 그리고 클라이언트 쪽에서는 보이지 않게 백그라운드에서 이메일 발송 예약이 있는지 지속적으로 확인해 발송하는 작업을 하는 프로그램을 통해 이메일을 전송하는 작업을 계속 한다면, 이것은 비동기 처리이다.

 


 

 

'Programming > Web Programming' 카테고리의 다른 글

JavaScript Basic #6  (0) 2017.07.21
JavaScript Basic #5  (0) 2017.07.18
JavaScript Basic #3  (0) 2017.07.16
JavaScript Basic #2  (0) 2017.07.15
JavaScript Basic #1  (0) 2017.07.13
Posted by BinZIP
Programming/Web Programming2017. 7. 16. 02:33

JavaScript#3


UI & API


API: Application Programming Interface, 프로그램에서 사용할 수 있도록 OS나 프로그래밍 언어가 제공하는 기능을 제어하기 위해 만든 조작 장치.

UI: User Interface, 유저가 직접 프로그램을 사용할 때 제공되는 인터페이스.

Java Script API는 크게 JavaScript 자체 API JavaScript가 동작하는 호스트 환경의 API로 구분

 

정규표현식


Regular Expression. 문자열에서 특정한 문자를 찾아내는 도구.

정규표현식은 두 가지 단계로 이루어짐. 하나는 컴파일, 다른 하나는 실행.


1.    컴파일 (Compile)


-       검출하고자 하는 패턴을 만드는 일.

-       먼저 정규표현식 객체를 만들어야 함. 객체를 만드는 방법은 두 가지가 있음.

1.      정규표현식 리터럴:


var pattern = /a/


2.      정규표현식 객체 생성자:


var pattern = new RegExp(‘a’);

위 코드는 정규표현식 리터럴에 예시로 적은 코드와 같은 역할을 함.

 

2.    실행 (Execution)


정규표현식 메소드 실행

-       RegExp.exec(‘인자’): 입력한 패턴(RegExp의 괄호 안에 넣은 문자열)이 제공받은 인자 안에 있으면 패턴을 반환


alert(pattern.exec(‘asdf1234’));

alert(pattern.exec(‘qwerzxcv’));




인자에서 a를 찾으면 a라는 문자열을 반환하고, 그렇지 않으면 null을 반환하는 것을 볼 수 있음.

 

-       RegExp.test(‘인자’): 인자 안에 패턴에 해당되는 문자열이 있으면 True, 아니면 False를 반환


alert(pattern.test(‘asdf1234’));

alert(pattern.test(‘qwerzxcv’));




‘a’ 패턴이 있는 문자열에서는 true, 없는 문자열에서는 ‘false’를 반환하는 것을 확인할 수 있음.

 

문자열 메소드 실행

-       String.match(RegExp): RegExp.exec(‘인자’)와 비슷함.


alert(‘asdf1234’.match(pattern));

alert(‘qwerzxcv’.match(pattern));




패턴에 해당하는 문자가 String에 있으면 패턴의 문자열을 리턴, 그렇지 않으면 null을 리턴하는 것을 확인할 수 있음.

-       String.replace(RegExp, ‘변경할 문자열’): String에서 패턴을 검색해 패턴에 해당하는 부분을 변경할 문자열로 바꾸고 변경된 값을 리턴


alert(‘asdf1234’.replace(pattern,’q’));

alert(‘qwerzxcv’.replace(pattern,’q’));




String a q로 바뀌어 출력되는 것을 볼 수 있음.

옵션

-       i: i를 붙이면 대/소문자를 구분하지 않음.


alert('ASDF1234'.match(noCheckC));




-       g: 검색된 모든 결과 리턴


var Check = /a/;

var CheckAll = /a/g;

alert('asdfasdfasdf'.match(Check));

alert('asdfasdfasdf'.match(CheckAll));




-       캡처: 괄호 안의 패턴은 마치 변수처럼 재사용 할 수 있음.


var pattern = /(\w+)\s(\w+)/;

var str = "coding everybody";

var result = str.replace(pattern, "$2, $1");

alert(result);


공백(\s)을 기준으로 문자열이 2개의 그룹으로 나뉘었다고 생각하면 됨. , ‘coding’이라는 문자열이 $1, ‘everybody’라는 문자열이 $2인 것임.


-       치환


var urlPattern = /\b(?:https?):\/\/[a-z0-9-+&@#\/%?=~_|!:,.;]*/gim;

var content = '빈집 채우는 중 : http://binzip2.tistory.com 입니다.';

var result = content.replace(urlPattern, function(url){

    return '<a href="'+url+'">'+url+'</a>';

});

alert(result);



Html 하이퍼링크 태그로 치환시킨 것을 볼 수 있음.

'Programming > Web Programming' 카테고리의 다른 글

JavaScript Basic #5  (0) 2017.07.18
JavaScript Basic #4  (0) 2017.07.18
JavaScript Basic #2  (0) 2017.07.15
JavaScript Basic #1  (0) 2017.07.13
CSS #2  (0) 2017.07.12
Posted by BinZIP