JavaScript

1. Object

Object.assign()

열거할 수 있는 하나 이상의 출처 객체로부터 대상 객체로 속성을 복사할 때 사용합니다. 대상 객체를 반환합니다.
[ Object.assign() | MDN ]

let obj1 = {
  a: 1,
  b: 2
};
let obj2 = {
  b: 4,
  c: 3
};

object.assign(obj1, obj2); // 타겟 obj1 -> obj1이 변한다.
// {a: 1, b: 4, c: 3}
obj1
// {a: 1, b: 4, c: 3}

Object.assign({}, obj1, obj2); // 타겟 {} -> 클론이 만들어진다.
// {a: 1, b: 4, c: 3}
obj1 // 변하지 않음.
// {a: 1, b: 2}

let newObj = Object.assign({}, obj1, obj2);
newObj
// {a: 1, b: 4, c: 3}
Object.assign(newObj, obj1); // 타겟과 출처가 같은 키를 가졌다면, 출처의 값이 타겟의 값을 덮어쓴다.
// {a: 1, b: 2, c: 3}

2. Array

Array 메서드의 Mutating

기존 배열을 변경하는 대표적인 Array 메서드들

메서드명 반환내용
Array.push() push() 메서드는 배열의 끝에 하나 이상의 요소를 추가하고, 배열의 새로운 길이를 반환합니다.
Array.ushift() unshift() 메서드는 새로운 요소를 배열의 맨 앞쪽에 추가하고, 새로운 길이를 반환합니다.
Array.pop() pop() 메서드는 배열에서 마지막 요소를 제거하고 그 요소를 반환합니다.
Array.shift() shift() 메서드는 배열에서 첫 번째 요소를 제거하고, 제거된 요소를 반환합니다.
Array.splice() splice() 메서드는 배열의 기존 요소를 삭제 또는 교체하거나 새 요소를 추가합니다.제거한 요소를 담은 배열을 반환합니다.

Array.reduce()

배열의 각 요소에 대해 주어진 리듀서(reducer) 함수를 실행하고, 하나의 결과값을 반환합니다.
초기값을 제공하지 않으면 배열의 첫 번째 요소를 사용합니다. 빈 배열에서 초기값 없이 reduce()를 호출하면 오류가 발생합니다.
[ Array.prototype.reduce() | MDN ]

// 인덱스에 배열이 들어있는 배열 arr을 하나의 배열로 만들기
function joinArrayOfArrays(arr) {
  const joinedArr = arr.reduce(function(acc, val) {
    return acc.concat(val);
  });
  return joinedArr;
}
// 배열 안에서 가장 길이가 짧은 값을 찾기
return newArray.reduce(function(arr, curr) {
  if (arr.length <= curr.length) {
    return arr;
  } else {
    return curr;
  }
});
// 배열 안 모든 요소를 곱한 값을 구하기
function allElements(arr) {
  return arr.reduce(function(acc, val) {
    return acc * val;
  });
}

Array.filter()

주어진 함수의 테스트를 통과하는 모든 요소를 모아 새로운 배열로 반환합니다.
[ Array.prototype.filter() | MDN ]

// 100보다 작은 값만 반환하기
return prop.filter(function(el) {
  return el < 100;
});
// null값이 아닌 값만을 반환하기
var finalAnswer = answer.filter (
    function (answer) {
      return answer != null;
  }
);

Array.map()

배열 내의 모든 요소 각각에 대하여 주어진 함수를 호출한 결과를 모아 새로운 배열을 반환합니다.
[ Array.prototype.map() | MDN ]

var array1 = [1, 4, 9, 16];
const map1 = array1.map(x => x * 2);
console.log(map1);
// [2, 8, 18, 32]

// 배열 각 요소를 거듭제곱한 값을 반환함
return prop.map(function(x) {
    return Math.pow(x, 2);
  });

const map = prop.map(x => x * x);

console.log(map);
// [1, 16, 81, 256]

Array.slice()

어떤 배열의 begin부터 end까지(end 미포함)에 대한 얕은 복사본을 새로운 배열 객체로 반환합니다.
[ Array.prototype.slice() | MDN ]

