1007 TIL

기멜·2021년 10월 7일
0

자바스크립트 독학

목록 보기
22/44

함수부터 듣기 시작합니다. 할 수 있다!
참조: 제로초 ES2021 자바스크립트 강좌

함수

프로그래밍에서 함수(function)는 일정한 동작을 수행하는 코드를 의미합니다. 함수를 미리 만들어두고 원할 때 실행해 정해진 동작을 수행하게 할 수 있습니다. 함수를 만들 때 보통 function 예약어를 사용하거나 =>(화살표) 기호를 사용합니다. 화살표 기호를 사용한 함수를 화살표 함수(arrow function)라고 합니다.

함수의 두가지 방법

function() {}
// 또는
() => {}

위에 함수에는 이름이 없기 때문에 다른 곳에서 사용할 수 없습니다. 함수에 이름을 붙이면 다른 곳에서 사용할 수 있습니다.
함수에 이름을 붙여봅시다.

함수에 이름 붙여주는 세 가지 방법

function a() {} // 함수 선언문
const b = function() {}; // 함수 표현식
const c = () => {}; // 화살표 함수

세 개의 함수에 각각 a,b,c라고 이름을 붙였습니다. 두 번째와 세 번째 함수는 각각 상수(const) b 와 c 에 대힙했습니다. 이렇게 대입하면 상수 또는 변수의 이름이 함수의 이름이 됩니다.
함수 a 만 특별하게 상수에 대입하지 않았습니다. 이처럼 함수를 상수에 대입하는 대신 function 키워드 뒤에 함수 이름을 넣어주는 방식을 함수 선언문(function declaration srarement)이라고 합니다. 반대로, 함수 b와 같이 상수나 변수에 대입하는 방식을 함수 표현식(function expression)이라고 합니다. 여기에 화살표 함수까지 포함해 함수를 만드는 방식은 크게 세 가지라고 보면 됩니다. 셋 사이에는 큰 차이가 있습니다. 변수와 마찬가지로 함수를 만드는 행위도 선언한다(declare)고 표현합니다.

<참고> 왜 a 함수 뒤에는 세미콜론을 안 붙이는지?
if문, for문, while문, 함수 선언문의 중괄호 뒤에는 세미콜론이 붙지 않습니다.

자, 이제 만든 함수를 사용해 보겠습니다. 함수를 사용하는 행위를 호출한다(call)고 표현합니다.

function a() {} //선언
a(); //호출
< undefined

함수 a 를 선언한 수 a 뒤에 ()를 붙이면 함수가 실행됩니다. 그런데 함수의 이름 뒤에 ()를 붙이는 것을 어디서 많이 보지 않았나요? 지금까지 console.log 나 parseInt 같은 명령 뒤에 ()를 붙여 사용했습니다. 바로 console.log와 parseInt도 함수이기 때문입니다.

이번에는 함수 안에 동작문을 넣어봅시다. 함수의 중괄호 안에 실행할 코드를 넣어주면 됩니다.

function a() {
  console.log('hello');
  console.log('Function');
}
a();
< hello
< Function

실행하려는 코드를 함수로 만들어두면 좋은 점이 있습니다. 재사용하기 쉽습니다. 함수 a 를 여러 번 호출하면 호출한 만큼 내부의 동작문이 실행됩니다.a();를 여러번 쓰면 hello, Function이 여러번 실행됩니다.

return 이해하기

function a() {}
< undefined //return값
a();
< undefined //return값

식들은 반환값이라는 것이 있다. undefined도 반환값이다.

function b() {
  return '반환값';
}
< undefined
b();
< '반환값'
function c() {
  return 'hello';
  console.log('hi');
}
c();
< 'hello' // return만 인식함

함수 동작문 끝에 return undefined가 있다고 생각하면 된다.

function a() {
  console.log('a');
}
// 위 아래는 동일함
function a() {
  console.log('a');
  return undefined; // 생략되어있다.
}

반환값도 값이므로 다른 식이나 문에 넣어 사용할 수 있습니다.

function a() {
  return 10;
}
console.log(a());
< 10 //함수 안에 return으로 10이 있기때문에 a()는 10 이다.

여러개의 값을 내놓고 싶다면 배열을 사용하면됩니다.

function a() {
  return [1, 5];
}
a();
< (2) [1, 5]

return문의 기능이 하나 더 있습니다. 바로 함수의 실행을 중간에 멈추는 역할입니다.

function a() {
  console.log('hello');
  return;
  console.log('Return');
}
a();
< hello

이를 활용하여 조건문과 return문을 결합해 함수의 실행을 조작할 수 있습니다.

function a() {
  if (false) {
    return; //false니까 여기서 멈추게 된다.
  }
  console.log('실행됩니다.');
}
a();
< 실행됩니다.

