함수 선언(function declaration)

자바스크립트에서 함수는 다양한 방식으로 선언할 수 있는데, 가장 일반적인 방법은 function 키워드를 통해 함수를 선언하는 방식이고, 

// 함수 선언
function 함수이름(파라미터) {
  동작
  return; 리턴값
};

function sayHi() {
  console.log('Hi!');
};

다른 하나는 함수 선언을 변수에 할당하는 방식(함수 표현식 (function expression))이다. 

//함수 표현식
const printCode = function () {
  console.log('Code World!');
};

printCode();

 

자바스크립트에서 함수는 값으로 취급될 수도 있기 때문에 변수에 할당해서 함수를 선언할 수도 있다. 함수선언을 변수에 할당하는 모습만 함수 표현식이라고 오해할 수 있는데, 

// 변수에 할당해서 활용
const printJS = function () {
  console.log('JavaScript');
};

// 객체의 메소드로 활용
const codeLove = {
  printTitle: function () {
    console.log('Code');
  }
}

// 콜백 함수(callback function, 다른 함수의 파라미터에 전달된 함수)로 활용
myBtn.addEventListener('click', function () {
  console.log('button is clicked!');
});

// 고차 함수(higher order function, 변수에 호출된 값 할당해서 활용)로 활용
function myFunction() {
  return function () {
    console.log('Hi!?');
  };
};
//이중 괄호를 사용해서 고차함수를 바로 호출할수도 있다.
myFunction()();

파라미터로 함수를 선언해서 전달한 콜백함수로 활용하는 모습도 결과적으로는 함수선언을 값처럼 활용한다는 점에서 함수 표현식이라고 할 수 있다.

✅함수 표현식은 변수에 할당하는것이 포인트가 아니라 함수 선언을 값처럼 사용하는 방식이 포인트다.

함수 선언과 함수 표현식의 차이

//함수 선언
printCode(); //Welcome Coding World

function printCode() {
  console.log('Welcome Coding World');
};

함수 선언보다 먼저 함수를 호출했는데도 문제 없이 코드가 잘 동작한다. 선언문이 위쪽으로 끌어올려지는 현상을 호이스팅(Hoisting)이라고 한다.

//함수 표현식
printCode(); //ReferenceError

const printCode = function() {
  console.log('Welcome Coding World');
};

반면 함수 표현식은 변수 특성상 선언 이전에 접근할 수가 없다.

//함수 선언
function printCode() {
  function printJS() {
    console.log('JavaScript');
  }
  console.log('Hello Code World');
  printJS();
};

printCode(); //Hello Code World, JavaScript
printJS(); //ReferenceError

함수 선언은 변수의 var 키워드 처럼 함수 스코프를 가진다. 함수 안에 선언된 함수는 함수 밖에서 호출할 수 없지만 함수가 아닌 다른 코드블록에서 함수 선언을 하게 되면 모두 전역적으로 호출이 가능해진다.

//함수가 아닌 다른 코드블록에서 함수 선언을 해서 전역적으로 호출이 가능해진 모습
const x = 4;

if (x < 5) {
  function printJS() {
    console.log('JavaScript');
  }
};

{
  function printCode() {
    console.log('I love Coding');
  };
}

printCode(); //I love Coding
printJS(); //JavaScript

반면에 함수 표현식의 경우에는 할당된 변수에 따라 스코프(scope)가 결정된다.

var printJS = function () {
  console.log('JavaScript');
};

let printHi = function () {
  console.log('Hi');
};

const printCode = function () {
  conosole.log('Coding');
};
함수 선언 함수 표현식
-코드의 가독성
-변수 선언과 함수선언 명확하게 구분 가능
-함수 호출 자유로움
-반드시 선언 이후에 호출 가능
-가독성 good
-코드의 흐름 더 쉽게 파악 가능
-변수의 스코프도 활용 가능

일반적으로 개념을 설명할 때는 표현식보다 선언 부분이라는 의미가 좀 더 명확하게 구분되는 함수 선언이 보편적으로 사용된다.


파라미터(Parameter)의 기본 값

함수를 호출할때 함수의 밖에서 안쪽으로 다양한 값들을 전달받고자 한다면 파라미터를 활용해야한다.