var animals = ['ant', 'bison', 'camel', 'duck', 'elephant'];

console.log(animals.slice(0, -1));
// ["ant", "bison", "camel", "duck"]
animals.slice(); // 추출시점(인덱스값)을 넣지 않으면 클론이 생성된다.

Array.push()

배열의 끝에 하나 이상의 요소를 추가합니다.
값 한 개 뿐 만 아니라 배열 혹은 여러개의 값을 만들거나 넣을 수 있습니다.
[ Array.prototype.push() | MDN ]

function convertObjectToList(obj) {
  let result = [];
  for (let key in obj) {
    result.push(key, obj[key]); // 여러개의 값을 넣을 수 있다.
  }
  return result;
}
function convertObjectToList(obj) {
  let result = [];
  for (let key in obj) {
    result.push([key, obj[key]]); // 값을 배열로 만들어 넣을 수 있다.
  }
  return result;
}
function convertObjectToList(obj) {
  let result = [];
  for (let key in obj) {
    result.push({key : obj[key]}); // 값을 객체 형태로 넣으려고 시도했다. 키값은 모두 'key'로, value값은 값으로 전달된다. 'key'를 적으면 value로 key가 전달된다.
  }
  return result;
}
// [{key: "Holly"}, {key: 35}, {key: "producer"}]

Array.indexOf()

배열에서 지정된 요소를 찾을 수 있는 첫 번째 인덱스를 반환합니다. 존재하지 않으면 -1을 반환합니다.
[ Array.prototype.indexOf() | MDN ]

var beasts = ['ant', 'bison', 'camel', 'duck', 'bison'];

console.log(beasts.indexOf('bison'));
// expected output: 1

// start from index 2
console.log(beasts.indexOf('bison', 2));
// expected output: 4

console.log(beasts.indexOf('giraffe'));
// expected output: -1

Array.isArray()

인자가 Array인지 판별합니다. 객체가 Array라면 true, 아니라면 false를 반환합니다.
[ Array.isArray() | MDN ]

const emptyArray = [];
const filledArray = [1, 2, 3];
const obj = {};

// 매개변수가 배열인지 아닌지를 검사하기
if(Array.isArray(emptyArray)) {
  console.log('hello');
};
// 'hello'

if(Array.isArray(obj)) {
  console.log('hello');
};
// undefined
// 배열이 비었는지 아닌지를 검사하기 
if(emptyArray.length === 0) {
  console.log('hello');
};
// 'hello'

if(filledArray.length === 0) {
  console.log('hello');
};
// undefined

3. String

String.concat()

호출 문자열에 매개변수 문자열을 이어 붙인 결과를 반환합니다. 원본 문자열과 결과 문자열의 변형은 서로에게 영향을 미치지 않습니다. 매개변수의 값이 문자열이 아니면 계산 전에 문자열로 변환합니다.
[ String.prototype.concat() | MDN ]

str1.concat(str2, str3);

var str1 = 'Hello';
var str2 = 'World';

console.log(str1.concat(' ', str2)); // ' ' 삽입
// expected output: "Hello World"

console.log(str2.concat(', ', str1)); // ', ' 삽입
// expected output: "World, Hello"

String.toUpperCase(), String.toLowerCase()

var sentence = 'The quick brown fox jumps over the lazy dog.';

// 문자열을 대문자로 변환해 반환합니다.
sentence = sentence.toUpperCase();
// 'THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG.'

// 문자열을 소문자로 변환해 반환합니다.
sentence = sentence.toLowerCase();
// 'The quick brown fox jumps over the lazy dog.'

4. 문자열이 아닌 값을 문자열로 변환하는 메서드

String()

일반적으로 toString() 함수를 많이 사용하고 있지만, toString()의 "안전한" 대안으로 String을 사용할 수 있습니다. String은 [null]과 [undefined]에 대해서도 잘 동작합니다.
[ 문자열 변환 | MDN ]

var outputStrings = [];
for (var i = 0, n = inputValues.length; i < n; ++i) {
  outputStrings.push(String(inputValues[i]));
}

Number.toString()

