User Tools

Site Tools


gmdm_js_convention

gMDM UI 자바스크립트 코딩 규칙

  • 규칙의 일부는 jslint 의 규칙을 참조 하여 정한다.

기본 설정

탭 설정

  • 2 스페이스로 설정한다.

strict mode

  • 'use strict' 를 전역으로 사용되지 않게(서드파티에서 지원하지 않는 경우에 문제), 각 정의하는 모듈의 첫번째 라인에 넣는다.
    app.test = (function () {
      'use strict';
    } ());

webix ui

  • webix ui 라이브러리를 이용하여 뷰를 생성할때 모든 컴포넌트에는 css property 를 반드시 붙여준다.
  • id 는 필요시에만 적용한다.
  • 예제
      (sample은 아래 명명규칙의 webix.ui 부분 참조)

사용되지 않는 파라메터

  • jslint 오류중 사용되지 않는 파라메터 에러가 있는데 이때는 삭제하거나 주석처리를 하거나 /*unused_parameter*/로 처리한다.
    // 꼭 남아 있어야 하는 파라메터라면 아래처럼 처리해 놓는다.
    var fun1 = function(/*unused_parameter*/ _n_parameter) {
      ....
    };
  • 파라메터가 하나 이상일 경우,
  • 첫번째 파라메터를 주석이나 /*unused_parameter*/로 처리하면 오류가 발생할 수 있으므로,
  • 파라메터를 다시 정의 하거나 반드시 사용하도록 해야 한다.
    // 첫번째 파라메터를 주석이나 /*unused_parameter*/로 처리하면 두번째 파라메터가 첫번째 파라메터로 인식되어,
    // 오류가 발생 할 수 있다.
    var fun1 = function (/*unused_parameter*/ _s_first_name, _s_last_name) {
      ....
    };

문자열 생성 규칙

홑따옴표

  • 모든 문자열은 홑따옴표(싱글 쿼테이션)를 사용한다.
    var str1 = 'abcde';
    var htmlStr = '<div class="style-class">text</div>';

new String()

  • new String() 은 사용하지 않는다.
    var str1 = new String(); // 사용자제
    var str2 = '';

줄바꿈

  • 줄바꿈이 필요한 경우 문자열이 계속 된다는 의미를 알기 쉽게 + 기호를 앞에 붙여 준다,
    var str1 = 'abcdefghijklmn'
      + 'opqrstuvwxyz';

띄어쓰기(공백) 규칙

  • 모든 구분자 이후에는 한칸의 공백을 준다.

배열

// 쉼표(,) 이후 공백을 준다.
var arrayList = [1, 2, 3, 4];
var first_name, last_name, address;

변수 값 할당

// = 의 앞뒤로 공백을 준다.
var str1 = 'str';

오브젝트

// : 앞뒤로 공백을 준다.
var obj = {
  first_name : 'abc',
  last_name : 'def'
};

명명 규칙 (미정, 검토중)