자바스립트에서 함수의 파라미터는 할당 연산자로 기본값을 가질 수가 있다. 기본값이 있는 파라미터는 함수를 호출할 때 아규먼트를 전달하지 않으면, 함수 내부의 동작은 이 파라미터의 기본값을 가지고 동작하게 된다.

//  (name)이 파라미터이다.
function greeting(name) {
  console.log(`Hi! My name is ${name}!`);
}

//파라미터를 활용하면 전달하는 값에 따라서 다양한 결과로 동작하는 모습을 확인 할 수 있다.
greeting('Anna'); //Hi My name is Anna!
greeting('Tom'); //Hi My name is Tom!
greeting(); //Hi My name is Undefined!

// 파라미터 기본값
function sayHi(name = 'kelly') {
  console.log(`Hi! ${name}`);
}

sayHi('JavaScript'); // Hi! JavaScript
sayHi(); // Hi! kelly


//아규먼트가 파라미터로 전달될 때는 파라미터의 기본값과는 관계없이 함수를 호출할 때 작성한 순서 그대로 전달한다.
//때문에 기본값이 필요한 파라미터는 가급적 오른쪽에 작성하는것이 권장된다.
function greeting(name = 'Jenny', interest = 'Javascript') {
  console.log(`Hi! My name is ${name}!`);
  console.log(`I Like ${interest}!`);
};

greeting(undefined, 'Python'); //아규먼트가 undefined값으로 전달될 때도 동작한다.

//출력되는 값
Hi! My nmae is Jenny!
I Like Python!

arguments 객체

자바스크립트 함수 안에는 arguments라는 독특한 객체가 존재한다. arguments 객체는 함수를 호출할 때 전달한 아규먼트들을 배열의 형태로 모아둔 유사 배열 객체인데 특히, 함수를 호출할 때 전달되는 아규먼트의 개수가 불규칙적일 때 유용하게 활용될 수 있다.

function printArguments() {
  // arguments 객체의 요소들을 하나씩 출력
  for (const arg of arguments) {
    console.log(arg); 
  }
}

printArguments('Young', 'Mark', 'Koby');

‼️파라미터와 아규먼트를 헷갈릴 수도 있다. 하지만 꼭 구분지어서 알아두는 것이 좋다.

function greeting(name) { //함수 선언 부분에서 소괄호 안에 작성되는것이 파라미터
  console.log(`Hi My naame is ${name}!`);
};

greeting('Anna'); //함수 호출부분에서 파라미터로 전달하는 값에 해당하는 부분이 아규먼트
greeting('Jenny');
greeting('Tom');

Rest Parameter

arguments 객체를 이용하는 것 말고도 불규칙적으로 전달되는 아규먼트를 다루는 방법이 있다. 파라미터 앞에 마침표 세 개를 붙여주면, 여러 개로 전달되는 아규먼트들을 배열로 다룰 수 있다.
그리고 arguments객체는 유사 배열이기 때문에 배열의 메소드를 활용할 수 없는 반면, rest parameter는 배열이기 때문에 배열의 메소드를 자유롭게 사용할 수 있다는 장점이 있다.

function printArguments(...args) {
  // args 객체의 요소들을 하나씩 출력
  for (const arg of args) {
    console.log(arg); 
  }
}

printArguments('Young', 'Mark', 'Koby');

rest parameter는 다른 일반 파라미터들과 함께 사용될 수도 있는데

//앞에 정의된 parameter에 아규먼트를 먼저 할당하고 (first, second)
//나머지 아규먼트(...other)를 배열로 묶는 역할을 하기 때문에 
//일반 파라미터와 사용될때는 가장 마지막에 작성되어야 한다.
function printRankingList(first, second, ...others) {
  console.log('코드잇 레이스 최종 결과');
  console.log(`우승: ${first}`);
  console.log(`준우승: ${second}`);
  for (const arg of others) {
    console.log(`참가자: ${arg}`);
  }
}

printRankingList('Tommy', 'Jerry', 'Suri', 'Sunny', 'Jack');

이름 그대로 앞에 정의된 이름 그대로 앞에 정의된 파라미터에 argument를 먼저 할당하고 나머지 argument를 배열로 묶는 역할을 하기 때문에 일반 파라미터와 함께 사용할 때는 반드시 가장 마지막에 작성해야 한다.

Arrow Function