toString() 메소드는 메소드의 첫 번째 아규먼트를 파싱하여, 메소드는 특정 기수(radix)를 기준으로 한 진수 값의 문자열을 환원하기 위한 시도를 합니다. 진수를 나타내는 기수 값(radix) 이 10 이상의 값일 때는, 알파벳의 글자는 9보다 큰 수를 나타냅니다. 예를 들면, 16진수(base 16)는, 알파벳 f 까지 사용하여 표현됩니다.
만약에 radix값 이 지정되지 않으면, 임의로 10진수로 가정하게 됩니다.
[ Number.prototype.toString() | MDN ]

var count = 10;

console.log(count.toString());    // '10'
console.log((17).toString());     // '17'
console.log((17.2).toString());   // '17.2'

var x = 6;

console.log(x.toString(2));       // '110' 2진수
console.log((254).toString(16));  // 'fe' 16진수

console.log((-10).toString(2));   // '-1010' 10진수 음수를 2진수로
console.log((-0xff).toString(2)); // '-11111111' 16진수 음수를 2진수로

Object.toString()

모든 객체에는 객체가 텍스트 값으로 표시되거나 객체가 문자열이 예상되는 방식으로 참조 될 때 자동으로 호출되는 toString() 메서드가 있습니다. 기본적으로 toString() 메서드는 Object에서 비롯된 모든 객체에 상속됩니다.
[ Object.prototype.toString() | MDN ]

function Dog(name, age) {
  this.name = name;
  this.age = age;
}

var dog1 = new Dog('Gabby', '24');

Dog.prototype.toString = function dogToString() { // toString 메서드를 재정의함
  return '' + this.name + ' ' + this.age;
}

console.log(dog1.toString()); // 재정의한 메서드의 반환 결과
// "Gabby  24"

이 메서드가 사용자 지정 개체에서 재정의되지 않으면 toString()은 "[object type]"을 반환합니다. 여기서 type은 object type입니다.

var o = new Object(); // 재정의 하지 않았을 때
o.toString(); // returns [object Object]

5. Math 메서드 + 숫자열을 반환하는 함수

Math.abs()

주어진 숫자의 절대값을 반환합니다.
[ Math.abs() | MDN ]

Math.abs('-1');     // 1
Math.abs(-2);       // 2
Math.abs(null);     // 0
Math.abs('');       // 0
Math.abs([]);       // 0
Math.abs([2]);      // 2
Math.abs([1,2]);    // NaN
Math.abs({});       // NaN
Math.abs('string'); // NaN
Math.abs();         // NaN

Math.sqrt()

숫자의 제곱근을 반환합니다.
[ Math.sqrt() | MDN ]

Math.sqrt(9); // 3
Math.sqrt(2); // 1.414213562373095

Math.sqrt(1);  // 1
Math.sqrt(0);  // 0
Math.sqrt(-1); // NaN

parseInt()

문자열 인자의 구문을 분석해 특정 진수(수의 진법 체계에 기준이 되는 값)의 정수를 반환합니다.
[ parseInt() | MDN ]

만약 radix 가 undefined 이거나 0이라면, (또는 없다면), JavaScript 는 아래와 같이 임의 처리합니다.

  • 인풋 값 string 이 "0x" 나 "0X"로 시작한다면, radix 는 16(16진)이며, 나머지 문자열은 파싱됩니다.
  • 인풋 값 string 이 "0"으로 시작한다면, radix 는 8(8진)이거나, 10(십진)입니다. 정확히 이 선택된 radix 는 구현 의존적적입니다. ECMAScript 5 는 10(십진)이 사용되는 것을 명시하지만, 모든 브라우저가 아직 이렇게 되지 않습니다. 이러한 이유로 항상 parseInt를 사용할 때는 radix 값을 명시해야 합니다.
  • 인풋 값 string 이 다른 값으로 시작 된다면, radix 는 10(십진)입니다.
// 다음의 예제는 모두 15을 리턴합니다.
parseInt("15.3456");
parseInt("15.3456", 10);
parseInt("15,123", 10);
parseInt("1111", 2);
parseInt("17", 8);
// 다음의 예제는 모두 -15을 리턴합니다.
parseInt("-15", 10);
parseInt("-1111", 2);
parseInt("-17", 8);
  • 만약 매개변수 string이 문자열이 아니면 문자열로 변환(ToString 추상 연산을 사용)합니다.
