본문으로 바로가기

Javascript

category Frontend 2020. 1. 29. 19:56
    반응형

    정의

    • 프로토타입 기반 객체 지향 프로그래밍 언어
    • 웹 브라우저 내에서 주로 사용된다. 웹 브라우저를 통해서 실행된다.
      • Node.js의 경우 자바스크립트 엔진을 통해서 실행된다.(서버사이드)
    • 자바스크립트는 스크립트 언어이므로 인터프리터를 통해서 실행된다.
    • ECMA-262에서 표준을 정의하며 브라우저마다 지원하는 자바스크립트 버전이 다르다.
      • ECMA-262 3판은 자바스크립트 버전은 1.5이다.
      • 현재 브라우저 지원은 ES5, 자바스크립트 프레임워크는 ES6, 최신버전은 ES10
    • 마치 자바와 관련되어 보이지만 자바와 자바스크립트 둘다 C언어의 기본 구문을 바탕으로 두었다.
      • 자바는 클래스 기반 객체지향 프로그래밍 언어
      • 자바스크립트는 프로토타입 기반 객체지향 프로그래밍 언어
    • 다른 응용 프로그램의 객체에 접근할 수 있는 기능이 있다.
      • 문서 객체 모델(DOM)을 통해 웹 페이지 컨텐츠를 조작하는 메서드와 인터페이스를 제공한다.

    npm(Node Package Manager)

    node.js에서 빠질 수 없는게 npm인데 사실 저 같은경우는 bower 및 grunt를 사용하기 위해 npm을 그러면서 자연스럽게 node.js를 접하게 되었다.
    node.js가 빠른 발전을 할 수 있었던 것도 이 npm덕분이라 생각하는데
    npm은 위에 설명한 것 처럼 Node Package Manager의 약자로 node.js에서 사용하는 모듈들을 패키지로 만들어 npm을 통하여 관리하고 배포하고 있다.
    이게 무엇을 의미하냐면 다른 사람이 잘 만들어놓은 모듈들을 npm을 통하여 설치하여 사용이 가능하다는 점이다.
    또한 이 모듈이 사용하고있는 다른 모듈의 의존성또한 자동으로 해결해준다.
    어떻게? npm install 이 명령어 한번으로 말이다.
    다른언어에서 비슷한 개념으로

    • ruby의 Gem
    • php의 Composer
    • C#의 NuGet
    • java의 Jpm
    • python의 pip

    등 있으며 대부분 이러한 패키지 매니저가 의존성도 다 해결해주고 있다.

    프레임워크

    • Vue.js, Angular.js, React.js
      • 싱글 페이지 어플리케이션 개발을 위해 필요한 기술들을 제공한다.
    • Node.js
      • 확장성 있는 네트워크 어플리케이션 개발에 사용되는 소프트웨어 플랫폼
      • Non-blocking I/O와 단일 스레드 이벤트 루프를 통한 높은 처리 성능
      • 내장 HTTP
      • V8(자바스크립트 엔진)으로 빌드된 이벤트 기반 자바스크립트 런타임

    특징

    • 자바스크립트는 객체 기반의 언어이다. 하지만 상속과 클래스라는 개념이 없다.
    • 프로토타입 체이닝을 통해 비슷하게 상속 기능을 제공함.

    기본문법

    • 식별자는 변수명과 함수명을 의미한다.
    • 시스템에서 지정된 명령어를 키워드라고 한다. (var, for 같은 것들)

    키워드

    • const 변수명 : 상수 선언

    데이터타입

    • 자바스크립트 기본 타입 (5가지)
      • 수 (Number)
      • 문자열 (String)
      • 불린 (Boolean)
      • 널 (NuLL)
      • 정의되지않음(Undefined)
    • 느슨한 타입 체크 언어이다. var 키워드 사용.
    • 데이터에 따라 해당 변수의 타입이 지정됨.
    • null은 값이 없다는 표시
    • 선언되지 않거나 값이 할당되지 않은 변수(즉 타입 미정)을 나타내는 자료형은 undefined 자료형이라 하고 자료형인 동시에 값이 될 수 있다.
    • false로 표현되는 것들은 0, NaN, '', null, undefined가 있다.

    연산자

    • typeof 연산자는 피연산자의 타입을 문자열형태로 반환한다.
    • == 동등과 ===일치. 동은은 타입변환 후 비교, 일치는 타입변환하지 않고 비교
    • !!는 피연산자를 불린값으로 변환할 때 사용.
    • in 은 피연산자가 해당 객체 안에 존재하는지 확인 할 때 사용. (test in window 윈도우 안에 test라는 변수가 정의되어있는지 확인)

    리터럴

    문자열 리터럴 String();

    숫자 리터럴 Number();

        var str = new String("test");
        alert(typeof str); // Object
    
        var literal = String("test");
        alert(typeof literal); // String 
    

    함수(Function)

    • 함수는 일급 객체이다.
    • 함수 생성 시 프로토타입 객체를 갖는다. 프로토타입을 통해서 객체를 생성.
    • 함수 생성
      • 함수선언
      • function add(a, b) { return a+b; }
      • 함수표현
      • var add = function() { return a+b; };
      • 함수선언과 함수표현의 차이점은 함수 호이스팅 차이이다,
      • 코딩가이드들이 함수표현식으로 생성하기를 권고함.
        • 함수선언식을 사용하면 코드 가독성이 떨어진다고함.
        • 함수선언식을 사용하면 선언문은 자바스크립트 맨 위에 작성하자.
    1. 콜백함수
    2. 즉시 실행 함수

    함수를 정의함과 동시에 바로 실행하는 함수

    최초 한번의 실행만을 필요로 하는 초기화 코드 부분 등에 사용

    자바스크립트의 변수 유효 범위 특성을 이용하여 라이브러리 코드가 전역 네임스페이스에 들어가지 않게 하기 위해서 사용한다.

        (function (name) {
            console.log("this is the immediate function --> " + name);
        })("foo"); //바로 실행 된다.
    1. 내부함수

    클로저를 통해서 부모 함수 코드에서 외부에서의 접근을 막고 독립적인 헬퍼 함수를 구현하는데 사용

        function parernt() {
            var a = 100;
            var b = 200;
    
            //child() 내부 함수 정의
            function child() {
                var b = 300;
                console.log(a);
                console.log(b);
            }
    
            child();
        }
    
        parenrt();
        child();
    1. 함수를 리턴하는 함수
    2. 함수 호출 시 암묵적으로 전달되는 arguments, this 인자
      1. 가변인자 함수
      2. var print = function () { if(arguments.length == 0) console.log("인자 0"); else if(arguments.length == 1) console.log(arguments[0]); else if(arguments.length == 2) console.log(arguments[0], arguments[1]); }; print(); print(1); print(1,2);
    3. this 바인딩
      • 객체 함수에서 호출 시 호출한 함수의 객체에 바인딩
      • 함수에서 호출 시 전역 객체에 바인딩된다. (브라우저에서 자바스크립트를 생하는 경우 전역 객체는 window 객체가 된다.)
      • 내부함수에서 호출 시 전역 객체 바인딩 됨
    4. 생성자 함수
    • 특정 함수가 생성자 함수로 정의되어 있음을 알리기 위해 함수 이름의 첫문자를 대문자로 쓰기를 권고한다.
    • 생성자 함수에서 리턴값이 지정되지 않은 경우 객체가 리턴된다.
    • 생성자 함수를 new 없이 호출할 경우
      • this가 전역변수를 바인딩한다.
      • 리턴값이 없으므로 undefined가 반환된다.
      • 생성자 함수가 new 없이 호출되는 것을 막는 방법
      • function A(arg) { if(!(this instanceof arguments.callee)) return new arguments.callee(arg); this.value = arg ? arg : 0; } var a = new A(100); // 정상생성 var b = A(10); // 정상 생성
      • function.apply, function.call을 통한 객체 생성

    객체

    • 프로퍼티와 메소드
    • 객체 (Object)
      • 함수(Function)
      • 배열(Array)
      • 날짜(Date)
      • 정규식(RegExp)
    • 자바스크립트에는 사용자 정의 객체, 내장 객체, 브라우저 객체가 존재한다.
    • 모든 객체는 프로토타입 객체를 가르키는 프로퍼티가 있다.
    • 내장 객체에는 배열이 있다. ECMAScript 표준으로 제공되는 메서드들이 존재한다.
    • 일급객체
      • 리터럴에 의해 생성
      • 변수나 배열의 요소, 객체의 프로퍼티 등에 할당 가능
      • 함수의 인자로 전달 가능
      • 함수의 리턴값으로 리턴 가능
      • 동적으로 프로퍼티를 생성 및 할당 가능
    • 프로토타입을 통한 객체 생성
    • function Person(name, addr) { this.name = name; // this 는 함수에서 호출하면 전역 바인딩, 객체에서 호출하면 객체 바인딩. this.addr = addr; } Person.prototype.getName = function() { return this.name; // 객체의 이름 반환 }; Person.prototype.getAddr = function() { return this.addr; // 객체의 주소 반환 }; var p = new Person(); // 빈객체 -> 프로토타입-> 생성자호출 -> 동적 프로퍼티 생성 Person.prototype.name = 'person'; console.log(Person.prototype.getName()); // person
    • 스태틱 프로퍼티, 메소드
      • 자바스크립트는 스태틱 변수 메소드가 존재하지 않는다. 이를 구현하기 위해서 대문자로 시작되는 객체를 만들어 사용한다.
      • Math.E Math.NL2 Math.abs(x);

    배열과 객체의 차이

    • 객체는 배열이 가지고 있는 표준 메서드들을 사용할 수 없다.
    • 배열과 객체의 프로토타입이 서로 다르기 때문이다.
    • 객체의 경우 Object.prototype이 프로토타입이다.
    • 배열의 경우 Array.prototype이 프로토타입이다.

    체이닝

    • 상속은 _proto 체이닝
    • 클로저는 scopes 체이닝

    프로토타입

    new 키워드

    • 빈객체에 함수에 프로토타입 연결해주고 생성자 호출 끝

    • 함수가 생성되면 해당 함수에 대한 프로토타입이 만들어짐. → 빈 객체 생성 → 빈 객체에 함수의 프로토타입 객체를 프로토타입으로 설정 → 생성자 함수 호출 this 바인딩을 통한 동적 프로퍼티 할당 → 생성된 객체 this 리턴 (암묵) → 해당 객체에 변수가 없을 경우 프로토타입 탐색을 진행 (프로토타입 체이닝, 상속기능 구현)

    • 함수의 프로토타입을 바꾸면 상속 기능을 구현할 수 있다.
    • function Person() { this.name = "전승규"; this.address = "ssyauu580@gmail.com"; this.test = function() {}; // 프로토타입의 함수 정보를 덮어씀 } Person.prototype.test = function() {}; function Student() { this.school = "파주중"; } Student.prototype = Person.prototype ;// Person (체이닝을 통한 상속) Student.prototype.constructor = Student; // 생성자는 그대로
    1. 객체 리터럴 방식과 생성자 함수를 통한 객체 생성 방식의 차이
      • 객체 리터럴 방식의 경우는 자신의 프로토타입 객체가 Object이고, 생성자 함수 방식의 경우 Person이 프로토타입이다.

    실행 컨텍스트(함수 객체)

    • 컨텍스트에 활성객체에는 arguments, 스코프 체인(현재 컨텍스트의 유효범위를 나타내는 스코프 정보 생성), 지역 변수 생성, this 바인딩 정보를 가지고 있다.
    • 활성객체에 지역변수가 한번에 할당된다. 초기화는 소스코드가 실행될 때 진행된다.

    1. 스코프 체인

    유효 범위를 나타내는 스코프가 프로퍼티로 각 함수 객체 내에서 연결리스트 형식으로 관리된다. 대응되는 이름의 프로퍼티를 찾을 때 까지 계속해서 다음 객체로 이동하며 찾는다.

    • 함수 객체(Function) 생성 시 스코프 프로퍼티로 현재 컨텍스트의 스코프를 참조한다. 현재 실행되는 함수 객체의 스코프를 복사하고, 새롭게 생성된 변수 객체를 해당 체인의 제일 앞에 추가한다. ( 스코프 체인 = 현재 실행 컨텍스트의 변수 객체 + 상위 컨텍스트의 스코프 체인)
    • 스코프체인은 실행컨텍스트 기준으로 for, if와 같은 구문은 유효 범위가 없다. 함수만이 유효 범위의 한 단위가 된다.

    2. 클로저

    이미 생명주기가 끝난 외부 함수의 변수를 참조하는 함수를 클로저라고 한다.(생명주기가 끝나도 참조 되어 있으므로 가비지 콜렉터 대상이 아님.)

    • 체이닝을 통한 클로저
    • 클로저로 사용되는 변수는 주로 스코프에 첫번째 객체가 아닌 경우가 많다. 그러므로 너무 많은 변수를 탐색하여 성능저하를 일으키지 않도록 개발해야 한다.

        // 클로저 개념
        function scope() {
    
            var x = 20;
    
            return function () {
                return x;
            }
        }
    
        var inner = scope();
    
        console.log(inner());
    1. 클로저의 활용
      1. 특정 함수에 사용자가 정의한 객체의 메서드 연결하기
      2. function Caller(event) { this.func = Caller.prototype[event]; // Caller.prototype.event; } Caller.prototype.who = function () { console.log("Who are you?"); } Caller.prototype.call = function () { this.func(); } var caller = new Caller("who"); caller.call();
      3. 함수의 캡슐화
      4. var getName = (function () { var name = "ssyauu580"; return function () { return name; } })(); // 클로저 함수 반환 console.log(getName()); // ssyauu580
      5. setTimeout()에 지정되는 함수의 사용자 정의

    DOM(Document Object Model)

    HTML을 기반으로 생성한 문서 객체, DOM의 목적은 자바스크립트를 통해 이 문서의 프로그래밍 인터페이스 제공

    DOM 트리는 노드로 구성됨

    • 노드
      • 요소 노드
      • 텍스트 노드

    1. 노드

    DOM의 모든 노드는 Node를 상속하고 있다.

    Object < Node < Document < HTMLDocument
    Object < Node < Element < HTMLElement
    Object < Node < Attr (속성도 노드)
    Object < Node < CharacterData < Text
    Object < Node < DocumentFragment

    2. 이벤트핸들러 4가지

        //4가지
        // 하나의 이벤트 핸들러만 등록 가능
        // 고전 이벤트
        window.onload = function() {
        };
    
        // 인라인 이벤트
        <p onclick="alert('hi');"></p>
    
    
        //복수의 이벤트 핸들러 등록 가능
        // IE이벤트
        element.attachEvent("onclick", function() {});
    
        // 표준 이벤트 (표준), 제일 바람직한 코드 
        // Javascript와 HTML을 분리하는 것은 중요하다.
        header.addEventListener("click", function() {});

    3. 이벤트

    • 이벤트는 기본적으로 버블링으로 진행된다. 아래에서 위로 이벤트 핸들러 실행. document까지 올라감.
    • 사용자 정의 이벤트 생성 및 발생 시킬 수 있다.
    • 이벤트 로직과 어플리케이션 로직을 분리하여 사용한다. (유지보수 용이)

    4. 그외

    • InnerHTML은 HTML파서를 호출하므로 부하가 있음. 사용 지양
    • DocumentFragment노드를 통해서 라이브 DOM 트리 외부에 경량화된 문서 DOM을 만들 수 있다. 한번에 바꿔치기 가능.
    • 스크립트 Element를 만나면 모든 작업을 블록킹 후 스크립트 해석을 진행하는데 <script defer> 속성을 사용하면 블록킹을 하지 않고 스크립트 실행 지연.
    • 스크립트 async 는 블록킹하지 않고 다운로드 완료되면 파일 해석

    에러처리

    function MyError(message) {
         this.message = message;
     }
    
    MyError.prototype = new Error(); // Error 상속. Error은 자바스크립트 예외 기본 타입
    try {
        throw new MyError("addClass() : First argument must be a DOM element.");
    } catch (ex ) {
        if( ex instanceof TypeError) {
    
        } else if( ex instanceof ReferenceError) {
    
        } else if (ex instanceof MyError) {
    
        } else {
    
        }
    } finally {
    
    }

    모듈화(ES6)

    자바스크립트는 변수의 유효 범위가 파일 단위로 구분되지 않는다. 그래서 변수의 충돌이 발생한다. 이런 문제를 해결하기 위해서 모듈화가 필요하다.

    • export는 한 파일의 특정기능을 다른 파일에서 사용하게 할 때 사용한다.
    • {}는 이름이 있는 기능을 불러올 때 사용한다.
    • export default의 경우 명명해줘야 사용가능하다.
    // lib/math.js
    export function sum(x, y) {
        return x + y;
    }
    export var pi = 3.141593;
    // app.js
    import * as math from "lib/math";
    console.log("2π = " + math.sum(math.pi, math.pi)); // 2π = 6.283186
    // otherApp.js
    import {sum, pi} from "lib/math";
    console.log("2π = " + sum(pi, pi)); // 2π = 6.283186
    export default와 export * 문법도 제공합니다.
    // lib/mathplusplus.js
    export * from "lib/math";
    export var e = 2.71828182846;
    export default function(x) {
        return Math.log(x);
    }
    // app.js
    import ln, {pi, e} from "lib/mathplusplus";
    console.log("2π = " + ln(e)*pi*2);

    Named Exports

    export 키워드를 사용하며, import시 변수명을 적시해야함.

    Default Export

    export default를 사용하며, import시 변수명을 정의 해줘야함.

    자바스크립트 개발 시 중요한 것들

    1. 표준 여부 및 기술 지원 여부 확인

    • 자바스크립트는 브라우저마다 지원하는 프로퍼티 및 메소드가 다르므로 사용하는 표준 기술이 아닌 경우 브라우저별로 처리해야줘야 한다.

    2. UI 레이어를 느슨하게 연결하기

    1. 자바스크립트에서 CSS 분리하기
    • style일의 모든 정보가 css에 있어야 한다.
    • 요소 스타일 변경 시 클래스 변경을 통해서 해야 하다.
    • 자바스크립트와 CSS를 분리함으로써 유지보수를 용이하게 한다. 각자 용도에 충실
    1. HTML에서 자바스크립트 분리하기
    • html 태그에 이벤트 연결 분리한다. 함수 수정시 HTML 수정 자바스크립트 수정이 발생
    • html내에 스크립트 태그 사용하지말고 자바스크립트 파일로 분리
    • 자바스크립트 수정 시 자바스크립트 파일만 수정할 수 있게 된다.
    1. 자바스크립트에서 HTML 분리하기
    • 유지보수 관련 문제
    • HTML 구조파악이 힘듬
    • HTML에 템플릿 생성 후 자바스크립트로 가져와서 사용

    3. 전역문제 해결하기

    1. 전역문제
      1. 암묵적 결합. 전역변수 스코프는 전체. 그 변수를 참조하는 함수들.. 강한 결합
      2. 긴 생명 주기
      3. 스코프 체인상에 종점에 위치. 성능저하 발생
      4. 네임스페이스 오염
    2. 해결방안
      1. 즉시실행함수
      2. (function () { var beer = 'kirin'; // 즉시 실행 함수의 지역 변수 true// ... }()); console.log(beer); // ReferenceError: beer is not defined
      3. 네임스페이스 객체( 하나의 객체에 몰빵)
      4. var BEER = {}; // 전역 네임 스페이스 객체 생성 BEER.species = { name: 'stella', from: 'Belgium' }; console.log(BEER.species.from); // Belgium
      5. 모듈 패턴
      6. const Counter = (function () { // private 변수 let num = 0; // 외부로 공개할 데이터나 메소드를 프로퍼티로 추가한 객체를 반환. return { increase() { return ++num; }, decrease() { return --num; } }; }()); // private 변수는 외부에서 참조할 수 없음. console.log(Counter.num); // undefined console.log(Counter.increase()); // 1 console.log(Counter.increase()); // 2 console.log(Counter.increase()); // 3 console.log(Counter.decrease()); // 2 console.log(Counter.decrease()); // 1
    3. 사용을 지양하는 것은 맞지만 아직까지는 전역변수를 쓰고 있고, 만약 쓰게된다면 하나의 객체에 몰빵하는 것도 좋은 방법

    4. 구성데이터 분리

        // 구성 데이터 분리 별도에 파일에 관리하는 것이 데이터 관리에 효율적이다.
        var config = {
            MSG_INVALID_VALUE : "invailid value",
            URL_INVALID : "/errors/invaid.php",
        };
    
        function validate(value) {
            if(!value) {
                alert(config.MSG_INVALID_VALUE);
                location.href = config.URL_INVALID;
            }
        }

    5. 객체변경

    자바스크립트는 객체 수정이 자유롭기 때문에 무분별한 객체수정을 지양하도록 한다.

    1. 객체 변경 금지 규칙
      1. 메서드 오버라이드를 하지 않는다.(잘못된 동작 유발)
      2. 새로운 메소드 추가 금지 (이름 충돌문제)
      3. 메서드 삭제 금지 (오류발생)
    2. 방안
      1. 객체 기반 상속
      2. 타입 기반 상속
      3. 패서드 패턴(Wrapper)
      4. ES5 객체 변경 방지 사용

    기타

    주석

    웹 개발 시 자바스크립트 주석은( //, /* * /) 클라이언트에게 전송되므로 jsp 사용할 경우 jsp 주석을 사용하도록 한다.(<%-- --%>) HTML 주석 () 또한 클라이언트에게 전달되므로 사용을 지양한다.

    undefined 는 false 처리

    • 자바스크립트 자료형에서 false로 처리되는 값은 "", null, undefined, 0, NaN 이 있고 나머지는 모두 true
     var value2 = "" 
     if( !value2 )
     { console.log("비어 있음"); }
     else
     { console.log("값이 있음"); }
     //기능 탐지
     if(document.getElementById)
        return document.getElementById();

    typeof, instacneof 키워드

        var awardCategoryList = typeof opener.requestForm.awardcategoryList == "undefined" ? "" : opener.requestForm.awardcategoryList.value
    
        //
        if(obj instanceof Date) {
    
        }

    셀렉트박스 Code, Value 가져오기

        this.options[this.selectedIndex].innerHTML

    파라미터 가져오기

        function test() {
    
            if(arguments.length >1 )
                alert('hi');
        }
    
        test('안녕'); // hi alert 호출
        test(); // hi alert 비호출
    
    toLocalString()

    숫자를 돈의 형태로 반환

        var num = 1000;
        console.log(num.toLocaleString());
    
    document.querySelector
    
        document.querySelector("#header"); // 하나 반환
        document.querySelectorAll(""); // 배열반환 

    in 키워드

        //해당 객체의 함수인지 확인
        if("querySelectorAll" in document) {
            //실행
        }
    
        //프로퍼티 존재 여부
        if("name" in employee) {
            //실행
        }
    반응형