//변수 및 함수이름: camelcase(첫글자 소문자, 단위로 첫글자 대문자, _사용 금지)
  //숫자, 문자, boolean
  let helloThere = 3;
  const heyYeji = 5;

  //배열: 배열은 복수형이름
  const dogs = [];

  //정규표현식-정규표현식은 'r'로 시작 
  const rDesc = /.*/;

  //함수
  function getPropertyName() {
    //some code...
  }

  //이벤트 핸들러-'on'으로 시작 
  const onClick = () => {};
  const onKeyDown = () => {};

  //불린 반환 함수 - 반환 값이 불린이면 'is'로 시작 
  let isAvailabale = false;

  //지역변수 or private 변수명은 '_'로 시작한다 
  let _privateVariableName;

  //URL, HTML과 같은 범용적인 대문자 약어는 대문자 그대로 사용
  parseHTML
  parseXML

  // 전역 변수를 사용하지 않는다: 전역변수는 window에 로딩되어서, 모든 부분에서 접근할 수 있기 때문에 위험
  // Bad
  function sum(x, y) {
    result = x + y;
    return result;
  }

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

  // Good
  function foo() {
    let a, b;
    a = b = 0;
  }

//상수는 영어 대문자 스네이크 표기법(_사용) 사용 
SYMBOLIC_CONSTANTS;

//생성자는 대문자 카멜 케이스 
class ConstructorName {

}

// 선언과 할당 
  //var 절대 사용하지 말 것 
  //값이 변하지 않는 변수는 const(가장 권장), 값이 변하는 변수는 let을 사용하여 선언 
  //const를 let보다 위에 선언한다. (그룹핑하여 가독성)
  //const, let은 블록 스코프이므로 호이스팅 되지 않는다. 
  //const와 let은 사용시점에서 선언 및 할당한다. 
  // Bad - 블록 스코프 밖에서 변수 선언
  function foo() {
    const len = this._array.length;
    let i = 0;
    let j = 0;
    let len2, item;

    for (; i < len; i += 1) {
        //...
    }
    
    len2 = this._array2.length;
    for (j = 0, len2 = this._array2.length; j < len2; j += 1) {
        item = this._array2[j];
        //...
    }
  }

  // Good 
  function foo() {
    const len = this._array.length;
    for (let i = 0; i < len; i += 1) {
        //...
    }

    // 사용 시점에 선언 및 할당
    const len2 = this._array2.length;
    for (let j = 0; j < len2; j += 1) {
        const item = this._array2[j];
        //...
    }
  }
  
//배열과 객체
  //배열과 객체는 리터럴로 선언(생성자보다 짧고 명확하여 실수를 줄일 수 있음)
    // Bad-배열 생성자 사용 
    const emptyArr = new Array();
    const arr = new Array(1, 2, 3, 4, 5);

    // Bad - 객체 생성자 사용
    const emptyObj = new Object();
    const obj = new Object();

    // Good
    const emptyArr = [];
    const arr = [1, 2, 3, 4, 5];

    // Good
    const emptyObj = {};
    const obj = {
      pro1: 'val1', 
      pro2: 'val2'
    };

  //배열 및 객체 복사시 순환문을 사용하지 않고, 전개 연산자를 사용하면 좀 더 명확하게 정의할 수 있다. (es5에서는 slice()사용)
    //good
    const items = [1, 2, 3];
    const copyItems = [...items];
    console.log(copyItems); //[1, 2, 3]

    const objItem = {
      one: 1,
      two: 2,
      three: 3
    }

    const copyObj = {
      ...objItem,
      four: 4
    }

    console.log(copyObj); //one, two, three, four 모두가 들어옴 

    // Bad
    for (i = 0; i < len; i++) {
      itemsCopy[i] = items[i];
    }

  // 배열 요소 중 하나라도 줄바꿈이 있다면, 모든 요소는 일관되게 줄바꿈 해야한다. 
    const a = [1
    ]; //bad
    const b = [
      1
    ]; //good

    const c = [1,
    2, 3]; //bad
    const d = [
      1, 
      2, 
      3
    ]; //good 

  // 객체 프로퍼티가 한개인 경우에만 한줄 정의 허용하며, 2개 이상일때는 개행을 강제한다. 
    const obj = {foo: 'a', bar: 'b'}; //bad 
    //good 
    const obj = {
      foo: 'a', 
      bar: 'b'
    }; 
    const obj = {foo: 'a'}; //good 
    const obj = {
      foo: 'a', //good 
    }
  
  // 객체 리터럴 정의 시 콜론 앞은 공백 허용x, 콜론 뒤는 항상 공백 강제 
    //bad 
    const obj = {
      foo : 'a'
    }
    //good
    const obj = {
      foo: 'a'
    }
  
  //객체 내의 메소드 표현시, 축약 메소드 표기를 사용한다. 
    //bad
    const atom = {
      addValue: function(value) {
        return 1;
      }
    }
    //good
    const atom = {
      addValue(value) {
        return 1;
      }
    }

