Javascript, 함수의 기초 2

[10] 변수의 유효 범위

1. 전역 유효 범위와 지역 유효 범위

유효범위(scope)
변수에 접근할 수 있는 범위를 그 변수의 유효 범위라 함.
유효 범위를 결정하는 2가지 방법
🔹어휘적 범위(lexical scope) – 프로그램의 구문 만으로 유효 범위를 정하는 방법
🔹동적 범위(dynamic scope) – 프로그램 실행 중에 유효 범위를 정하는 방법

자바스크립트에서는 어휘적 범위를 채택하고 있다.

변수의 유효 범위에 따라 전역 변수지역 변수로 나뉜다.

  • 전역 변수 : 함수 밖에서 선언된 변수로 유효 범위가 전체 프로그램
  • 지역 변수 : 함수 안에서 선언된 변수와 함수 인자로 유효 범위는 선언된 함수 내부
var a = "global";
function f() {
    var b = "local";
    console.log(a);    // → global
    return b;
}
f();
console.log(b);    // → ReferenceError: b is not defined

// 이 코드는 '모던 자바스크립트 입문(徹底マス夕一JavaScriptの敎科書)'에서 인용한 것입니다.
// [ISBN #978-4797388640]. Copyright 2017 by 磯博

변수 a는 전역 변수 – 유효 범위가 전체 프로그램이므로 함수 f  내부에서도 유효

변수 b는 지역 함수 – 함수 f 안에서만 유효한 함수. 함수 f 밖에서는 참고 오류가 발생

2. 변수의 충돌

변수에 유효 범위가 존재하는 이유는 프로그램의 다른 부분에서 선언된 이름이 같은 변수와 충돌하지 않도록 하기 위해서이다.

지역 변수의 경우 모두 선언된 함수 내부에서만 유효하므로 이름이 같아도 충돌을 일으키지 않는다. 하지만 전역 변수 이름과 지역 변수 이름이 같아지면 두 변수가 충돌한다.

전역 변수 이름과 지역 변수 이름이 같아지면, 이때는 전역 변수를 숨기고 지역 변수를 사용하게 된다.

var a = "global";
function f() {
    var a = "local";
    console.log(a);    // → local
    return a;
}
f();
console.log(a);    // → global

// 이 코드는 '모던 자바스크립트 입문(徹底マス夕一JavaScriptの敎科書)'에서 인용한 것입니다.
// [ISBN #978-4797388640]. Copyright 2017 by 磯博

위 코드에서 지역 변수 a의 유효 범위 안에서 전역 변수 a는 숨겨진다.

3. 함수 안에서의 변수 선언과 변수 끌어올림

함수 안에서 선언된 지역 변수의 유효 범위는 함수 전체.

함수 중간 부분에서 변수를 선언하더라도 변수는 함수 첫머리에서 선언된 것처럼 함수 안의 다른 문장보다 먼저 생성된다. 즉, 자바스크립트 엔진은 함수 안의 변수 선언부를 함수의 첫머리로 끌어올린다.

function f() {
    console.log(a);    // → undefined
    var a = "local";
    console.log(a);    // → local
    return a;
}

// 이 코드는 '모던 자바스크립트 입문(徹底マス夕一JavaScriptの敎科書)'에서 인용한 것입니다.
// [ISBN #978-4797388640]. Copyright 2017 by 磯博

4. 함수 안에서의 변수 선언 생략

변수를 선언하지 않은 상태에서 값을 대입하면 전역 변수로 선언이 됨.

이 현상은 함수 안밖에서 모두 발생. 그러므로 프로그램 어느 위치에서도 사용 가능

function f() {
    a = "local";
    console.log(a);    // → local
    return a;
}
f();
console.log(a);    // → local

// 이 코드는 '모던 자바스크립트 입문(徹底マス夕一JavaScriptの敎科書)'에서 인용한 것입니다.
// [ISBN #978-4797388640]. Copyright 2017 by 磯博

[11] 블록 유효 범위 : let과 const

let, const는 ECMAScript 6부터 추가된 변수 선언자로 모두가 ‘블록 유효 범위‘를 갖는 변수를 선언

블록 유효 범위를 가진 변수는 { } 안에서만 유효

let은 변수 선언, const는 한 번만 할당할 수 있는 상수를 선언

1. let 선언자

블록 유효 범위를 갖는 지역 변수를 선언

사용법은 var와 같다.

let x;
let a, b, c;
let x = 5, y = 7;
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

// 이 코드는 '모던 자바스크립트 입문(徹底マス夕一JavaScriptの敎科書)'에서 인용한 것입니다.
// [ISBN #978-4797388640]. Copyright 2017 by 磯博

{ } 밖에 있는 변수 x의 유효 범위는 전체 프로그램이 되지만, { } 안에 있는 변수 x는 ( { } 밖에 있는 변수 x와 이름은 같지만 ) 중괄호 안에서만 유효하다. 또한 변수 y도 { } 안에서만 유효하다. 그래서 변수 y는 { } 밖에서 읽으려고 시도하면 참조 오류가 발생한다.

※ var 문과 달리 let 문으로 선언한 변수는 끌어올리지 않는다.

console.log(x);    // → ReferenceError: x is not defined
let x = 5;

let 문으로 똑같은 변수를 선언하면 문법 오류가 발생한다.

let x;
let x;    // → Uncaught SyntaxError

