[리액트 프로그래밍 정석] React ES6 문법 액기스

02-1. 템플릿 문자열

  • 기존 자바스크립트에선 문자열과 문자열 또는 문자열과 변수를 연결하려면 병합연산자(+)를 사용했어야 했는데 ES6에선 템플릿 문자열을 도입하여 이를 대체했다.

    템플릿 문자열: 작은따옴표(‘’) 대신 백틱(`)으로 문자열을 표현한다. 템플릿 문자열에 특수 기호 $를 사용하여 변수 또는 식을 포함할수도 있다.

// ES5 문법
var string1 = '안녕하세요';
var string2 = '반갑습니다';
var greeting = string1 + ' ' + string2;
var product = { name: '도서', price: '4200원' };
var message = '제품' + product.name + '의 가격은' + product.price + '입니다';
var multiLine = '문자열1\n문자열2';
var value1 = 1;
var value2 = 2;
var boolValue = false;
var operator1 = '곱셈값은 ' + value1 * value2 + '입니다. ';
var operator2 = '불리언값은 ' + (boolValue ? '참' : '거짓') + '입니다. ';

//ES6 문법
var string1 = '안녕하세요';
var string2 = '반갑습니다';
var greeting = `${string1} ${string2}`;

var product = { name: '도서', price: '4200원' };
var message = `제품 ${product.name}의 가격은 ${product.price}입니다`;
var multiLine = `문자열1
문자열2`;
var value1 = 1;
var value2 = 2;
var boolValue = false;
var operator1 = `곱셈값은 ${value1 * value2}입니다.`;
var operator2 = `불리언값은 ${boolValue ? '참' : '거짓'}입니다.`;

02-2. 전개 연산자

  • ES6의 전개 연산자(spread operator)는 독특하면서도 매우 유용한 문법으로 나열형 자료를 추출하거나 연결할때 사용한다. 사용방법은 배열이나 객체, 변수명 앞에 마침표 세 개(…)를 입력한다. 다만, 배열,객체,함수 인자 표현식([],{},()) 안에서만 사용해야 한다.

    ES6의 배열 전개 연산자 사용 방법

// ES5 문법
var array1 = ['one', 'two'];
var array2 = ['three', 'four'];
var combined = [array1[0], array1[1], array2[0], array2[1]];
var combined = array1.concat(array2);
var combined = [].concat(array1, array2);
var first = array1[0];
var second = array1[1];
var three = array1[2] || 'empty';

function func() {
  var args = Array.prototype.slice.call(this, arguments);
  var first = args[0];
  var others = args.slice(1);
}

// ES6 문법
var array1 = ['one', 'two'];
var array2 = ['three', 'four'];
var combined = [...array1, ...array2];
// combined = ['one', 'two', 'three', 'four'];
var [first, second, three = 'empty', ...others] = array1;
// first = 'one', second = 'two', three = 'empty', others = []

function func(...args) {
  var [first, ...others] = args;
}

function func(first, ...others) {
  var firstInES6 = first;
  var othersInES6 = others;
}

// 올바르지 못한 예
// var wrongArr = ...array1;

ES6의 객체 전개 연산자 사용 방법

// ES5 예제
var objectOne = { one: 1, two: 2, other: 0 };
var objectTwo = { three: 3, four: 4, other: -1 };

var combined = {
  one: objectOne.one,
  two: objectOne.two,
  three: objectTwo.three,
  four: objectTwo.four,
};
var combined = Object.assign({}, objectOne, objectTwo);
// combined = { one: 1, two: 2, three: 3, four: 4, other: -1}
var combined = Object.assign({}, objectOne, objectTwo);
// combined = { one: 1, two: 2, three: 3, four: 4, other: 0}
var others = Object.assign({}, combined);
delete others.other;

// ES6 예제
var combined = {
  ...objectOne,
  ...objectTwo,
};
// combined = { one: 1, two: 2, three: 3, four: 4, other: -1} 
var combined = {
  ...objectTwo,
  ...objectOne,
};
// combined = { one: 1, two: 2, three: 3, four: 4, other: 0}
var { other, ...others } = combined;
// others = { one: 1, two: 2, three: 3, four: 4}

02-3. 가변 변수와 불변 변수

  • 기존 자바스크립트 문법은 변수 선언에 var 키워드를 사용했지만 ES6에서는 값을 수정할수 있는 가변 변수를 위한 let키워드와, 값을 수정할 수 없는 불변 변수를 위한 const 키워드를 사용한다.
const num = 1;
num = 3; // 타입 에러가 발생합니다

const str = '문자';
str = '새 문자'; // 타입 에러가 발생합니다

const arr = [];
arr = [1, 2, 3]; // 타입 에러가 발생합니다

const obj = {};
obj = { name: '내 이름' }; // 타입 에러가 발생합니다

const arr2 = [];
arr2.push(1); // arr2 = [1]
arr2.splice(0, 0, 0); // arr2 = [0,1]
arr2.pop(); // arr2 = [1]

const obj2 = {};
obj2['name'] = '내이름'; // obj2 = { name: '내이름' }
Object.assign(obj2, { name: '새이름' }); //obj2 = { name: '새이름' }
delete obj2.name; //obj2 = {}

const num1 = 1;
const num2 = num1 * 3; // num2 = 3

const str1 = '문자';
const str2 = str1 + '추가'; // str2 = '문자추가'

const arr3 = [];
const arr4 = arr3.concat(1); // arr4 = [1]
const arr5 = [...arr4, 2, 3]; // arr5 = [1, 2, 3]
const arr6 = arr5.slice(0, 1); // arr6 = [1], arr5 = [1, 2, 3]
const [first, ...arr7] = arr5; // arr7 = [2, 3], first = 1

const obj3 = { name: '내이름', age: 20 };
const obj4 = { ...obj3, name: '새이름' }; // obj4 = { name: '새이름', age: 20}
const { name, ...obj5 } = obj4; // obj5 = { age: 20 }

const arr = [1, 2, 3];
// 가변 변수를 사용한 예
for (let i = 0; i < arr.length; i++) {
  console.log(arr[i]);
}
// iterator 방식의 for-in 루프와 함께 불변 변수를 사용한 예
for (const item in arr) {
  console.log(item);
}

// forEach 함수를 활용한 예
arr.forEach((item, index) => {
  console.log(item);
  console.log(index);
});

02-4. 클래스

  • 기존 자바스크립트 문법은 클래스 표현식이 없어서 prototype으로 클래스를 표현했다. 하지만 ES6는 클래스를 정의하여 사용할수 있다.
// ES5 문법
function Shape(x, y) {
  this.name = 'Shape';
  this.move(x, y);
}
// static 타입 선언 예제
Shape.create = function(x, y) {
  return new Shape(x, y);
};
Shape.prototype.move = function(x, y) {
  this.x = x;
  this.y = y;
};
Shape.prototype.area = function() {
  return 0;
};

// 혹은
Shape.prototype = {
  move: function(x, y) {
    this.x = x;
    this.y = y;
  },
  area: function() {
    return 0;
  },
};

var s = new Shape(0, 0);
var s2 = Shape.create(0, 0);
s.area(); // 0

function Circle(x, y, radius) {
  Shape.call(this, x, y);
  this.name = 'Circle';
  this.radius = radius;
}
Object.assign(Circle.prototype, Shape.prototype, {
  area: function() {
    return this.radius * this.radius;
  },
});

var c = new Circle(0, 0, 10);
c.area(); // 100

// ES6 예제
class Shape {
  static create(x, y) {
    return new Shape(x, y);
  }
  name = 'Shape';

  constructor(x, y) {
    this.move(x, y);
  }
  move(x, y) {
    this.x = x;
    this.y = y;
  }
  area() {
    return 0;
  }
}

var s = new Shape(0, 0);
var s1 = Shape.create(0, 0);
s.area(); // 0

class Circle extends Shape {
  constructor(x, y, radius) {
    super(x, y);
    this.radius = radius;
  }
  area() {
    if (this.radius === 0) return super.area();
    return this.radius * this.radius;
  }
}

var c = new Circle(0, 0, 10);
c.area(); // 100

02-5. 화살표 함수

  • 화살표 함수는 화살표 기호=>로 함수를 선언하고 화살표 기둥 =을 사용하므로 fat arrow function이라고 부르기도 한다.
function add(first, second) {
  return first + second;
}

var add = function(first, second) {
  return first + second;
};

var add = function add(first, second) {
  return first + second;
};

// this scope를 전달한 예
var self = this;
var addThis = function(first, second) {
  return self.value + first + second;
};

var addThis = (first, second) => first + second;

function addNumber(num) {
  return function(value) {
    return num + value;
  };
}
// 화살표 함수로 변환한 예
var addNumber = num => value => num + value;

var addTwo = addNumber(2);
var result = addTwo(4); // 6

// bind함수를 통해 this scope를 전달한 예
class MyClass {
  value = 10;
  constructor() {
    var addThis2 = function(first, second) {
      return this.value + first + second;
    }.bind(this);
    var addThis3 = (first, second) => this.value + first + second;
  }
}

02-6. 객체 확장 표현식과 구조 분해 할당

객체확장 표현식 사용 방법 알아보기

// ES5의 예
var x = 0;
var y = 0;

var obj = { x: x, y: y};

var randomKeyString = 'other';
var combined = {};
combined['one' + randomKeyString] = 'some value';

var obj2 = {
  methodA: function() { console.log('A'); },
  methodB: function() { return 0; },
};

// ES6의 예
var x = 0;
var y = 0;
var obj = { x, y };

var randomKeyString = 'other';
var combined = {
  ['one' + randomKeyString]: 'some value',
};

var obj2 = {
  x,
  methodA() { console.log('A'); },
  methodB() { return 0; },
};

구조 분해 사용 방법 알아보기

// ES5 예제
var list = [0,1];
var item1 = list[0];
var item2 = list[1];
var item3 = list[2] || -1;

var temp = item2;
item2= item1;
item1 = temp;

var obj = {
  key1: 'one',
  key2: 'two',
};

var key1 = obj.key1;
var key2 = obj.key2;
var key3 = obj.key3 || 'default key3 value';
var newKey1 = key1;

// ES6 예제
var list = [0, 1];
var [
  item1,
  item2,
  item3 = -1,
] = list;
[item2, item1] = [item1, item2];

var obj = {
  key1: 'one',
  key2: 'two',
};
var {
  key1: newKey1,
  key2,
  key3 = 'default key3 value',
} = obj;

var [item1, ...otherItems] = [0, 1, 2];
var { key1, ...others } = { key1: 'one', key2: 'two' };
// otherItems = [1, 2]
// others = { key2: 'two' }

02-7. 라이브러리 의존성 관리

  • ES6는 import 구문을 사용하여 script엘리먼트 없이 연결된 파일 및 의존 파일을 먼저 모두 내려 받고 코드를 구동하도록 변경한다.
// CommonJS 방식
var module = require('./MyModule');
function Func() {
  module();
}
module.exports = new Func();

// RequireJS 방식
// define(['./MyModule'], function(module) {
//   function Func() {
//     module();
//   }
//   return new Func();
// });

// ES6 방식
// import MyModule from './MyModule';
// import { ModuleName } from './MyModule';
// import { ModuleName as RenamedModuleName } from './MyModule';

// function Func() {
//   MyModule();
// }
export const CONST_VALUE = 0;
export default new Func();

02-8. 배열 함수

  • ES6에선 배열 함수인 forEach(),map(),reduce()함수가 추가되었다.
const qs = 'banana=10&apple=20&orange=30';

function parse(qs) {
  var queryString = qs.substr(1); // querystring = 'banana=10&apple=20&orange=30'
  var chunks = queryString.split('&'); // chunks = ['banana=10', 'apple=20', 'orange=30']
  var result = {};
  for(var i = 0; i < chunks.length; i++) {
    var parts = chunks[i].split('=');
    var key = parts[0];
    var value = Number.isNaN(Number(parts[1])) ? parts[1] : Number(parts[1]);
    result[key] = value;
  }
  return result;
}

const params = parse(qs); // params = { banana: 10, apple: 10, orage: 30};

function parse(qs) {
  const queryString = qs.substr(1); // querystring = 'banana=10&apple=20&orange=30'
  const chunks = queryString.split('&'); // chunks = ['banana=10', 'apple=20', 'orange=30']
  let result = {};
  chunks.forEach((chunk) => {
    const [ key, value ] = chunk.split('='); // key = 'banana', value = '10'
    result[key] = value; // result = { banana: 10 }
  });
  return result;
}

function parse(qs) {
  const queryString = qs.substr(1);
  const chunks = queryString.split('&');
  const result = chunks.map((chunk) => {
    const [ key, value ] = chunk.split('='); // key = 'banana', value = '10'
    return { key: key, value: value }; // { key: 'banana', value: '10' }
  });
  return result;
  // result = [
  //  { key: 'banana', value: '10'},
  //  { key: 'apple', value: '20' },
  //  { key: 'orange', value: '30'}
  // ];
}

function sum(numbers) {
  return numbers.reduce((total, num) => total + num, 0);
}
sum([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) // 55

function parse(qs) {
  const queryString = qs.substr(1);
  const chunks = queryString.split('&');
  return chunks
    .map((chunk) => {
      const [ key, value ] = chunk.split('='); // key = 'banana', value = '10'
      return { key, value }; // { key: 'banana', value: '10' }
    })
    .reduce((result, item) => ({
      ...result,
      [item.key]: item.value,
    }), {});
}

function parse(qs) {
  const queryString = qs.substr(1);
  const chunks = queryString.split('&');

  // return chunks
  //   .map((chunk) => chunk.split('='))
  //   .map(([key, value]) =>({ key, value }))
  //   .reduce((result, [ key, value ]) => ({
  //     ...result,
  //     [key]: value,
  //   }), {});
  return chunks
    .map((chunk) => chunk.split('='))
    .reduce((result, [ key, value ]) => ({
      ...result,
      [key]: value,
    }), {});
}

02-9. 비동기 함수

  • 기존의 콜백지옥을 벗어나기 위해서 만들었다는 후문이다.비동기 처리방식이 중요하니 다시한번 복습하록 하자.

02-10. 디바운스와 스로틀

디바운스(debounce): 어떤 내용을 입력하다가 특정 시간동안 대기하고 있으면 마지막에 입력된 내용을 입력하다가 특정시간 동안 대기하고 있으면 마지막에 입력된 내용을 바탕으로 서버 요청을 하는 방법이다. ex)연관검색어

스로틀(throttle): 디바운스 개념과 비슷하지만 ‘입력되는 동안에도 바로 이전에 요청한 작업을 주기적으로 실행한다는 점’이 다르다. ex)페이스북의 타임라인의 무한 스크롤 기능

  • 참고한 github : https://github.com/justinpark/justin-do-it-react/blob/master/src/02