//메소드 문법 사용시, 매소드 사이에 개행을 추가한다. 
  // Bad
  class MyClass {
    foo() {
      //...
    }
    bar() {
      //...
    }
  }

  // Good
  class MyClass {
    foo() {
      //...
    }

    bar() {
      //...
    }
  }
  
//함수
  //함수 생성자를 사용하여 선언하지 않는다(생성자 함수 쓰지 말라는 말 아님)
    //bad
    const doSomething = new Function('param1', 'param2', 'return param1 + param2;'); 
    console.log(doSomething(1, 2)); //3

    //good: 함수 선언식
    function doSomething(parm1, parm2) {
      return parm1 + parm2;
    }

    //good: 함수 표현식 
    const doSomething = function(parm1, parm2) {
      return parm1 + parm2;
    }
    doSomething(1, 2); //3

  //함수표현식을 사용한다면, 함수는 사용하기 전에 선언해야한다. 
  const sum = function(parm1, parm2) {
    return parm1 + parm2;
  }
  const sumValue = sum(1, 2); 
  sumValue; //3

// 화살표 함수 
  //함수 표현식 대신, 화살표 함수를 사용한다. 
    // Bad
    [1, 2, 3].map(function (x) {
      const y = x + 1;
      return x * y;
    });

    // Good
    [1, 2, 3].map(x => {
      const y = x + 1;
      return x * y;
    });

  //화살표 함수의 파라미터 하나이면, 괄호 생략 
    // Good
    [1, 2, 3].map(x => x * x);

    // Good
    [1, 2, 3].reduce((y, x) => x + y);
  
  // 함수의 본체가 하나의 표현식이라면 중괄호를 생략하고, 암시적 반환을 사용할 수있다. 그외에는 return 명시
    //bad
    [1, 2, 3].map(num =>  {
      const nextNum = num + 1;
      `A string containt the ${nextNum}.`; //여기 return 해줘야함 
    })

    //good
    [1, 2, 3].map(number => `A string containing the ${number + 1}.`);

  //암시적 반환을 사용할 경우, 함수 본문 전에 개행해지 않는다. 
    //bad
    (foo) => 
      bar;
    //good
    (foo) => bar

//Promise Executor 함수 

//Destructuring (구조분해할당)
    //오브젝트의 프로퍼티에 접근할 때는 destructuring을 이용한다 (✨객체의 경우, 반드시 key값과 같아야함)
      const yeji = {
        firstName: 'kim',
        lastName: 'yeji'
      }

      //bad
      function getFullName(user) {
        const firstName = user.firstName;
        const lastName = user.lastName;

        return `${firstName} ${lastName}`; 
      }
      //Good 
      function getFullName(obj) {
        const {firstName, lastName} = obj; //obj에서 {firstName, lastName} key를 가져온다

        return `${firstName} ${lastName}`;
      }
      //Good -> getFullName(yeji)로 하면, obj가 firstName, lastName으로 나뉘어짐
      function getFullName({firstName, lastName}) {
        return `${firstName} ${lastName}`;
      }

      //bad 
      const first = arr[0];
      const second = arr[1];
      //Good
      const [first, second] = arr;

    //새로운 이름으로 변수에 할당할때는 Destructuring을 사용하지 않아도 된다. 
    const changeFirstName = user.firstName;
    const {firstName: changeFirstName} = user; //changeFirstName: firstName키값이 들어옴 

// 템플릿 문자열: 변수 등을 조합해서 문자열을 생성하는 경우, 템플릿 문자열을 이용한다 (코드복잡도 낮아짐)
  function sayHi(name) {
    return `How are you, ${name}?`;
  }

// 클래스와 생성자 
  // class, extends를 이용해서 객체 생성 및 상속 구현 

// 모듈 
  // 항상 import, export를 이용해서 모듈을 로드한다. 
  import {es6} from './AirbnbStyleGuide';
  export default es6; 

  //wildcard import는 사용하지 않는다 
   //import * from './text'; //bad
  import * as AirbnbStyleGuide from './text';

  //import문으로 직접 export하지 않는다 (간결하긴 하지만, import와 export 구분하는 것이 좋다)
  export {es6 as default} from './airbnbStyleGuide';  //bad