arrow function은 익명 함수를 좀 더 간결하게 표현할 수 있도록 ES2015에서 새롭게 등장한 함수 선언 방식이다. arrow function은 이름이 없는 익명함수이기 때문에 일반적으로 어떤 이름을 가진 변수에 할당하거나, 다른 함수의 아규먼트로 선언할 때 주로 활용된다.
아래 코드와 같이 표현식으로 함수를 정의할 때 활용될 수도 있고 콜백 함수로 전달할 때 활용할 수도 있다.

// 화살표 함수 정의
const getTwice = (number) => {
  return number * 2;
};

// 콜백 함수로 활용
myBtn.addEventListener('click', () => {
  console.log('button is clicked!');
});

화살표 함수는 기존의 function 함수를 조금 더 간결하게 표현하고자 등장했기 때문에 상황에 따라서는 훨씬 더 짧게 표현될 수도 있다.

// 1. 함수의 파라미터가 하나 뿐일 때
const getTwice = (number) => {return number * 2;};

// 파라미터를 감싸는 소괄호 생략 가능 (파라미터가 두개 이상이거나 없을 때는 반드시 소괄호를 작성)
const getTwice = number => {return number * 2;};

// 2. 함수 동작 부분이 return문만 있을 때
const sum = (a, b) => {return a + b;};

// return문과 중괄호 생략 가능 
// (하지만 함수 내부에서 조건문이나 반복문, 변수의 값을 할당하는 것과 같이 
// return문 외에 다른 표현들이 더 필요하다면 중괄호와 return 키워드는 생략할 수 없다.)
const sum = (a, b) => a + b;

// 3. 함수 내부 동작이 return문 하나뿐이어도 값이 객체인 경우는 주의해서 사용해야한다.
const getCode = () => {
  return {name: 'Ann', };
};

//중괄호와 return 키워드를 생략하게 되면 에러가 발생한다.
const getCode = () => {name: 'Ann', }; //Error

//객체라고 작성한 중괄호를 함수의 동작 부분을 구분하는 중괄호로 해석하기 때문이다. 이 땐 소괄호로 한번 더 감싸주면 해결된다.
const getCode = () => ({name: 'Ann', }); //{name: Ann}

그리고 Arrow function이 일반 함수와 몇 가지 차이점이 있는데 가장 대표적인 차이점은 arguments 객체가 없고, this가 가리키는 값이 일반 함수와 다르다는 것이다.

this

자바스크립트에는 this라는 조금 특별한 키워드가 있다. 웹 브라우저에서 this가 사용될 때는 전역 객체, Window 객체를 가지게 된다. 하지만 객체의 메소드를 정의하기 위한 함수 안에선 메소드를 호출한 객체를 가리킨다.

//이렇게 사용해도 잘 동작하지만 (물론 여기서 user을 this로 바꿔 사용해도 충분히 사용가능하다.)
const user = {
  firstName: 'Tess',
  lastName: 'Jang',
  getFullName: function () {
    return `${user.firstName} ${user.lastName}`;
  },
};

console.log(user.getFullName()); // Tess Jang

//이 메소드를 다른 객체에도 적용하고 싶어서 험수 외부로 분리하면 동작에 어려움이 있다.
function getFullName() {
  return `${user.firstName} ${user.lastName}`
};

const user = {
  firstName: 'Tess',
  lastName: 'Jang',
  getFullName: getFullName
};

const admin = {
  firstName: 'Alex',
  lastName: 'Kim',
  getFullName: getFullName
};

console.log(user.getFullName()); // Tess Jang
console.log(admin.getFullName()); // Tess Jang

//getFullName의 동작부분에서 user 객체만 바라보기 때문에 admin 객체에서 메소드를 호출하더라도 user 프로퍼티를 사용한다.

function getFullName() {
  return `${this.firstName} ${this.lastName}`
};

const user = {
  firstName: 'Tess',
  lastName: 'Jang',
  getFullName: getFullName
};

const admin = {
  firstName: 'Alex',
  lastName: 'Kim',
  getFullName: getFullName
};

console.log(user.getFullName()); // Tess Jang
console.log(admin.getFullName()); // Alex Kim

위 상황에선 this 키워드가 유용하게 사용될 수 있다. 자바스크립트에서 this는 함수를 호출한 객체를 가리키는 키워드인것이다. 그래서 코드를 작성할 때 값이 미리 결정되는게 아니라 함수가 호출될 때 어떤 객체가 그 함수를 호출했는지에 따라 상대적으로 값이 변하게 된다.