공통

  • 모든 함수는 private 일경우 _(언더바) 를 붙여 준다.
    app.mDefModel = (function () {
      'use strict';
      var publicFunction, // public 함수는 _ 를 붙이지 않는다.
        _privateFunction; // private 함수는 _ 를 붙여준다.
     
      publicFunction : function () {
        var _f_local_private, f_public;
        _f_local_private = function () {
          ....
        };
     
        f_public = function () {
          ....
        };
     
        return f_public;
      };
      return {
        publicFunction : publicFunction
      };
    }());
  • 함수의 아규먼트는 private 이므로 _(언더바)를 붙이고 타입 프리픽스를 붙이며 단어와 단어 사이에 _(언더바) 를 붙여 소문자로만 작성한다.
    app.mDefModel = (function () {
      'use strict';
      var funcion1, function2;
      function1 = function (_s_first_name, _s_last_name) {
        ....
      };
      function2 = function (_m_elem, _a_three_name_parameter) {
        ...
      }
    }());
  • Map 타입의 Object 를 정의 할때 Key 는 단어와 단어 사이 _(언더바) 및 소문자로 작성한다.
    var configMap = {
      height: 100,
      width: 200,
      max_height: 500,
      min_height: 50
    };
  • 타입을 알수 있도록 타입 프리픽스는 아래와 같이 붙여 준다.
    var s_variable, // String 타입
      n_variable,   // Number 타입
      b_variable,   // Boolean 타입
      a_variable,   // Array 타입
      m_variable,   // Map 타입
      f_variable,   // Function 타입
      d_variable;   // Dynamic(동적) 타입
      ui_variable;  // webix ui 정의 타입
     
      objName_variable; // Object 타입
      _objName_variable; // private 또는 argument 로 사용
     
      // 모듈내 타입 명시 방법
      configMap = {},
      domainList = [],
      initModule,   // function 타입 - 모듈 초기화
      configModule, // function 타입 - 모듈 설정
     
      // 이벤트 핸들러  on + event type (+ 옵션 : event target) 
      onSelectGridItem,    // 모듈 : on + event type + event target
      _on_select_grid_item, // 로컬 : private _on + event type + event target
     
      onSaveDone,          // 모듈 : on + event type
      _on_save_done        // 로컬 : private _on + event type
     
      // loop에 사용되는 i, j, k 등은 타입 프리픽스 없이 그대로 사용한다

상수

  • 상수는 단어와 단어사이 _(언더바)를 붙이며 대문자로만 작성한다.
    var PI = 3.14, DO_NOT_EDIT_THIS_NAME = 'gmdm';

모듈

  • 모듈 스코프의 변수명은 타입 프리픽스를 지정하지 않는다. 대신 property의 경우 의미상 type을 알 수 있도록
  • configMap 처럼 명사(이 경우는 약어를 사용하였음) 뒤에 의미있는 type명을 지정하고,
  • function의 경우 동사로 시작하는 두 단어 이상으로 정의함.
  • 모듈 스코프의 변수명은 camelCase 로 작성한다.
    app.mDefModel = (function () {
      'use strict';
      // 모듈 스코프 변수
      var stateMap = {}, configMap = {}, initModule, configModule
        _privateFunction;
      ....
    }());

모듈 내 로컬 함수의 변수

  • 모듈 내 정의되는 로컬 함수의 내부 변수는 변수프리픽스를 붙이고 단어사이 _(언더바) 를 붙이며 소문자로 작성한다.
    app.mDefModel = (function () {
      'use strict';
      var _privateLocalFunction, publicFunction;
     
      _privateLocalFunction = function (_n_parameter) {
        var s_local_variable, _f_local_private, f_local_public;
        ....
     
        return f_local_public;
      };
     
      return {
        publicFunction : publicFunction
      };
    }());

webix ui

  • id, css
    // app.mDefModel.js 파일의 이름(네비게이터에서 뷰의 코드) 의 전체 이름으로 지정한다.
    // UI 의 계층 구조에 따라 - (마이너스) 로 구분한다.
    // workspace code + view code
    var _ui_scheme;
    _ui_scheme = {
      id : 'app-mDefModel',
      css : 'app-mDefModel',
      ....
    };
  • subview id, css
    // app.mDefModel.js 파일의 이름(네비게이터에서 뷰의 코드) 의 전체 이름으로 지정한다.
    // UI 의 계층 구조에 따라 -(마이너스) 로 구분한다.
    // workspace code + view code
    // 중간에 layout 을 삽입할 경우 layout에 css 나 id 가 없다면 'layout' 이라는 이름을 붙여 준다.
    var _ui_list_header, _ui_list, _ui_scheme;
    _ui_list_header = {
      id : 'app-mDefModel-list-header',
      css : 'app-mDefModel-list-header',
      ....
    };
    _ui_list = {
      id : 'app-mDefModel-list',
      css : 'app-mDefModel-list',
      rows : [
        ui_list_header
      ]
      ....
    };
    _ui_scheme = [{
      id : 'app-mDefModel',
      css : 'app-mDefModel',
      rows : [
        ui_list,
      ]
      ....
    }];
    webix.ui(_ui_scheme, stateMap.container);

