모던 자바스크립트 (2)

kirin.log·2021년 2월 27일
1

📚 함수의 기초

🐟 함수

  • 일련의 처리를 하나로 모아 언제든 호출할 수 있도록 만들어 둔 것
  • 입력 값을 받으면 출력 값(return)으로 함수 값을 반환
  • 함수의 입력 값 : 인수, 함수의 출력 값 : 반환값, 함수 정의문의 인수 : 인자(parameter)

🐟 함수 hoisting

  • 변수 선언문과 동일하게 함수 선언문을 프로그램의 첫머리로 끌어올림
  • 함수 선언은 프로그램의 어떤 위치에도 작성 가능
// ex)
console.log(square(5)); // 25
function square(x) { return x * x ; };
// 정상 동작

🐟 값으로서의 함수

  • 함수가 객체
  • 함수 선언문(function "함수이름" (인자) { }; )으로 함수를 선언할때, 내부적으로 그 함수 이름을 변수 값으로 한 변수와 함수 객체가 생성
  • 해당 변수에 함수 객체의 참조가 저장
  • 해당 변수 값을 다른 변수에 할당시 그 변수 이름으로 함수 실행 가능
// ex)
let sq = square;
console.log(sq(5)); // 25

🐟 참조에 의한 호출 vs 에 의한 호출

  • 원시 값(primitive value)을 인수로 넘길때와, 객체를 인수로 넘길때 다르게 동작 ✨

🐙 원시값이 인수일 경우

// ex)
function add(x) { 
  return x = x+1; 
}

let a = 3;
let b = add(a);

console.log("a = " + a + ", b = " + b ); 
// a = 3, b = 4

👉 함수가 호출될 때 변수 a의 복사본이 인자 x에 할당 ➡ 값 자체가 인자에 전달 (값의 전달)
👉 변수 a와 x는 다른 영역의 메모리에 위치한 별개의 변수

🐙 인수가 객체일 경우

// ex)
function add(p) { 
  p.x = p.x + 1; 
  p.y = p.y + 1; 
  return p; 
}
let a = { x:3, y:4 };
let b = add(a);

console.log(a, b); 
// Object {x=4, y=5} Object {x=4, y=5}

👉 함수 호출시 변수 a의 복사본이 인자 p에 할당
👉 이전과 다른건 변수 a 에 객체의 참조가 저장되어 있으며, 이 참조 값을 인자 p에 대입하는것. ➡ 인수를 객체로 넘길 때 전달 되는 값은 참조값 (참조 전달)
👉 인자 p와 변수 a는 똑같은 객체를 참조
👉 함수 안에서 p.x와 p.y를 수정하는 행위는 a.x와 a.y를 수정하는 행위와 같음 ➡ 함수 안에서 원래의 객체 변경 가능

❗ 함수에 넘겨야 하는 인수 개수가 많아질때의 문제
1) 인수의 순서를 착각할 수 있음
2) 함수가 받는 인수 개수를 바꿀때 함수의 호출 방법이 바뀌므로 프로그램 전체를 수정해야함

//ex)
function setBallProperties(x, y, vx, vy, radius) { 
  ... 
}
setBallProperties(0, 0, 10, 15, 5);

❗ 이를 해결하기 위해서는?
인수를 객체 프로퍼티에 담는다

var parameters = {
    x: 0,
    y: 0,
    vx: 10,
    vy: 15,
    radius: 5
}

❗ 함수의 인수를 하나만 받도록 변경 가능

function setBallProperties(params) { 
  ...  
}

setBallProperties(parameters);

👉 함수 안에서 프로퍼티를 읽는 코드는 params.vx 등으로 표현 가능하므로 인수 순서를 고려하지 않아도 됨
👉 인수 추가시에도 프로퍼티만 추가하면 되므로 함수 호출 방식은 동일함을 유지할 수 있음

var parameters = {
    x: 0,
    y: 0,
    vx: 10,
    vy: 15,
    radius: 5,
    color: "blue"
}
setBallProperties(parameters);