//일반 함수와 Arrow function은 this를 다루는 방식이 서로 다르다.

//화살표 함수에서 this 값은 일반 함수처럼 호출한 대상에 따라 상대적으로 변하는게 아니라
//화살표 함수가 실행되기 직전에 유효한 this 값과 똑같은 값을 가지고 동작한다.

console.log(this); //window객체가 호출된다.

const printThis = () => { //여기 화살표 함수가 선언되기 직전의 this는 윗줄에 window 객체이다.
  console.log(this);
};

const myObj = {
  cotent: 'myObj',
  printThis: printThis
};

const otherObj = {
  cotent: 'otherObj',
  printThis: printThis
};

myObj.printThis(); //window 객체
otherObj.printThis(); //window 객체, 그래서 코드를 실행했을 때 이런결과가 출력되는 것이다.

//이런 객체 특징때문에 객체에 메소드를 만들 때는 화살표 함수보다 일반 함수가 조금 더 권장된다.

'코린이 개념잡기 > JavaScript' 카테고리의 다른 글

Spread 구문  (0) 2024.12.16
조건부 연산자(삼항 연산자)  (0) 2024.12.16
null 병합 연산자 (??)  (0) 2024.12.15
AND와 OR 연산자 심화  (0) 2024.12.15
Falsy & Truthy  (1) 2024.12.15

물음표 두개(??)를 사용해서 null 혹은 undefined 값을 가려내는 연산자이다.

const example1 = null ?? 'I';
const example2 = undefined ?? 'love';
const example3 = 'Coding' ?? 'JavaScript';

console.log(example1, example2, example3); // ?

예시 1과 2를 보면 nill 병합 연산자 왼편에 각각 null과 undefined가 있다. 연산자 왼편의 값이 null이나 undefined라면 연산자 오른편의 값이 리턴되고, 예시 3처럼 연산자 왼편 값이 null이나 undefined 값이 아니라면 연산자 왼편 값이 리턴되는 동작 방식이다.

결과적으로 출력되는 값은 "I love Coding"

const example1 = null ?? 'I'; // I
const example2 = undefined ?? 'love'; // love
const example3 = 'Coding' ?? 'JavaScript'; //Coding

console.log(example1, example2, example3); // I love Coding

OR 연산자와 비슷해보이는데 실제로도 상황에 따라 똑같이 동작할 수 있다.

const title1 = null || 'love cat';
const title2 = null ?? 'love dog';

console.log(title1); // love cat
console.log(title2); // love dog

하지만 null 병합 연산자는 왼쪽의 값이 nill이나 undefined인지 확인하고 OR 연산자는 왼쪽의 값이 falsy인지 확인하기 때문에 null이나 undefined가 아닌 falsy값을 활용할 때 결과가 서로 다르다.

const title1 = false || 'Merry Christmas!';
const title2 = false ?? 'Santa';

console.log(title1); // Merry Christmas!
console.log(title2); // false

const width1 = 0 || 150;
const width2 = 0 ?? 150;

console.log(width1); // 150
console.log(width2); // 0

'코린이 개념잡기 > JavaScript' 카테고리의 다른 글

조건부 연산자(삼항 연산자)  (0) 2024.12.16
함수  (0) 2024.12.15
AND와 OR 연산자 심화  (0) 2024.12.15
Falsy & Truthy  (1) 2024.12.15
새로운 데이터 타입과 특징  (1) 2024.12.15
console.log('I love u' && 'React!');

위 코드를 실행하면 어떤 결과 값이 출력될까? 

I live u 와 React! 모두 문자열이기 때문에 Truthy한 값이라 true and true가 되서 콘솔에 true가 출력될것 같다.

//출력된 값
React!

하지만 실행해보면 "React!"가 출력된걸 볼 수 있다. 자바스크립트에서 논리연산자는 매번 true 혹은 false를 리턴하는게 아니라 상황에 따라 양쪽 값 중 어느 한쪽을 선택하는 방식으로 동작한다.

//익숙하게 본 boolean 형태로 AND 연산자를 생각해보자
console.log(true && true); //ture
console.log(true && false); //false
console.log(false && true); //flase
console.log(false && false); //flase

AND 연산자는 양쪽 값이 모두 true인 경우에만 true를 리턴하고 어느 한쪽이라도 false일 경우 false를 리턴한다.

