#4 함수 / 스코프 / 전역 변수의 문제점

JIY00N·2023년 2월 16일
0

HTML / CSS / JavaScript

목록 보기
6/18
post-thumbnail

2023.02.16

1. 함수

✔ 일련의 과정을 문으로 구현하고 코드 블록으로 감싸서 하나의 실행 단위로 정의한 것
✔ 함수 이름을 호출X -> 함수 객체를 가리키는 식별자 호출O
✔ 일급 객체이다 = 함수를 값처럼 자유롭게 사용할 수 있다.
✔ 함수 호스트잉 = 함수 선언문이 코드의 선두로 끌어 올려진 것처럼 동작하는 자바스크립트 고유의 특징

1-1 함수정의

1. 함수 선언문

function add(x,y){
  return x+y;
}

✔ 함수 이름 생략 불가
✔ 표현식이 아닌 문
✔ 함수 리터럴을 단독으로 사용 -> 함수 선언문

// 기명 함수 리터럴을 단독 사용 -> 함수 선언문
function foo() { console.log('foo');} 
foo(); // foo
// 함수 리터럴을 피연산자로 사용 -> 함수 리터럴 표현식
(function bar() { console.log('bar');});
bar(); // ReferenceError: bar is not defined

2. 함수 표현식

// var add(식별자) = function add(함수이름)(x,y)
var add = function add(x,y){
  return x+y;
};
console.log(add(2,5)); //7
//console.log(add(식별자)(2,5))

✔ 변수에 할당되는 값이 함수 리터럴인 문
✔ 함수 이름 생략 = 익명함수
✔ 표현식인 문
✔ 함수 호스트잉 X -> 변수 호스트잉 O
✔ 반드시 함수 표현식 이후에 참조 또는 호출
✔ 함수 선언문 보다 함수 표현식 권장

3. Function 생성자 함수

var add = new Function('x','y','return x+y');
console.log(add(2,5)); //7

✔ Function 생성자 함수에 매개변수 목록과 함수 몸체를 문자열로 전달하면서 new 연산자와 함께 호출하면 함수 객체를 생성해서 반환

4. 화살표 함수(ES6)

var add = (x,y) => x+y;
console.log(add(2,5)); //7
}

✔ function 키워드 대신 화살표 사용
✔ 항상 익명 함수로 정의

1-2 다양한 함수의 형태

  1. 즉시 실행 함수(IIFE) - 함수 정의와 동시에 즉시 호출되는 함수
    ✔ 단 한번만 호출
    ✔ 익명 함수
    ✔ 그룹연산자() 로 감싸기
(function(){ //주로 사용
  //...
}());

(function(){
  //...
})();

!function(){
  //...
}();

+function(){
  //...
}();
  1. 재귀 함수(recursive call) - 함수가 자기 자신을 호출
    ✔ 탈출 조건 필수
var factorial = function foo(n){
  if(n<=1)
    return 1;
  return n * factorial(n-1);
};
console.log(factorial(5)); 120
  1. 중첩 함수(nested function) - 함수 내부에 정의된 함수
    ✔ if, for문에서 정의 할 수 있지만 함수 선언문을 통해 정의X
function outer(){
  var x = 1
  //중첩 함수
  function inner(){
    var y = 2;
    //외부 함수의 변수를 참조 할 수 있음
    console.log(x+y); //3
  }
  inner();
}
outer();
  1. 콜백 함수 - 어떤 일을 반복 수행
    ✔ 함수의 매개변수를 통해 다른 함수의 내부로 전달되는 함수
    ✔ 고차 함수 - 매개변수를 통해 함수의 외부에서 콜백 함수를 전달받은 함수
function repeat(n){
  for(var i = 0; i<n; i++)
    console.log(i);
}
repeat(5); // 0 1 2 3 4
  1. 순수 함수와 비순수 함수
    ✔ 순수 함수 - 외부 상태에 의존하지도 않고 변경하지도 않는, 부수 효과가 없는 함수(최소 하나 이상의 인수)
    ✔ 비순수 함수 - 부수 효과가 있는 함수
//순수 함수
var count = 0; //현재 count를 나타내는 상태
// increase는 동일한 인수가 전달되면 언제나 동일한 값 반환
function increase(n){
  return ++n;
}
// 순수 함수가 반환한 결과값을 변수에 재할당해서 상태 변경
count = increase(count);
console.log(count); //1
count = increase(count);
console.log(count); //2

//비순수 함수
var count = 0; //increase 함수에 의해 변화
// 외부 상태에 의존하여 외부 상태를 변경
function increase(){
  return ++count;
}
// 외부 상태(count)를 변경하므로 상태 변화를 추적하기 어려움
increase();
console.log(count); //1
increase();
console.log(count); //2

2. 스코프

✔ 식별자가 유효한 범위
✔ 식별자를 검색하는 규칙