매개변수와 인수

console.log 함수를 호출할 때 소괄호 안에 값을 넣었습니다. 그렇게 넣은 값을 console.log 함수가 받아서 콘솔에 출력합니다. 여기서 알 수 있는 것은 함수에 원하는 값을 넣을 수도 있다는 것입니다. 여기서 매개변수와 인수의 관계가 나옵니다.

function a(parameter) {
  console.log(parameter);
}
a('argument'); // a(parameter) 와 연결이 된다.
< argument

소괄호에 넣은 'argument' 문자열이 어떻게 사용되는지를 파악해야 합니다. 이 문자열은 함수 a 를 선언할 때 소괄호에 넣은 parameter와 연결됩니다. 따라서 parameter는 'argument'의 값을 가집니다.
parameter = 'argument'와 같고, 실제로 parameter는 변수와 같은 특성을 가집니다.

함수가 하나의 매개변수와 하나의 인수만을 가지는 것은 아닙니다. 각각 여러 개를 가질 수 있고, 매개변수와 인수의 개수가 일치하지 않아도 됩니다.

function a(w, x, y, z) {
  console.log(w, x, y, z);
  console.log(arguments);
}
a('hello', 'parameter', 'Argument');
< hello parameter Argument undefined
< Arguments(3) ['hello', 'parameter', 'Argument']

인수 hello, Parameter, Argument 가 각각 매개변수 w,x,y에 연결됩니다. 그런데 매개변수 z에 대응되는 인수는 존재하지 않습니다. 이때 대응되지 않는 매개변수에는 자동으로 undefined 값이 대입됩니다. 따라서 매개변수 z의 값이 undefined가 됩니다.

이렇게 매개변수와 인수의 개수가 일치하지 않을 수 있습니다. 따라서 매개변수의 개수로 인수의 개수를 예측할 수 없습니다. 만약 인수가 몇 개 들어왔는지 궁금하다면 어떻게 해야할까요?
함수 내에서 arguments 라는 값을 사용할 수 있습니다. 예제에서 console.log(arguments)로 arguments를 출력해 보니 호출 시 넣었던 인수 목록을 볼 수 있습니다. 그 뒤에 나오는 callee나 Symbol(symbol.iterator)는 인수가 아니니 무시해도 됩니다.
그런데 화살표 함수 안에서는 arguments 를 사용할 수 없습니다. arguments 는 function으로 선언한 함수에서만 사용할 수 있습니다.

이번에는 인수는 같지만, 매개변수의 개수를 인수보다 적게 만들어 보았습니다.

function a(w, x) {
  console.log(w, x);
}
a('hello','Parameter','Argument');
< hello Parameter

이러면 Argument 가 무시가 됩니다.

더하기를 하는 간단한 함수를 만들어 보겠습니다.

function add(x, y) {
  return x + y;
}
console.log(add(3, 5));
console.log(add(8, 7));
< 8
< 15

return문을 통해 둘을 더한 값을 반환합니다.

문제
매개변수로 x,y,z를 받아 곱한 값을 반환하는 multiply 함수를 만들어 보세요. 화살표 함수로 만드세요

const f = (x, y, z) => {
  return x * y * z;
}
f(2, 3, 4)
< 24

그런데 {} 와 return 이 이어지면 이 역시도 생략할 수 있습니다.

const f = (x, y, z) => x * y * z;
f(2, 3, 4)
< 24

이렇게 줄여 쓸 수도 있습니다. 간단한 것을 할 때는 화살표 함수가 많이 쓰입니다.

다른 변수 사용하기

함수 내부에서 매개변수 외에도 변수나 상수를 선언할 수 도 있습니다.

function minus1(x, y) {
  const a = 100;
  return (x - y) * a;
}
console.log(minus1(5, 3));
< 200

이처럼 함수 내부에 const a = 100이라는 변수를 선언을 했습니다. 밖에 변수를 만들어도 됩니다.

const a = 100;
function minus1(x, y) {
  return (x - y) * a;
}
console.log(minus1(5, 3));
< 200

객체 리터럴

배열이나 함수가 아닌 객체를 살펴봅시다. 객체는 여러 개의 변수를 하나의 변수로 묶을 때 사용합니다. 다음과 같은 코드가 있다고 생각해 봅시다.

const kimel = {
  name: '기멜',
  year: 1992,
  month: 11,
  date: 8,
  gender: 'W',
};

kimel 이라는 변수를 선언하고, 그 안에 정보들을 모아두었습니다. 정보들은 {} 안에 묶여 있습니다. 객체 내부에 사용한 name ~ gender 같은 정보들을 속성이라고 합니다.
속성은 속성 이름속성 값으로 구분됩니다. name: '기멜'이라는 속성에서는 name 이 속성 이름이고, '기멜'은 속성 값이 됩니다. 이처럼 {}를 사용해 객체를 표현하는 것을 **객체 리터럴** 이라고 합니다