❗ 주의사항: 함수 안에서 객체의 프로퍼티를 수정할 경우, 객체의 참조가 전달된 상태 이므로, 호출한 코드에 있는 인수 객체의 프로퍼티가 함께 바뀜


🐟 변수 유효범위

🐠 전역 유효 범위지역 유효 범위

  • 유효 범위(Scope): 변수에 접근할 수 있는 범위
  • 유효 범위의 결정 방법 두가지
    1) 어휘적 범위(lexical scope) - 프로그램 구문만으로 유효 범위 정함
    2) 동적 범위(dynamic scope) - 프로그램 실행 중에 유효 범위 정함
    ❗ C, Java등의 언어와 마찬가지로 자바스크립트도 어휘적 범위를 채택
  • 자바스크립트의 변수는 유효 범위에 따라 '전역 변수''지역 변수' 로 구분
    1) 전역 변수 : 함수 바깥에서 선언된 변수, 유효 범위가 전체 프로그램
    2) 지역 변수 : 함수 에서 선언된 변수와 함수 인자로서, 유효 범위는 변수가 선언된 함수 내부

🐠 변수의 충돌

  • 유효범위가 있는 이유
    ➡ 프로그램의 다른 부분에서 선언된 동명의 변수와 충돌하지 않도록 하기 위함
  • 전역 변수와 지역 변수가 동명일 경우
    ➡ 두 변수가 충돌하며, 이때는 전역 변수가 숨겨지고 지역 변수를 사용
// ex)
let a = "global";

function f() {
    var a = "local";
    console.log(a);  // local

    return a;
}
f();

console.log(a); // global

🐠 함수 안에서의 변수 선언변수 끌어올림

  • 함수 안에서 선언된 지역 변수의 유효범위 : 함수전체
  • 중간 부분에서 변수를 선언 하더라도 함수 첫머리에서 선언된 효과
// ex)
function f() {
    console.log(a); // undefined

    let a = "local";
    console.log(a); // local

    return a;
}

🐠 함수 안에서의 변수 선언 생략

  • 변수를 선언하지 않고 값을 대입시 전역 변수로 선언
  • 함수 바깥에서 발생하지만 함수 안에서도 발생
// ex)
function f() {
    a = "local";
    console.log(a); // local
    return a;
}
f();
console.log(a); // local
// 언뜻 a는 함수 f의 지역 변수처럼 보이지만, var로 선언하지 않았으므로 실제로는 전역 변수

🐟 블록 유효 범위 : letconst

  • ECMAScript 6 부터 추가된 변수 선언자
  • 모두가 블록 유효 범위 를 갖는 변수를 선언
  • 블록 유효 범위를 가진 변수는 중괄호({}) 안에서만 유효
  • let은 변수를 선언하고, const는 한 번만 할당할 수 있는 상수 선언

🐸 let 선언자

  • 블록 유효 범위를 갖는 지역 변수 선언
let x;
  • 변수가 여러 개일 때는 쉼표로 구분해 동시 선언
let a, b, c;
  • 변수를 선언하면서 초깃값 설정 가능
let x = 5, y = 7;

// ex) let으로 선언한 변수의 유효 범위
let x = "outer x";
{
    let x = "inner x";
    let y = "inner y";
    console.log(x); // inner x
    console.log(y); // inner y
}
console.log(x); // outer x
console.log(y); // ReferenceError : y is not defined

// 중괄호 바깥의 변수 x의 유효범위 : 전체 프로그램
// 안에 있는 변수 x의 유효 범위 : 중괄호 안쪽
// y의 유효 범위는 중괄호 안이므로 y를 함수 밖에서 읽으려고 시도하면 참조오류 발생
  • 자바스크립트는 var과 달리 let문으로 선언한 변수는 끌어올리지 않음 (hoisting❌)