for, for-in 문 생성 규칙

일반적인 for 문

  • for 문을 이용할 때에는 아래의 규칙을 이용한다.
  • 배열이 작은 경우에는 상관없지만, document 의 elements 등 큰 배열을 다룰 때에는 성능에 영향을 미치게 된다.
  • 항상 아래와 같이 먼저 length를 변수에 받아서 사용하기로 함.
    var app = (function () {
      'use strict';
      var a_elems, n_elems_length, i, a_some_array, n_some_array_length;
      a_elems = document.getElementsByClassName('some-class');
      n_elems_length = a_elems.length; // length 를 미리 정의한다.
      for (i = 0; i < n_elems_length; i++) {
        a_elems[i];
      }
     
      a_some_array = [1, 2, 3, 4, 5];
      n_some_array_length = a_some_array.length; // length 를 미리 정의한다.
      for (i = 0; i < n_some_array_length; i++) {
        a_some_array[i];
      }
     
      // 아래의 방식은 사용하지 않는다.
      for (i = 0; i < a_elems.length; i++) { // length 를 매번 호출
        a_elems[i];
      }
     
      a_some_array = [1, 2, 3, 4, 5];
      for (i = 0; i < a_some_array.length; i++) { // length 를 매번 호출
        a_some_array[i];
      }
    }());

forEach 문

  • Array 를 다룰때 일반적인 for 문을 사용하는 경우도 있지만 경우에 따라선 Array.prototype.forEach 함수를 이용할 때가 있다.
  • forEach 를 사용할때 callback 함수 안에서 this 를 사용할때 아래의 예제와 같이 쓴다.
    var app.mDefModel = (function () {
      var selectedColor, fun1;
     
      fun1 = function () {
        var a_color_list = ['red', 'blue', 'white', 'green'], s_selected_color;
     
        // callback 함수내의 this 잘못 사용하는 예 - 1
        a_color_list.forEach(function (s_color, n_index) {
          if (s_color === 'white') {
            // 아래 this 가 모듈(app.mDefModel) Object를 지칭하여, 그의 selectedColor 를 사용할 것으로 기대하지만,
            // 현재 function이 app.mDefModel의 function이 아니라, 거기에서 다시 호출한 function이므로,
            // this는 Object가 없어서 Window Object를 지칭하여서, 기대대로 되지 않음.
            this.selectedColor = s_color;
            s_selected_color = s_color;
          }
        });
     
        // callback 함수내의 this 잘못 사용하는 예 - 2
        var self = this; // 특별한 경우가 아니라면 this 를 self 나 that 같은 변수에 할당해서 쓰지 않는 것이 좋다.
        a_color_list.forEach(function (s_color, n_index) {
          if (s_color === 'white') {
            // this 대신 self 를 사용하였다. 이경우 정상 동작 하겠지만 call, apply 를 이용하는 경우 오류 발생 가능성이 있다.
            self.selectedColor = s_color;
            s_selected_color = s_color;
          }
        });  
     
        // forEach 함수만의 callback 함수내의 this 정상 사용예
        // 좀더 일반적인 내용은 아래의 문서를 참조 한다.
        a_color_list.forEach(function (s_color, n_index) {
          if (s_color === 'white') {
            // forEach 의 두번째 아규먼트에 this 를 넘겨 정상 동작하도록 만든 예제 이다.
            this.selectedColor = s_color;
            s_selected_color = s_color;
          }
        }, this); // callback 함수 내에서 사용할 this 를 위해 현재 context(app.mDefModel) 의 this 를 넘겨준다.
      };
    }());
  • NodeList, HTMLCollection 와 같이 일반적인 array 와 비슷하지만 array 의 모든 함수를 지원하지 않는 오브젝트들은
  • 아래와 같이 forEach 를 사용할 수 있다.
    var elements = document.getElementsByClassName('className');
    [].forEach.call(elements, function (elem, index) {
      console.log(index, elem);
    });
     
    // 또는
     
    [].forEach.apply(elements, [function (elem, index) {
      console.log(index, elem);
    }]);
  • 함수 내부에서 this 의 일반적인 사용방법
    // forEach 와는 다르게 일반적으로 함수에 this context 를 전달하는 방법은 아래와 같다.
    function () {
      console.log(this);  // this 는 bind 로 넘겨 받은 this context 가 된다.
    }.bind(this);
     
    // 또는 
     
    (function () {
      console.log(this); // this 는 bind 로 넘겨 받은 this context 가 된다.
    }).bind(this);

