[카테고리:] IT

다양한 IT 기술에 대한 내용을 공유합니다.

  • [JavaScript] 자바스크립트 클로저

    [JavaScript] 자바스크립트 클로저

    정의

    중첩함수에서 내부함수가 외부함수의 환경을 기억하는것을 클로저라고 한다.

    function func() {
        var foo = 'data';
        return function() {
            return foo;
        }
    }
    

    func라는 함수를 선언하고 foo변수에 ‘data’문자열을 추가한 뒤 foo변수를 리턴하는 익명함수를 선언하였다.

    var closure = func();
    console.log(closure());
    // 'data'
    

    func함수의 리턴값을 closure변수에 할당한 뒤 closure를 실행한 값을 콘솔로 찍어보았다. 결과는 ‘data’라는 문자열이 출력되었다. func의 지역변수로 있는 foo는 func함수가 끝나면서 소멸되어야하지만 값을 잃지 않고 ‘data’값을 가지고 있다. 이 현상을 클로저라 한다. 다른 구문도 살펴보겠다.

    function count() {
        var num = 0;
        return function() {
            num++;
            return num;
        }
    }
    
    var closure = count();
    console.log(closure());
    console.log(closure());
    console.log(closure());
    // 1
    // 2
    // 3
    

    count함수의 지역변수인 num값이 소멸되지 않고 계속 카운트되는 것을 확인해 볼 수 있다.

    특징

    변수의 은닉화

    자바스크립트에서는 인스턴스를 생성할때 Private Variables에 대한 접근 권한 문제가 있다.

    function Create(name) {
        this._name = name;
    }
    
    var obj = new Create('민수');
    console.log(obj._name);
    // 민수
    

    위에서 생성된 obj객체의 _name프로퍼티는 변수명 앞에 _를 포함하였기 때문에 Private Variables로 쓰고싶다는 의도를 알 수 있다. 하지만 _name프로퍼티는 동적으로 변경될 수 있다.

    obj._name = '인성';
    console.log(obj._name);
    // 인성
    

    이 경우 클로저를 사용하여 외부에서 내부변수에 접근하는것을 제한할 수 있다.

    function create(name) {
        var _name = name;
        return function() {
            console.log(_name);
        }
    }
    
    var hello = create('민수');
    hello();
    // 민수
    

    여기서는 외부에서 _name에 접근할 방법이 전혀 없다. 이렇게 클로저를 활용하여 은닉화를 해결할 수 있다.

    고유한 환경

    클로저는 고유한 환경을 가지고 있다.

    function func(name) {
        var txt = name;
        return function() {
            return txt;
        }
    }
    
    var closure01 = func('민수');
    var closure02 = func('인성');
    var closure03 = func('한나');
    
    console.log(closure01()) // 민수
    console.log(closure02()) // 인성
    console.log(closure03()) // 한나
    

    위의 구문을 보면 txt변수가 동적으로 변화하는 것처럼 보이지만, 실제로는 txt변수 자체가 여러번 생성된 것이다. 즉, closure01(), closure02(), closure03()은 서로 다른 환경을 가지고 있다. 서로 다른 환경을 가지고 있다는것은 그만큼 메모리면에서 큰 비효율을 낳는다.

    function Func(input) {
        this.name = input;
        this.get = function() {
            return this.name;
        }
        this.set = function (rename) {
            this.name = rename;
        }
    }
    
    var obj = new Func('민수');
    console.log(obj.get());
    

    위 코드는 생성자함수를 사용하여 인스턴스를 생성하는 구문인데, 클로저가 두번(get, set)이나 생성되었다. 이 상태에서 인스턴스를 계속 만들면 같은일을 하는 클로저가 중복으로 생성되고 메모리낭비가 심해질 것이다.
    따라서 클로저는 객체의 prototype안에 저장함으로써 같은 기능을 모든 인스턴스가 공유하는 형태로 코드를 만들어야한다.

    function Func(input) {
        this.name = input;
    }
    Func.prototype.get = function() {
        return this.name;
    };
    Func.prototype.set = function(rename) {
        this.name = rename;
    };
    
    var obj = new Func('민수');
    console.log(obj.get());
    

    이렇게 prototype안에 클로저를 넣으면, 인스턴스가 생성되더라도 중복으로 메모리를 낭비하지 않고, 생성자 내부의 prototype안의 클로저를 참조하기 때문에 메모리낭비를 방지할 수 있다.

    정리

    • 클로저는 독립적인(자유) 변수를 가리키는 함수 또는 클로저 안에 정의된 내부함수는 만들어진 환경을 기억한다.
    • 클로저는 외부함수의 스코프 영역에 접근할 수 있고, 그것을 기억하고 있어야 한다.
    • 외부함수가 종료된 후에도 내부함수는 외부함수를 계속 참조하고 있어야 한다.
    • 데이터의 캡슐화 및 정보은닉에도 사용 가능하다.

    References

    JavaScript 클로저(Closure)

  • [JavaScript] 이벤트 위임(Event Delegation)

    [JavaScript] 이벤트 위임(Event Delegation)

    어플리케이션을 제작할 때 사용자가 페이지 요소들을 조작할 수 있도록 페이지의 버튼, 텍스트 등에 이벤트를 붙여야 할 때가 있다. 아래 리스트의 각 요소를 클릭하면 경고창이 뜨는 이벤트를 걸어줘야 된다고 가정해보면 아래처럼 구현할 것이다.

    html

    <ul id="list">
        <li>list01</li>
        <li>list02</li>
        <li>list03</li>
        <li>list04</li>
        <li>list05</li>
    </ul>
    

    javascript

    var item = document.getElementById('list').getElementsByTagName('li');
    for (var i = 0; i < item.length; i++) {
    
        // 각 li에 이벤트 리스너를 등록한다.
        item[i].addEventListener('click', function(e) {
            alert(e.target.innerText);
        })
    }
    

    결과

    See the Pen 이벤트 위임 by recordboy (@recordboy) on CodePen.

    리스트 요소가 많이 없는 경우 위 코드는 별 문제가 되지 않는다. 하지만 리스트 요소가 천개, 만개라면 일일히 분리된 이벤트 리스너를 생성하고, 그걸 각각 요소에 등록할 것이다. 이는 매우 비효율적인 방법이다. 아이템 갯수마다 이벤트 리스너를 생성, 등록하는 것보다는 감싸고 있는 리스트에 한개의 이벤트를 등록하고, 조건을 달아줘서 리스트의 요소를 클릭했을시에만 경고창을 출력하도록 구현하면 된다.

    javascript

    var list = document.getElementById('list');
    var item = list.getElementsByTagName('li');
    
    // 리스트에 이벤트를 등록
    list.addEventListener('click', function(e) {
    
        // 리스트 요소일 때 경고창 출력
        if (e.target.nodeName === 'LI') {
            alert(e.target.innerText);
        }
    })
    

    References

    자바스크립트 코딩 면접에서 알고 있어야 할 3가지 질문

  • [JavaScript] 자바스크립트의 오류 유형

    [JavaScript] 자바스크립트의 오류 유형

    구문 오류(Syntax Error)

    자바스크립트 규칙에 어긋나는 문법으로 작성하여 자바스크립트 엔진이 이해 못 할 문자가 입력되었을 때 발생한다. 요즘에는 에디터 내부에서 오류를 친절하게 찾아주기 때문에(ESlint 혹은 Prettier) 브라우저에서 구문 오류는 찾아보기가 힘들어 졌다.

    예제

    문자열을 따옴표로 닫지 않고 변수에 할당함

    let text = 'hello
    
    오류 메세지

    Uncaught SyntaxError – 유효하지 않거나 예상치 못한 토큰

    Uncaught SyntaxError: Invalid or unexpected token
    

    타입 에러(Type Error)

    가장 많이 발생하는 에러중 하나로 구문의 기대하는 값이 아닐 경우 오류가 발생한다. 쉽게 말해 변수의 값이 원하는 값이 아닐 때 나타난다고 볼 수 있다.

    예제 1

    obj 객체에 없는 함수 myFunc를 호출할 때 타입 에러가 발생한다.

    let obj = {};
    let result = obj.myFunc();
    
    오류 메세지

    Uncaught TypeErrorobj.myFunc는 함수가 아닙니다

    Uncaught TypeError: obj.myFunc is not a function
    
    예제 2

    obj 값이 null 혹은 undefined일 경우 없는 프로퍼티를 호출하면 에러가 발생한다.

    let obj = null;
    // or
    let obj;
    
    let result = obj.myProperty;
    
    오류 메세지

    Uncaught TypeError – 정의되지 않은 속성을 읽을 수 없습니다

    Uncaught TypeError: Cannot read properties of undefined (reading 'myProperty')
    

    타입 에러의 방어 코드(단축 평가)

    해당 변수의 객체가 있을 경우에만 프로퍼티(혹은 함수)를 사용하고 싶다면 오류가 발생하지 않도록 아래처럼 방어 코드(단축 평가)를 추가할 수 있다. 리액트같은 라이브러리를 사용하는 경우 state가 선언되기 전에 렌더링 될때 타입 에러가 발생되는 경우가 많은데 아래처럼 사용이 가능하다.

    let result = obj && obj.myProperty;
    // obj가 존재할 경우에만 myProperty 프로퍼티를 호출
    

    참조 에러(Reference Error)

    참조 에러는 현재 범위에 존재하지 않거나 선언하지 않은 변수를 참조하였을때 발생하는 에러유형이다.

    예제

    선언되지 않은 함수 boo를 호출하면 참조 에러가 발생한다.

    function foo() {}
    boo();
    
    오류 메세지

    Uncaught ReferenceError – boo가 정의되지 않았습니다

    Uncaught ReferenceError: boo is not defined
    

    범위 에러(Reference Error)

    어떤 값이나 데이터가 유효한 자원의 범위를 넘어설 때 발생한다. 대표적으로 콜 스택 초과 에러가 있다.

    예제

    foo 함수는 boo를 호출하고 boo 함수는 foo를 호출하면 무한 루프가 걸리면서 스택이 오버되었을 때 오류가 난다.

    function foo() {
        boo();
    }
    function boo() {
        foo();
    }
    foo();
    
    오류 메세지

    Uncaught RangeError – 최대 호출 스택 크기 초과

    Uncaught RangeError: Maximum call stack size exceeded
    

    그 외 에러

    이 외에도 아래와 같은 에러들이 존재한다.

    • EvalError : eval() 함수와 관련한 오류가 발생했을 때
    • InternalError : 자바스크립트 엔진 내부에서 오류가 발생했을 때
    • URIError : encodeURI()decodeURI() 함수에 부적절한 매개변수를 제공했을 때

    References

    MDN Web Docs – Error
    자주 발생하는 자바스크립트 에러
    자바스크립트 오류 확인하는 방법과 7가지 오류 유형

  • [JavaScript] 자바스크립트 모듈 패턴

    [JavaScript] 자바스크립트 모듈 패턴

    모듈 패턴이란?

    모듈이란 전제 어플리케이션의 일부를 독립된 코드로 분리하여 만들어 놓은 것이다.

    모듈화를 했을 때 장점

    • 자주 사용되는 코드를 별도의 파일로 만들어서 필요할 때마다 활용할 수 있다.
    • 코드를 개선하면 이를 사용하고 있는 모든 애플리케이션의 동작이 개선된다.
    • 코드 수정 시에 필요한 로직을 빠르게 찾을 수 있다.
    • 필요한 로직만을 로드해서 메모리의 낭비를 줄일 수 있다.
    • 한번 다운로드된 모듈은 웹브라우저에 의해서 저장되기 때문에 동일한 로직을 로드할 때 시간과 네트워크 트래픽을 절약할 수 있다.(브라우저에서만 해당)

    객체 리터럴을 사용한 모듈 패턴

    자바스크립트에서 모듈을 구현하는 가장 쉬운 방법은 객체 리터럴을 사용하는 방법이다.

    var module = {
        key: 'data',
        publicMethod: function() {
            return this.key;
        }
    }
    
    console.log(module.key); // data
    console.log(module.publicMethod()); // data
    

    객체 리터럴은 모듈 패턴이기도 하며, 하나의 객체라는 점에서 싱글톤 패턴이라고도 할 수 있다. 동일한 코드를 어떠한 관점에서 보느냐에 따라 다양한 패턴이 될 수 있다. 객체 리터럴은 간단하지만 모든 속성이 공개되어있다는 단점이 있다. 독립된 모듈은 자체적으로 필요한 내부 변수 및 내부 함수를 모두 갖고 있어야 하므로 클로저를 이용해야 한다.

    아래는 클로저를 활용한 모듈패턴이다.

    클로저를 활용한 모듈 패턴

    var module = (function() {
    
        /**
            * -----------------------
            * 모듈 패턴을 구현할 클로저 코드
            * -----------------------
            */
    
        // 은닉될 멤버 정의
        var privateKey = 0;
        function privateMethod() {
            return privateKey++;
        }
    
        // 공개될 멤버(특권 메서드) 정의
        return {
            publicKey: privateKey,
            publicMethod: function() {
                return privateMethod();
            }
        }
    
    })();
    
    console.log(module.publicMethod()); // 0
    console.log(module.publicMethod()); // 1
    

    모듈 패턴의 반환값은 함수가 아닌 객체이다. 위의 코드를 순서대로 보면 익명함수가 자동으로 실행되고 반환된 객체를 module 변수에 할당한다. 따라서 module.publicMethod()처럼 메서드를 호출할 수 있다. 자동 호출되는점을 제외하고 클로저와 유사하다.

    클로저 경우

    function func() {
        var private = 0;
        return function() {
            private++;
            return private;
        }
    }
    var val = func();
    console.log(val()); // 1
    console.log(val()); // 2
    

    그리고 인스턴스를 여러개 만들어 낼 수 있는 구조라는 점에서 싱글톤 패턴과 차이가 있다.

    싱글톤 패턴 경우

    var singleton = (function() {
    
        var instance;
        var private = 0;
        function init() {
            return {
                publicKey: private,
                publicMethod: function() {
                    return publicKey;
                }
            }
        }
        return function() {
    
            // 싱글톤 패턴은 아래 조건문에서 처음 인스턴스가 선언되면 다시 인스턴스를 만들지 않고 기존의 인스턴스를 리턴한다.
            if (!instance) {
                instance = init();
            }
            return instance;
        }
    })()
    
    var singleton1 = singleton();
    var singleton2 = singleton();
    console.log(singleton1 === singleton2); // true
    

    하나의 인스턴스를 선언하지 않고 여러개의 인스턴스를 생성하려면 익명함수를 사용하지 않고 생성자 함수 방식으로 만들면 된다.

    var Module = function() {
    
        var privateKey = 0;
        function privateMethod() {
            return privateKey++;
        }
    
        return {
            publicKey: privateKey,
            publicMethod: function() {
                return privateMethod();
            }
        }
    
    }
    
    var obj1 = Module();
    console.log(obj1.publicMethod()); // 1
    console.log(obj1.publicMethod()); // 2
    
    var obj2 = Module();
    console.log(obj2.publicMethod()); // 1
    console.log(obj2.publicMethod()); // 2
    

    위처럼 Module 함수를 정의하여 함수를 호출하면 여러개의 인스턴스를 생성할 수 있다. 클로저 인스턴스와 유사하지만, 한가지 차이점은 내부의 익명함수에서 반환값이 함수가 아니라 객체를 반환한다는 점이다.

    모듈 패턴과 네임 스페이스 패턴을 함께 사용하면 더욱 깔끔한 코드가 완성된다.

    var app = app || {};
    app.module = (function() {
    
        var privateKey = 0;
        function privateMethod() {
            return privateKey++;
        }
    
        return {
            publicKey: privateKey,
            publicMethod: function() {
                return privateMethod();
            }
        }
    })();
    
    console.log(app.module.publicMethod()); // 0
    console.log(app.module.publicMethod()); // 1
    

    References

    module pattern (모듈패턴) #1
    [JS_Design Pattern] 2. 모듈 패턴 (Module Pattern)

  • [GitHub] 깃허브 호스팅 페이지에서 404 오류 나올 경우

    [GitHub] 깃허브 호스팅 페이지에서 404 오류 나올 경우

    깃허브 호스팅 페이지가 404에러가 뜰 경우 아래 명령어를 실행하자, 설명은 아래 레퍼런스 참조

    $ git commit --allow-empty -m 'Trigger rebuild'
    $ git push origin
    

    References

    How to fix HTTP 404 on Github Pages?

  • [JavaScript] 자바스크립트 싱글톤 패턴

    [JavaScript] 자바스크립트 싱글톤 패턴

    전체 시스템에서 하나의 인스턴스만 존재하도록 보장하는 객체 생성패턴을 의미한다. 대표적으로 $를 활용해서 DOM을 조작하고 이벤트도 다루는 jQuery가 있으며, 객체 리터럴도 싱글톤 패턴이라고 할수 있다.(자바스크립트에서 객체 리터럴로 생성한 객체는 다른 객체와 같을 수 없다. 객체 내부의 내용이 같더라도 참조하는 객체가 다르기 때문이다.) 객체 리터럴은 한계가 있는데 비공개 프로퍼티 및 함수를 선언할 수 없다.

    var obj = {
        name: 'myName',
        get: function() {
            return this.name;
        }
    }
    console.log(obj.get()); // myName
    

    비공개 프로퍼티 및 함수를 정의하려면 클로저(closure)를 활용해야 한다. 즉 제대로 된 싱글톤 패턴은 객체 리터럴 + 클로저의 조합이 필요하다고 할 수 있다. 아래 코드를 확인해보면

    var singleton = (function() {
    
        // 비공개 프로퍼티 정의
        var instance;
    
        // 비공개 메서드 정의
        function init() {
    
            // singleton 인스턴스 정의
            return {
    
                // 공개 프로퍼티 정의
                prop: 'value',
    
                // 공개 메서드 정의
                method: function() {
                    return 'hello'
                }
    
            };
    
        }
    
        // 공개 메서드인 getInstance를 정의한 객체, 비공개 프로퍼티 및 메서드에 접근 가능(클로저)
        return {
    
            getInstance: function() {
    
                // 인스턴스가 선언이 안되있는경우 인스턴스 생성
                if (!instance) {
                    instance = init();
                }
    
                // 인스턴스가 선언이 되있는 경우 인스턴스 반환
                return instance;
    
            }
        }
    })()
    
    var singleton1 = singleton.getInstance();
    console.log(singleton1.method());
    var singleton2 = singleton.getInstance();
    console.log(singleton1 === singleton2); // true
    

    위 코드는 비공개 메서드인 init()의 return문에서 객체 리터럴로 정의되는 인스턴스가 싱글톤 객체이며, 전체 시스템에서 하나만 존재하게 된다. 순서대로 보면 익명함수의 return문에는 싱글톤 객체를 구하는 공개 메서드(getInstance)를 포함한 객체를 반환하며, getInstance메서드는 instance값을 확인해 인스턴스가 선언이 안되있는 경우 비공개 메서드인 init를 호출하여 singleton인스턴스를 생성하여 instance에 할당하게 된다.

    이렇게 일반적으로 싱글톤 패턴에서는 이미 객체가 생성되었는지 여부를 알려주는 instance와 같은 내부 변수가 필요하다. 그리고 싱글톤 패턴에서는 내부 변수에 접근할 수 있는 객체를 반환하는 클로저를 이용해야 한다.

    정리를 하면 내부의 getInstance메서드에서 비공개 프로퍼티인 instance에 접근할 수 있다는 것과, getInstance메서드의 호출이 끝나더라도 instance의 값은 계속 유지되는 특성(클로저)를 이용해 prop, method()이 포함된 객체를 유일하게 생성하게 된다. 그래서 singleton.getInstance()를 몇번이나 호출하더라도 얻는 객체는 모두 동일한 싱글톤 객체를 가리키게 된다.

    References

    싱글톤(singleton) 패턴

  • [JavaScript] ES6 클래스(Class)

    [JavaScript] ES6 클래스(Class)

    ES6에서 class라는 문법이 추가되었고, 기존의 prototype 기반으로 클래스를 선언하는 것보다 명료하게 클래스를 선언할 수 있게 되었다.

    기존(ES5) 클래스(생성자)

    함수를 만들 때는 함수 표현식과 선언식이 있으며, 선언식으로 작성한 클래스는 호이스팅이 일어난다. 여기서 호이스팅이란 함수를 선언했을 때 값들이 유효범위 최상단에 선언되는 것을 말한다.

    함수 표현식

    클래스가 선언되기 전에 인스턴스를 생성하여 에러가 뜬다.

    var obj = new Person('한나');
    obj.getName(); // TypeError
    
    var Person = function(name) {
        this.name = name;
        Person.prototype.getName = function() {
            console.log(this.name);
        }
    }
    

    함수 선언식

    인스턴스를 함수 선언 전에 생성해도 오류가 나지 않는다. 클래스를 선언식으로 작성하여 호이스팅되었기 때문이다.

    var obj = new Person('한나');
    obj.getName(); // 한나
    
    function Person(name) {
        this.name = name;
        Person.prototype.getName = function() {
            console.log(this.name);
        }
    }
    

    새로운(ES6) 클래스(생성자)

    class Person {
        constructor(name) {
            this.name = name;
        }
        getName() {
            console.log(this.name);
        }
    }
    
    const obj = new Person('민수');
    obj.getName(); // 민수
    

    위 코드는 새로운 클래스 키워드로 클래스를 선언하고 인스턴스를 만든 것이다. 함수 선언이 표현식과 선언식이 있듯이 클래스 키워드도 선언식과 표현식 두가지 방법으로 정의가 가능하다.

    const obj = new Person('민수');
    obj.getName(); // ReferenceError
    
    class Person {
        constructor(name) {
            this.name = name;
        }
        getName() {
            console.log(this.name);
        }
    }
    

    위 코드는 에러를 출력하고 있다. 이유는 새로운 클래스는 호이스팅이 일어나지 않는다. 아니 엄밀히 말해 호이스팅이 발생하지 않는 것처럼 동작하는건데 이거는 추후에 알아보도록 하겠다.

    constructor

    constructor는 인스턴스를 생성하고 클래스 필드를 초기화하기 위한 특수한 메서드이다.

    클래스 필드(class field) 클래스 내부의 캡슐화된 변수를 말하며, 데이터 혹은 멤버 변수라고 부른다. 자바스크립트의 생성자 함수에서 this에 추가한 프로퍼티를 클래스 기반 객체지향 언어에서는 클래스 필드라고 부른다.

    class Person {
        constructor(name) {
            // 여기서 this는 생성될 인스턴스를 바라보고 있다.
            this.name = name;
        }
    }
    

    constructor는 클래스 내에 한 개만 존재할 수 있으며 이 함수 안에 프로퍼티를 작성하면 되며, 이 안에서 this는 생성될 인스턴스를 바라보고 있다.

    메서드 정의

    class Person {
        constructor(name) {
            this.name = name;
        }
        // 클래스 몸체에는 메서드만 선언할 수 있다.
        getName() {
            console.log(this.name);
        }
    }
    

    클래스 몸체 안에는 메서드만 선언할 수 있다. 클래스 몸체 안에 프로퍼티를 선언하면 오류를 출력한다.

    extends

    ES6 클래스는 extends키워드로 상속을 구현한다.

    class Wrap {
        constructor(name) {
            this.name = name;
        }
        getName() {
            console.log(this.name + ' 슈퍼');
        }
    }
    
    class Inner extends Wrap {
        getName() {
            super.getName()
            console.log(this.name + ' 상속 받은 클래스');
        }
    }
    
    var obj = new Inner('안녕');
    obj.getName();
    
    // 결과
    // 안녕 슈퍼
    // 안녕 상속 받은 클래스
    

    위 코드를 보면 InnerWrap를 상속 받았으며, new Inner('안녕')를 실행하면 아래의 과정을 거치게 된다.

    1. Inner클래스의 constructor를 호출
    2. Inner클래스의 constructor를 작성하지 않았기 때문에 super클래스(Wrap)의 constructor가 호출됨(내부적으로 프로토타입 체인으로 인해)
    3. super클래스의 constructor에서 this는 현재의 인스턴스를 참조하므로 인스턴스의 name프로퍼티로 전달받은 값을 설정
    4. 생성한 인스턴스를 Inner에 할당

    super

    위에 코드에서도 잠깐 나왔지만 super키워드는 슈퍼 클래스의 메서드를 호출할 수 있다.

    class Wrap {
        msg() {
            console.log('안녕');
        }
    }
    
    class Inner extends Wrap {
        msg() {
            // 슈퍼 클래스의 msg메서드를 실행한다.
            super.msg();
        }
    }
    
    var obj = new Inner();
    obj.msg();
    

    static

    static키워드는 클래스를 위한 정적(static) 메서드를 정의한다. 정적 메서드는 prototype에 연결되지 않고 클래스에 직접 연결되기 때문에 클래스의 인스턴스 없이 호출되며, 클래스의 인스턴스에서는 호출할 수 없다.

    class Inner {
    
        // 인스턴스 없이 클래스에 바로 메서드를 선언해줌
        static msg() {
            console.log('안녕');
        }
    }
    
    Inner.msg(); // 안녕
    
    var obj = new Inner();
    obj.msg(); // TypeError
    

    동일한 클래스 내의 다른 정적 메서드 내에서 정적 메서드를 호출하는 경우 키워드 this를 사용할 수 있다.

    class Inner {
        static msg() {
            console.log('안녕');
        }
        static msg2() {
            this.msg();
        }
    }
    
    Inner.msg2(); // 안녕
    

    정적 메서드는 어플리케이션을 위한 유틸리티 함수를 생성하는데 주로 사용된다.

    References

    [JS] javascript – OOP Class, Super
    ES6 Class 파헤치기
    super
    클래스

  • [JavaScript] 디바이스 구분 스크립트

    [JavaScript] 디바이스 구분 스크립트

    어떤 디바이스로 접속했는지 확인 가능한 코드

    var filter = "win16|win32|win64|macintel|mac|"; // PC일 경우 가능한 값
    if (navigator.platform) {
        if (filter.indexOf(navigator.platform.toLowerCase()) < 0) {
            alert("모바일에서 접속하셨습니다");
        } else {
            alert("PC에서 접속하셨습니다");
        }
    }
    
  • [JavaScript] 자바스크립트 변수 명명 규칙

    [JavaScript] 자바스크립트 변수 명명 규칙

    변수, 함수명은 카멜 케이스를 사용한다.

    첫글자는 소문자, 단위로 첫글자 대문자를 사용, 중간에 언더바(_)사용 금지한다. 대표적인 표기법으로 카멜 케이스, 파스칼 표기법, 헝가리안 표기법, 스네이크 표기법이 있으며 사용하는 언어에 따라 권장사항이 다르다.

    var pageName;
    

    상수는 영문 대문자 스네이크 표기법을 사용한다.

    var SYMBOLIC_NAME;
    

    여러 단어가 합쳐져 만들어진 약어(HTML, XML)의 경우는 전부 대문자로 사용한다.

    var HTML;
    

    생성자 함수는 대문자 카멜 케이스를 사용한다.

    function Func() {
        ...
    }
    

    지역변수 혹은 private 변수는 언더바(_)로 시작한다.

    var _private;
    

    예약어를 사용하지 않는다.

    // bad
    var if;
    var for;
    var this;
    ...
    

    전역 변수를 사용하지 않는다.

    모든 컴파일 단위는 하나의 공용 전역 객체(window)에 로딩된다. 전역 변수는 언제든지 프로그램의 모든 부분에서 접근할 수 있기 때문에 편하지만, 바꿔 말하면 프로그램의 모든 부분에서 변경될 수 있고, 그로 인해 프로그램에 치명적인 오류를 발생시킬 수 있다.

    var global = 'data';
    

    암묵적 전역 변수를 사용하지 않는다.

    // bad
    function sum(x, y) {
      result = x + y;
      return result;
    }
    
    // bad
    function foo() {
      var a = b = 0; // var a = (b = 0);와 같다. b가 암묵적 전역이 된다.
    }
    
    // good
    function sum(x, y) {
      var result = x + y;
      return result;
    }
    
    // good
    function foo() {
      var a, b;
      a = b = 0;
    }
    

    References

    코딩 컨벤션

  • [Nginx] Nginx 기본 세팅

    [Nginx] Nginx 기본 세팅

    Nginx 설치

    # rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
    # rpm -Uvh https://mirror.webtatic.com/yum/el7/webtatic-release.rpm
    # yum install nginx.x86_64
    # systemctl start nginx
    # systemctl enable nginx
    

    PHP 설치

    # yum install yum-plugin-replace
    # yum install mod_php71w php71w-common
    # yum install php71w-gd
    # yum install php71w-fpm
    # yum install php71w-opcache
    # yum install php71w-cli
    # yum install php71w-mysqlnd
    # yum install php71w-xml
    # yum install php71w-mbstring
    
    # sed -i 's/;date.timezone =/date.timezone = Asia\/Seoul/g' /etc/php.ini
    
    # yum install -y make automake gcc gcc-c++ kernel-devel openssl-devel php php-devel php-pear bzip2-devel libvpx-devel yum-utils bison re2c libmcrypt-devel libpqxx-devel libxslt-devel pcre-devel libcurl-devel libgsasl-devel openldap-devel libmemcached-devel libjpeg-devel libpng-devel readline-devel
    
    # systemctl start php-fpm
    # systemctl enable php-fpm
    

    nginx.conf 파일찾기

    # sudo find / -name nginx.conf
    

    nginx.conf 수정하기

    # vi /etc/nginx/nginx.conf
    

    nginx 다시 로드 하기

    # sudo service nginx reload