마지막에 쉼표를 넣는 이유
요즘은 코딩할 때 어떤 코드를 변경했는지 체크해주는 git같은 도구를 사용합니다. 보통 이러한 종류의 도구는 줄 단위로 어떤 줄이 변경됐는지를 알려줍니다. 다음을 대비해서 항상 , 를 찍어줍시다.

접근하는 방법은 두 가지가 있습니다.

const kimel = {
  name: '기멜',
  year: 1992,
  month: 11,
  date: 8,
  gender: 'F',
};
console.log(kimel.name); // .으로 접근하는 방법
console.log(kimel['name']); //[] 로 접근하는 방법
기멜
기멜

만약에 객체 내부에 존재하지 않는 속성에 접근한다면 undefined 가 나옵니다.

객체 속성 수정하기

객체를 만들고, 객체 내부의 속성에 접근해 보았습니다. 이번에는 객체 내부의 속성을 수정해 보겠습니다.

kimel.gender = 'M';
console.log(kimel.gender);
< M //실행결과

객체 속성 제거하기

객체 내부의 속성을 제거할 수도 있습니다. 이럴때 delete를 쓰면 됩니다.

delete kimel.gender;
console.log(kimel.gender);
< undefined // 제거되서 이렇게 보인다.

메서드 이해하기

객체의 속성 값으로 함수를 넣었을 때 이 속성을 특별히 메서드(method)라고 합니다.

const debug = {
  log: function(value) {
    console.log(value);
  }
}
debug.log('hello, Method!');
< hello, Method!

log는 debug 객체의 메서드 입니다. 이와 비슷한 코드는 바로 console.log 입니다. 지금까지 콘솔 창에 결과를 출력하려고 사용했던 함수가 바로 console객체의 log 메서드 였습니다.
console객체와 그 안에 든 log 메서드는 웹 브라우저가 기본으로 만들어 둔 객체이므로 따로 선언하지 않아도 사용할 수 있습니다.

객체 간의 비교

객체를 다룰 때 가장 많이 실수를 하는 상황이 있습니다. 바로 객체 간에 비교 연산을 할 때입니다.

{} === {}
< false

객체끼리는 서로 모양이 같아도 false가 나옵니다.
객체가 아닌({}로 묶인게 아닌) 숫자, 문자열, 불 값, null, undefined는 모두 true를 반환합니다.
객체는 모양이 같아도 생성할 때마다 새로운 객체가 생성됩니다. 따라서 같은 객체인지 비교하고 싶다면 기존 객체를 변수에 저장해 두어야 합니다.

const a = {name: 'kimel'};
const array = [1, 2, a];
console.log(a === array[2])
< true

const a 객체를 a라는 변수에 저장을 하고 array 배열 안에 넣고, 그 a 와 array 배열에 index 2번째 자리에 있는 a와 비교를 하니까 true가 나오는 것.

참조와 복사

객체를 사용할 때 반드시 알아야할 개념이 참조(reference)입니다.

const a = { name: 'kimel'};
const b = a;
a.name = 'hero';
console.log(b.name); //hero

변수 b에 a를 대입한 상황. a 변수의 name 속성 값을 변경했는데, b 변수도 같이 변경됐습니다. 객체를 저장한 변수를 다른 변수에 대립하면 두 변수 모두 같은 객체를 저장하는 셈이 됩니다. a 와 b 변수 모두 같은 객체를 저장하고 있는 것이므로 객체의 속성 값을 바꾸면 변수 a 와 b 모두 바뀌는 것 처럼 보입니다. 이러한 상황일 때 변수 a 와 b 가 같은 객체를 참조하고 있다고 표현합니다. 또는 a 와 b 그리고 객체 간에 참조 관계가 있다고 표현합니다.

다만 객체가 아닌 값 (문자열, 숫자, 불 값, null, undefined) 의 경우는 좀 다릅니다.

let a = 'kimel';
let b = a;
a = 'hero';
console.log(b); // 'kimel'

a 인 'kimel'값이 b로 들어가고 a를 hero로 바꿨고. 이때는 b 값을 호출하면 그대로 'kimel'이 나오게 됩니다. 참조 관계가 생기지 않기 때문.
이렇게 참조가 생기지 않는 상황을 복사(copy)라고 부릅니다.
객체를 변수에 담으면 참조 관계가 생긴다는 것을 꼭 기억하세요

대화창

prompt 함수는 사용자로부터 값을 전달받는다.
alert 는 사용자에게 경고 메세지를 표시한다.
confirm 함수는 사용자의 확인을 요구한다.

profile
프론트엔드 개발자를 꿈꾸는 도화지 위를 달리는 여자

0개의 댓글