// 블록 구문 
  // 한줄짜리 블록이라도 {}를 생략하지 않고, 명확히 줄바꿈 한다. (당장은 두줄 줄일수있지만, 생략하면 코드 구조를 애매하게 만들고, 잠재 위험요소)
    // Bad
    if(condition) doSomething();

    // Bad
    if (condition) doSomething();
    else doAnything();

    // Bad
    for(let prop in object) someIterativeFn();

    // Bad
    while(condition) iterating += 1;

    // Good
    if (condition) {
      //...
    }

    // Good
    if (condition) {
      //...
    } else {
      //...
    }
  
  // 키워드와 조건문 사이에 빈칸을 사용한다. 키워드와 조건문 사이가 빼곡하면 코드를 읽기 어렵다 
    // Bad
    for(let i=0; i<100; i+=1) {
      someIterativeFn();
    } 

    // Good (가능하면 for of, for in)
    for(let i = 0; i < 100; i += 1) {
      someIterativeFn();
    } 
  
  // do-while문 사용시, while문 끝에 세미콜론을 쓴다. 
    do {
      //...
    } while (condition);

  // switch-case 사용시 첫번째 case문을 제외하고 case문 사용 이전에 개행한다. 
    // Good
    switch (value) {
      case 1:
        doSomething1();
        break;

      case 2:
        doSomething2();
        break;

      case 3:
        return true;

      default:
        throw new Error('This shouldn\\'t happen.');
    }

  // switch-case 사용시 각 구문은 break, return, throw 중 한개로 끝나야 하며, default문이 없으면 '// no default' 표시 해주기
  // 여러 케이스가 하나의 기능을 한다면 break 생략해도 좋지만, 조금이라도 다른 기능을 포함한다면 break를 생략하지 않고 다른 방식으로 수정 
    // Bad - 케이스 1 과 2 가 서로 다른 처리를 하지만 break가 생략됨
    switch (value) {
      case 1:
        doSomething1();

      case 2:
        doSomething2();
        break;

      case 3:
        return true;

      // no default
    }

    // Bad - default문이 없지만 아무런 표기가 없음
    switch (value) {
      case 1:
        doSomething1();
        break;

      case 2:
        doSomething2();
        break;

      case 3:
        return true;
    }

    // Good - 여러 케이스가 하나의 처리를 할 때는 break생략 허용
    switch (value) {
      case 1:
      case 2:
        doSomething();
        break;

      case 3:
        return true;

      // no default
    }

// 조건 확인하기 
  // 함중 등호 연산자인 ===, !==만 사용한다. ==, !=는 암묵적 캐스팅으로인한 버그로 이어진다. 

// 반환 하기 
  // 함수 내에서 반환은 한번만 한다. (예측 가능, 간결한 함수 작성)
  // 특정 값을 반환해야하는경우 함수 맨 마지막에서 한번만 반환하며, 만약 예외로 빠져나가는 경우는 제외한다. 
  // return문 바로 위는 한칸 비워놓는다. (다른 명령과 return 붙어있으면 가독성 좋지 않음) 
    // Bad
    function getResult() {
      if (condition) {
        return someDataInTrue;
      }
      
      return someDataInFalse;
    }

    // Allow
    function foo(isValid) {
      // 예외처리로 바로 빠져나감
      if (!isValid) {
        return;
      }
      //...
      
      return someDataInTrue;
    }

    // Good
    function getResult() {
      let resultData;
      //...

      if (condition) {
        //...
        resultData = someDataInTrue;
      } else {
        //...
        resultData = someDataInFalse;
      }

      return resultData;
    }

// 순회 하기 
  // 반복문 사용은 일반화된 순회 메소드(map, forEach...) 사용을 권장한다. (실수 가능성이 적다)

// 주석 
  // 설명하려는 구문에 맞춰 들여쓰기 
  // 문장 끝에 주석 작성할 경우, 한 줄 주석을 사용하며 공백을 추가한다.  
    // Bad
    var someValue = data1;//주석 표시 전후 공백

    // Bad
    var someValue = data1; /* 여러 줄 주석 */

    // Good
    var someValue = data1; // 주석 표시 전후 공백
  
  // 여러줄 주석을 할때는 *의 들여쓰기 맞춘다. 첫줄 및 마지막 줄을 비운다. 
    /*
    * 주석 내용  
    */
  
  // 코드 블럭 주석 처리를 위해서는 한줄 주석 사용하기 (* 주석 bad)
    // const tmp = 3; 

// 공백 
  // 키워드, 연산자와 다른 코드 사이에 공백이 있어야 한다. 
    // Bad
    var value;
    if(typeof str==='string') {
      value=(a+b);
    }

    // Good
    var value;
    if (typeof str === 'string') {
      value = (a + b);
    }

  // 시작 괄호 바로 다음, 끝 괄호 바로 이전에 공백이 있으면 안된다
    // Bad - 괄호 안에 공백
    if ( typeof str === 'string' )

    // Bad - 괄호 안 공백
    var arr = [ 1, 2, 3, 4 ];

    // Good
    if (typeof str === 'string') {
      //...
    }

    // Good
    var arr = [1, 2, 3, 4];

  // 콤마 다음에 값이 오면 공백이 있어야한다. (콤마로 구분된 아이템간의 간격)
    let arr = [1,2,3,4]; //bad
    let arr = [1, 2, 3, 4]; //good