let a = 3.11
let b = 4.13

parseInt(a + b);
// 7

parseFloat()

[ parseFloat() | MDN ]

// 아래 예제는 모두 3.14를 반환합니다.
parseFloat(3.14);
parseFloat('3.14');
parseFloat('3.14와 숫자가 아닌 문자들');

6. 양수를 음수로, 음수를 양수로 만드는 방법

0 - n // -n
-1 * n // -n

7. 의문점 해결 : 객체와 let의 특징

Q. 사원들의 정보를 다른 형태로 변형 할 수 있는 함수 "transformEmployeeData" 함수를 작성하세요.
A1.

// 예시 인자
var array = [
  [['firstName', 'Joe'], ['lastName', 'Blow'], ['age', 42], ['role', 'clerk']],
  [['firstName', 'Mary'], ['lastName', 'Jenkins'], ['age', 36],['role', 'manager']]
];

// 원하는 반환 결과
[
  { firstName: 'Joe', lastName: 'Blow', age: 42, role: 'clerk' },
  { firstName: 'Mary', lastName: 'Jenkins', age: 36, role: 'manager' }
];
// 함수
function transformEmployeeData(array) {
  let result = [];

  for (let i = 0; i < array.length; i++) {
    let arrInArr = array[i];
    let obj = {};
    for (let j = 0; j < arrInArr.length; j++) {
      obj[arrInArr[j][0]] = arrInArr[j][1];
    }
    result.push(obj); // obj를 두 번 result에 push해준다.
  }

  return result;
}

이 문제를 페어 프로그래밍으로 풀다가 의문이 생겼다. 객체 obj를 첫번째 for문 안쪽이 아닌 바깥쪽에 선언해주면 어떤 방식으로 에러가 나는지를 살펴보았더니, 마지막에 대입되는 객체만 result에 두 번 push되어 있었다. 그런데 그 이유를 잘 이해할 수 없었다.

A2.

function transformEmployeeData(array) {
  let result = [];
  let obj = {}; // 여기에 obj를 선언함
  for (let i = 0; i < array.length; i++) {
    let arrInArr = array[i];
    for (let j = 0; j < arrInArr.length; j++) {
      obj[arrInArr[j][0]] = arrInArr[j][1];
    }
    result.push(obj);
  }
  return result;
}
// 결과 : for문이 만들어내는 마지막 객체만 두 번 result에 push 되어있다.
[
  { firstName: 'Mary', lastName: 'Jenkins', age: 36, role: 'manager' }
  { firstName: 'Mary', lastName: 'Jenkins', age: 36, role: 'manager' }
];

그래서 개발자 도구로 중단점을 이용해 A2를 살펴보니 다음과 같았다.

  1. 첫번째 for문에서 i = 0일 때, { firstName: 'Joe', lastName: 'Blow', age: 42, role: 'clerk' } 가 obj에 대입되고 result에 push된다.
  2. 첫번째 for문에서 i = 1일 때, for문이 실행되면서 동시에 obj가 두 번째 배열을 읽은 값인 Mary로 바뀐다.
  3. 동시에 result안에 push된 obj안에도 반영되어, 결국 result의 0번째 인덱스값인 객체 obj의 내용이 Mary로 바뀐다.
  4. 그 후 Mary의 키와 값이 대입된 객체 obj가 result에 push되어 result의 1번 인덱스에 들어간다.
  5. 결과적으로 result 의 0번과 1번 인덱스 모두 Mary가 된다.

정리하면 :

  • A2의 경우, result 안에 push된 obj가 맨 처음에 선언한 obj와 같기 때문에, 처음에 선언한 obj가 변하면 result안의 obj도 변한다.
  • A1의 경우, 첫 for문 안쪽에 obj를 새로 선언하면, for문이 반복될 때마다 for문 안쪽은 새로운 블록이 되기 때문에, i = 0일 때 선언된 obj와 i = 1일 때 선언된 obj는 서로 다른 변수이므로 서로 영향을 미치지 않는다.

2019.08.02 티스토리 블로그에 작성한 글을 velog로 옮김