2-1 스코프의 종류

  1. 전역 - 코드의 가장 바깥 영역 / 전역 스코프 / 전역 변수
    ✔ 전역 변수는 어디서든지 참조 가능

  2. 지역 - 함수 몸체 내부 / 지역 스코프 / 지역 변수
    ✔ 지역 변수는 자신의 지역 스코프와 하위 지역 스코프에서 유효

2-2 스코프 체인

✔ 스코프가 계층적으로 연결된 것
✔ 스코프가 함수의 중첩에 의해 계층적 구조를 가짐
✔ 변수를 참조할 때 자바스크립트 엔진은 스코프 체인을 통해 코드의 스코프 -> 상위 스코프으로 이동하며 선언된 변수를 검색

2-3 함수 레벨 스코프

✔ 함수 레벨 스코프 - var 키워드로 선언된 변수는 오로지 함수의 코드 블록(함수 몸체)만을 지역 스코프로 인정

var i =10;
//for 문에서 선언한 i는 전역 변수이다. 이미 선언된 전역 변수 i가 있으므로 중복 선언
for(var i = 0; i<5; i++){
  console.log(i); // 0 1 2 3 4
}

console.log(i); //5, i의 값이 변경됨

2-4 렉시컬 스코프(정적 스코프)

자바스크립트는 렉시컬 스코프이다.

✔ 동적 스코프 - 함수를 어디서 호출했는지에 따라 함수의 상위 스코프 결정
✔ 렉시컬 스코프(정적 스코프) - 함수를 어디서 정의했는지에 따라 함수의 상위 스코프 결정, 함수의 상위 스코프는 언제나 자신이 정의된 스코프

var x = 1;
function foo(){
  var x = 10;
  bar();
}
//전역에서 정의 -> 자신이 기억하고 있는 전역스코프를 상위 스코프로 사용
function bar(){ 
  console.log(x);
}
foo(); //1
bar(); //1

3. 전역 변수의 문제점

3-1 변수의 생명 주기

  1. 지역 변수의 생명 주기 = 함수의 생명 주기

  2. 전역 변수의 생명 주기 = 더 이상 실행할 문이 없을 때 종료
    ✔ var 키워드로 선언한 전역 변수 생명 주기
    = 전역 객체의 생명 주기 = 웹 페이지를 닫을 때까지 유효

3-2 전역 변수의 문제점

  1. 암묵적 결합 - 모든 코드가 전역 변수를 참조하고 변경
    -> 코드의 가독성이 나빠지고 의도치 않게 변경될 수 있음

  2. 긴 생명 주기 -> 메모리 리소스도 오래 기간 소비

  3. 스코프 체인 상에서 종점에 존재 - 전역 변수의 검색 속도가 가장 느림
    -> 변수를 검색할 때 전역 변수가 가장 마지막에 검색 됨

  4. 네임스페이스 오염 - 파일이 분리되어 있어도 전역 스코프를 공유함

3-3 전역 변수의 사용을 억제하는 방법

변수의 스코프는 좁을수록 좋다 -> 지역 변수 사용

  1. 즉시 실행 함수 - 모든 코드를 즉시 실행 함수로 감싸면 모든 변수는 즉시 실행 함수의 지역 변수가 됨 -> 라이브러리에 많이 사용
(function(){
  var foo = 10; // 즉시 실행 함수의 지역 변수
  //...
}());
console.log(foo); // ReferenceError
  1. 네임스페이스 객체(유용성 떨어짐)
var MYAPP={}; // 전역 네임스페이스 객체
MYAPP.person={
  name: 'Lee';
  address: 'Seoul';
};
console.log(MYAPP.person.name); //Lee
  1. 모듈 패턴
    ✔ 클로저 기반으로 동작
    ✔ 클래스를 모방해서 관련이 있는 변수와 함수를 모아 즉시 실행 함수로 감싸 하나의 모듈을 만듬
var Counter = (function(){
  //private 변수
  var num = 0;
  //외부로 공개할 데이터나 메서드를 프로퍼티로 추가한 객체 반환
  return{
    increase(){
      return ++num;
    },
    decrease(){
      return --num; 
    }
  };
}());

console.log(Counter.num); //undefined : private변수는 외부로 노출 x
console.log(Counter.increase()); //1
console.log(Counter.increase()); //2
console.log(Counter.decrease()); //1
  1. ES6 모듈
    ✔ ES6 모듈은 파일 자체의 독자적인 모듈 스코프를 제공
    ✔ 전역 변수 사용 불가
    ✔ script 태그에 type="module"
    ✔ 확장자 = .mjs
<script type="module" src="lib.mjs"></script>
<script type="module" src="app.mjs"></script>
profile
블로그 이전 했습니다. https://yoon-log.vercel.app/

0개의 댓글