ex)
console.log(x); // ReferenceError: x is not defined
let x = 5;
  • let 문으로는 똑같은 이름 변수 선언 불가
// ex)
let x;
let x; // Uncaught SyntaxError

🐸 const 선언자

  • 블록 유효 범위를 가지면서 한 번만 할당 가능한 변수(상수) 선언
  • let문으로 선언한 변수처럼 동작, 단, 반드시 초기화 해야함
// ex)
const c = 2;
c = 5;    // Uncaught TypeError
  • 상수값이 객체이거나 배열일 경우에는 프로퍼티 또는 프로퍼티 값을 수정 가능
// ex)
const origin = { x:1, y:2 };
origin.x = 3;

console.log(origin); // Object { x:3, y:2}

🐟 함수 리터럴로 함수 정의하기

  • 함수는 함수 리터럴로도 정의 가능 (= 함수 표현문)
ex) let square = function(x) { 
                    return x * x; 
                 };
  • 함수 리터럴은 이름이 없는 함수이므로 익명함수 또는 무명함수
  • 함수 선언문과 달리 함수 리터럴을 사용할 때는 끝에 반드시 세미콜론을 붙여줍니다.
  • 함수 선언문과 달리 함수 리터럴로 정의한 함수는 끌어올려지지 않습니다.
ex)
console.log(square(3)); // TypeError : square is not a function
let square = function(x) { 
               return x * x 
             };
  • 익명 함수에도 이름을 붙일 수 있음
// ex) 
let square = function sq(x) { 
               return x * x 
            };

// 코드에서 sq라는 이름은 함수 안에서만 유효하므로, 함수 바깥에서는 sq라는 이름으로 함수 호출이 불가

// 익명 함수 코드는 모두 anonymous function이라고 표시되므로 함수를 구별할 수 없으나, 
// 이름이 붙은 익명 함수는 어떤 함수인지 확인은 가능

🐟 객체의 메서드

  • 객체의 프로퍼티 중 함수 객체의 참조를 값으로 담고 있는 프로퍼티
  • 정의는 프로퍼티 값으로 함수 리터럴을 대입
ex)
var circle = {
      // 원의 중점 표현 객체
      center : { 
               x:1.0, 
               y:2.0 
                    }, 

      // 원의 반지름         
      radius : 2.5,

      // 원의 넓이를 구하는 메서드
      area: function () {    
          return Math.PI * this.radius * this.radius;
      }
}
circle.area() // 19.634954084936208
  • 메서드 또한 프로퍼티의 일종이므로 나중에 추가 가능
// ex)
circle.translate = function(a, b) {
    this.center.x = this.center.x + a;
    this.center.y = this.center.y + b;
};
circle.translate(1, 2);
circle.center; // Object {x=2, y=4}
  • 메서드는 일반적으로 메서드가 속한 객체의 내부 데이터(프로퍼티 값) 상태를 바꾸는 용도로 사용
  • 일반적 객체 지향 언어에서는, 데이터와 그 상태를 바꾸는 메서드를 하나로 묶는 용도로 객체를 사용.
    ➡ 이것이 바로 객체지향 프로그래밍이다

🚀 함수를 활용하면 얻을 수 있는 장점

[1] 재사용 가능

  • 반복 작업을 하나로 모아 호출만으로 같은 작업 반복 가능
  • 프로그램이 간결해짐

[2] 만든 프로그램을 이해하기 쉬움

  • 일정한 처리를 모아 이름을 붙일 수 있음
  • 함수 안에 상세한 내용을 숨기는 효과와 함께 프로그램을 읽을 경우 큰 흐름에 대한 쉬운 파악이 가능

[3] 프로그램 수정이 간단

  • 함수 미사용시 같은 처리를 프로그램 곳곳에 작성해야함(수정시에도 각각 모두 수정해야함)
  • 함수로 정리할 경우 해당 함수만 수정하면 되므로 수정이 간단해짐
profile
boma91@gmail.com

0개의 댓글