하지만 사실 왼쪽 값이 truthy하면 오른쪽 값을 리턴하고, 왼쪽 값이 falsy 하면 그대로 왼쪽 값을 리턴하는 방식으로 동작한다. 그래서 위에서 작성했던 문자열로 작성한 연산자에서 "React!"를 출력한 것이다. 문자열 "I love u"가 truthy 하기 때문에 오른쪽에 있는 "React!"가 리턴 된 것이다.

그렇다면 OR 연산자는?

//OR 연산자 boolean 타입
console.log(true || true); //ture
console.log(true || false); //true
console.log(false || true); //true
console.log(false || false); //false

둘 중 하나라도 true일 경우 true를 리턴하고 양쪽 다 false일 경우에 false를 리턴했다. 그런데 OR 연산자도 둘 중 하나를 선택하는 관점에서 바라보면 AND연산자와 정반대로

왼쪽 값이 truthhy 하면 그대로 왼쪽 값을 리턴하고, 왼쪽 값이 falsy하면 오른쪽 값을 리턴하는 방식으로 동작한다.

예시를 가지고 연산을 더 공부해보자.

console.log(null && undefined);
console.log(0 || true);
console.log('0' && NaN);
console.log({} || 123);
  1. null과 undefined 둘 다 falsy 값으로 flase AND false. 왼쪽 값이 falsy 하면 그대로 왼쪽 값을 리턴하기 때문에 null이 출력될것이다.
  2. 0은 falsy값, true는 말 그대로 true. false OR true. 왼쪽값이 falsy하면 오른쪽 값을 리턴하니 true가 출력될 것이다.
  3. 0이라는 문자열 true, NaN은 falsy 값. true AND false. 왼쪽 값이 true기 때문에 오른쪽 값을 리턴해 NaN이 출력될 것이다.
  4. 빈 배열과 객체 또한 truthy. 그리고 숫자 123은 true. true OR true. 왼쪽값이 truthy하면 그대로 왼쪽값을 리턴하기 때문에 {빈 객체}가 출력될 것이다.
function print(value) {
  const message = value || "Code World!";
  
  console.log(message);
};

print(); //Code World!
print('JavaScript'); //JavaScript

함수를 호출할 때 아무런 값도 전달하지 않으면 파라미터에 undefined, flasy한 값이 전달된다는 특징을 이용해서 함수를 호출할 때 전달한 값이 없다면 "Code World!"를,  전달한 값이 있을 땐 그 값을 사용하게끔 조건식처럼 활용할 수 있다.


AND 연산자와 OR 연산자 우선순위

function checkAnswer(value) {
  if (value < 10 && value > 0 && value !== 3) {
    return '정답입니다!';
  }
  return '틀렸습니다!';
};

console.log(checkAnswer(4)); // 정답입니다!

10보다는 작고, 0보다는 크지만 3은 아닐때 정답입니다를 리턴하고, 아니라면 틀렸습니다를 리턴하는 함수이다.

코드를 작성하다보면 다양한 상황을 고려하기 위해 이렇게 AND나 OR 연산자를 여러번 사용해야 할 수도 있다.

AND 연산자나 OR 연산자 중 하나만 계속해서 사용할 때는 문제 없지만, 만약 AND 연산자와 OR 연산자를 섞어서 사용할 때는 연산의 우선순위가 존재한다.

쉽게 설명해서 1 + 2 + 3 처럼 계속해서 더하기 연산자만 사용한다면 왼쪽부터 차례대로 더하면 되지만, 1 + 2 * 3 처럼 더하기와 곱하기 연산자가 섞여 있다면 연산자 우선순위를 고려해야 한다. AND 와 OR 연산자 사이에서는 AND 연산자의 우선순위가 더 높다.

console.log(true || false && false); // true
console.log((true || false) && false); // false

console.log('Coding' || NaN && false); // Coding
console.log(('Coding' || NaN) && false); // false

'코린이 개념잡기 > JavaScript' 카테고리의 다른 글

함수  (0) 2024.12.15
null 병합 연산자 (??)  (0) 2024.12.15
Falsy & Truthy  (1) 2024.12.15
새로운 데이터 타입과 특징  (1) 2024.12.15
이벤트 자세히 다뤄보기  (1) 2024.12.15

+ Recent posts