2. const 선언자

블록 유효 범위를 가지면서 한 번만 할당할 수 있는 변수(상수)를 선언

const로 선언한 상수는 let 문으로 선언한 변수처럼 동작. 단, 반드시 초기화해야 한다는 차이점이 있다.

const c = 2;
c = 5;    // → Uncaught TypeError

const 문으로 선언한 변수에 다시 대입을 시도하면 타입 오류가 발생한다. const 문으로 선언한 상수 값은 수정할 수 없지만, 상수 값이 객체이거나 배열일 경우에는 프로퍼티 또는 프로퍼티 값을 수정할 수 있다.

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

[12] 함수 리터럴로 함수 정의하기

함수는 함수 리터럴로도 정의할 수 있다.

function square(x) { return x * x; }

이 square 함수를 함수 리터럴로 수정할 수 있다.

var square = function(x) { return x * x; };

이 코드에서 function(x) { …} 부분 → 함수 리터럴

함수 리터럴 ➡️ 이름 없는 함수 : 익명 함수 or 무명 함수

함수 리터럴로 정의한 익명 함수는 변수에 할당한 후에야 비로소 square 라는 이름을 갖게 되고, 그 이름으로 호출할 수 있다. 그렇기 때문에 함수를 정의하지 않은 상태에서 함수를 사용하려고 하면 타입 오류가 발생한다.

🔸작성 시 주의점 : 함수 선언문에서는 끝에 세미콜론(;)을 붙일 필요가 없지만, 함수 리터럴을 사용할 때는 끝에 반드시 세미콜론을 붙여야 한다.

🔸사용법 : 함수와 같다. 실행 시 square(5)와 같이 작성하면 된다. 이는 함수 리터럴과 함수 선언문 모두 내부적으로 square 변수에 함수 객체의 참조를 저장하기 때문이다.

🔸차이점 : 자바스크립트 엔진이 함수 선언문으로 정의한 함수는 끌어올리지만 함수 리터럴로 정의한 함수는 끌어올리지 않는다.

console.log(square(3));    // → TypeError: square is not a function
var square = function(x) { return x * x; };

익명 함수에도 이름을 붙일 수 있다.

var square = function sq(x) { return x * x; };

그러나 코드에서 sq라는 이름은 함수 안에서만 유효하므로 함수 바깥에서는 sq라는 이름으로 함수를 호출할 수 없다.

익명 함수 코드는 디버거에 모두 anonymous function 이라고 표시되므로 함수를 구별할 없는 단점이 있다. 단, 이름이 붙은 익명 함수는 어떤 함수인지 확인할 수 있다.

[13] 객체의 메서드

메서드 : 객체의 프로퍼티 중에서 함수 객체의 참조를 값으로 담고 있는 프로퍼티를 말함. 메서드를 정의할 때 프로퍼티 값으로 함수 리터럴을 대입한다.

var circle = {
    center: { x:1.0, y:2.0 },    // 원의 중점을 표현하는 객체
    radius: 2.5,                 // 원의 반지름
    area: function() {           // 원의 넓이를 구하는 메서드
            return Math.PI * this.radius * this radius;
          }
};

// 이 코드는 '모던 자바스크립트 입문(徹底マス夕一JavaScriptの敎科書)'에서 인용한 것입니다.
// [ISBN #978-4797388640]. Copyright 2017 by 磯博

area는 메서드

함수 객체 안에 적힌 this는 그 함수를 메서드로 가지고 있는 객체를 가리킨다. 위 코드에서는 circle을 가리킨다. 즉, this.radius가 circle.radius 이다.

메서드는 일반 함수와 마찬가지로 ()를 붙여 실행한다.

circle.area()    // → 19.634954084936208

메서드 또한 프로퍼티의 일종이므로 나중에 추가할 수 있다.

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}

이 예에서 알 수 있듯이 메서드는 일반적으로 메서드가 속한 객체의 내부 데이터(프로퍼티 값) 상태를 바꾸는 용도로 사용한다.

일반적인 객체 지향 언어에서는 데이터와 그 상태를 바꾸는 메서드를 하나로 묶는 용도로 객체를 사용한다. → 객체를 기본 부품으로 삼아 프로그램을 만드는 것을 “객체 지향 프로그래밍“이라고 한다.

[14] 함수를 활용하면 얻을 수 있는 장점

  • 재사용할 수 있다. – 같은 작업을 반복할 때 함수 하나로 만들어 두면, 함수 호출만으로 같은 작업을 여러 번 반복할 수 있다. 또한 코드도 간결해진다.
  • 만든 프로그램을 이해하기 쉽다. – 함수를 사용하면 일정한 처리를 모아서 이름을 붙일 수 있다. 이는 함수 안의 상세한 내용을 숨기고 프로그램의 큰 흐름을 쉽게 파악할 수 있게 해 준다.
  • 프로그램 수정이 간단해진다. – 함수를 사용하지 않으면 똑같은 처리를 프로그램 곳곳에서 작성해야 하지만, 함수로 정리해 두면 해당 함수만 수정하면 되므로 수정이 간단해진다.

< 참고문헌 >
🔹주 참고문헌 : 모던 자바스크립트 입문 – 이소 히로시 지음, 서재원 옮김
🔹MDN Web Docs

댓글 달기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다


error: 컨텐츠가 보호되고 있습니다.
위로 스크롤