for in 문

  • for in 을 사용할 때, 자신만의 속성을 처리하려면 hasOwnProperty 를 사용하여 체크한다. 단, 예제처럼 Object literal로 직접 정의한 경우에는 (상속한 것이 없으므로) 이를 생략할 수 있다.
    var m_some_values = {
      key1 : 123,
      key2 : 456
    }, s_key, o_some_obj_extended;
     
    for (s_key in o_some_obj_extended) {
      if (o_some_obj_extended.hasOwnProperty(s_key) {
        o_some_extended[s_key];
        ....
      }
    }
     
    // 직접 생성하고 다른 object 를 상속하지 않은 object 인 경우는 가능.
    for (s_key in m_some_values) {
      m_some_values[s_key];
      ....
    }
  • for in 은 Object에 대해서 사용하며, Array에는 위의 for-loop(또는 forEach)를 사용한다.

세미콜론 규칙

  • 세미콜론은 생략하지 않고 모두 적용한다.
    // 가장 많이 빼먹는 세미콜론
    var funName = function () {
      ....
    }; // 잊어버리기 쉽다.
     
    var someObj = {
      ....
    }; // 잊어버리기 쉽다.

함수 생성 규칙

  • 함수는 먼저 함수명을 변수로 선언하고, 이후 함수 본문을 만든다.(호이스팅을 고려, 제일 위에 함수명을 변수로 선언)
    var funName;
    funName = function () {
      console.log('funtion');
    };
     
    // 아래와 같이 정의 하지 않는다.
    function funName() {
      console.log('function');
    }

이벤트 규칙

event

  • webix 에서 on 프로퍼티를 이용하여 이벤트를 등록하는 방법
    webix.ui({
      view: 'button',
      on: {
        onItemClick : function () {
          console.log('button clicked');
        }
        // 아래와 같이 홑따옴표로 감싸지 않는다.
        'onItemClick' : function () {
          console.log('button clicked');
        }
      }
    });
  • 이벤트 처리 함수 명은 on으로 시작하도록 한다. local 함수이면 _on으로 시작.
    app.mDefModel = (function () {
      var onSelectGridItem, localFun;
     
      localFun = function () {
        var _on_select_grid_item;
        _on_select_grid_item = function () {
          ...
        };
      };
      ....
    }());
  • 이벤트 이름 등록 방법(이벤트 이름이 중복되는 것을 방지)
    // on + 모듈 + 컴포넌트 + 이벤트 이름
    app.workViewBase = (function () {
      'use strict';
      var EVENT_SAVE_DONE = 'onComponentWorkViewBaseSaveDone';
      ....
     
      return {
        EVENT_SAVE_DONE : EVENT_SAVE_DONE
      };
    }());
     
    app.mDefModel = (function () {
      'use strict';
      var EVENT_UPDATE_VIEW = 'onMDefModelUpdateView';
     
      return {
        EVENT_UPDATE_VIEW : EVENT_UPDATE_VIEW
      };
    }());

주석 처리 규칙

  • 정식으로 주석을 작성 할 경우 아래의 규칙대로 작성한다.
  • 임시로 주석을 처리 할때에는 아래의 규칙을 꼭 사용할 필요는 없다.
  • 주석을 통해 정보 전달이 용이하도록 주석을 정의 하는 방법을 정리한다.
  • 참고 문서 jsDoc Reference

함수(메소드)

  • 함수 주석
    /**
    * 함수에 대한 설명을 기록합니다.
    * 여러줄로도 기록 할 수 있습니다.
    *
    * @method getName
    *
    * @param {String} first 인자값 설명
    * @param {Object} [second] 옵션 인자값 설명
    * @param {Number} third 인자값 설명
    * @param {Function} forth 인자값 설명
    * @param {Boolean} fifth 인자값 설명
    * @param {Number} sixth 인자값 설명
    *
    * @return {String} 이름을 반환합니다.
    */
    Person.prototype.getName = function (first, second, third, forth, fifth, sixth) {
      return this.first_name + this.last_name;
    };
     
    app.mDefModel = (function () {
      'use strict';
      var initModule, configModule;
     
      /**
      * 모듈의 환경설정을 위한 함수
      * 설정 가능한 항목은 아래와 같다.
      * - height, width
      * 
      * @example
      * app.mDefModel.configModule({
      *   height: 300,
      *   width: 450 
      * }, false)
      * 
      * 또는
      * 
      * var m_config_map = {
      *   height : 300,
      *   width: 450
      * }, flag = false;
      * app.mDefModel.configModule(m_configMap, flag)
      * 
      * @param {Object} m_config_map 환경설정 정보를 맵의 형식으로 가지고 있다.
      * @param {Boolean} [b_option] 옵션 flag 이다. // 변수명에 대괄호[] 를 감싸면 파라메터가 없을 수도 있다는 의미이다.
      * @return {Boolean} 환경설정이 정상처리 되면 true 를 반환하고 정상처리 되지 않으면 false 가 반환된다.
      */
      configModule = function (m_config_map, b_option) {
        ....
        return b_result;
      };
     
      /**
      * 모듈 초기화(생성자) 함수
      * 초기화 함수가 호출되면 초기화 함수 아규먼트로 받은 부모 컨테이너에 뷰를 생성하고 화면에 바로 표시가 된다.
      * 
      * @example
      * app.mDefModel.initModule(document.getElementById('app'));
      * 
      * @param {Object} container 모듈이 생성될 부모 컨테이너
      */
      initModule : function (o_container) {
        ....
      };
     
      return {
        initModule : initModule,
        configModule : configModule
      };
    }());

모듈

  • 모듈 주석
    /**
    * 모듈에 대한 설명을 기록합니다.
    * 
    * @module App
    */
    var App = {};

클래스

  • 클래스 주석
    /**
    * 클래스에 대한 설명을 기록합니다.
    *
    * @namespace App
    * @class Person
    * @constructor
    * @param {String} first_name 이름
    * @param {String} last_name 성
    * @param {Number} age 나이
    */
    App.Person = function (first_name, last_name, age) {
      ....
    }

Property

  • 프로퍼티 주석
    var Person = function (first_name, last_name) {
      /**
      * 프로퍼티에 대한 설명을 기록합니다.
      *
      * @property first_name
      * @type String
      */
      this.first_name = first_name;
      this.last_name = last_name;
    };

jslint 옵션

  • jslint 의 기본값을 사용하지 않고 아래의 옵션을 기본으로 사용한다.
/*jslint        
  browser  : true, // 브라우저의 메소드들을 지원 (location, document 등)
  continue : true, // for, while 문에서 continue 사용 지원
  devel    : true, // 개발을 위한 메소드들을 지원(console 과 같은 기능)
  indent   : 2,    // 들여쓰기
  maxerr   : 50,   // 최대 에러를 표시 할 갯수 (기본값은 무제한)
  nomen    : true, // 변수나 함수의 이름 앞에 언더바 허용
  plusplus : true, // 숫자 타입의 변수에 증감연산자 사용 허용
  regexp   : true, // 표현식 사용 허용
  vars     : false,// 여러줄의 var 사용 금지
  white    : true, // 공백 규칙 무시
  todo     : true  // TODO 사용 허용
*/
/*global webix, app, $$ */
gmdm_js_convention.txt · Last modified: 2016/03/09 11:03 by jeonjehun86