본문 바로가기
Javascript

함수 정리

by v8rus 2022. 11. 29.

함수 호출 방식

내부 변수 ( 블록 스코프 )
외부 변수 ( 함수 외부의 변수 접근 및 수정 가능 )

this가 바인딩 되는 객체는 동적으로 결정됨 ( 호출 방식에 따라 다름 )

 

1. 함수 호출

함수를 호출하면 prototype 을 가지게 됨 (기본값)
글로벌 영역에 선언된 함수는 전역 객체의 값에 접근 가능
내부 함수도  this가 global, window 를 가리킴

 

기명함수 (함수 선언문)  

function doSomething() {
	// do Something...
}

  호이스팅 O
    선언 이전에 호출 가능
  arguments : O
  this : global / window 객체
    this가 특정 객체를 가리키기 위한 방법 : this를 다른 변수에 담아 사용

 

함수 내부에서 자신 호출 가능

let sayHi = function(who) {
  if (who) {
    alert(`Hello, ${who}`);
  } else {
    sayHi("Guest"); // TypeError: sayHi is not a function
  }
};

let welcome = sayHi;
sayHi = null;

welcome(); 		// 중첩 sayHi 호출은 더 이상 불가능합니다!

  익명함수로 함수 작성시 외부에서 변경 가능

 

let sayHi = function func(who) {
  if (who) {
    alert(`Hello, ${who}`);
  } else {
    func("Guest");	 // 정상적인 값 출력
  }
};

let welcome = sayHi;
sayHi = null;

welcome(); 		// Hello, Guest (중첩 호출 동작)

    외부에서 값을 변경하더라도 정상적으로 동작

 

 


익명함수 (함수 표현식) 

let doSomething = function () {
	// do something...
}


  호이스팅 X
    실행 흐름이 도달했을 때 함수가 생성됨
      굳이, if 문 안에서 함수 작성하고 싶을때 사용
  arguments : O
  this : global / window 객체

  일회성 함수 사용을 위함    [콜백 함수(-함수를 함수의 인자로전달, 인수로 전달한 함수를 나중에 호출) 작성]
  중첩된 함수에서 클로저가 생성되면 즉시 실행함수로 대체하거나, 사용 후 객체에 null을 할당하여 가비지 컬렉터가 삭제

 

화살표 함수 (익명함수)

  호이스팅 : X
  this : X (존재하지 않기에 항상 상위 스코프의 this를 가리킴 - lexical scope)
    apply, bind, call 메서드로 this 값을 변경할 수 없다
  super : X
  arguments : X
  arguments에 접근하면 파라미터값을 써버림...

const arugments = [1,2,3];

function foo (n) {
	const f = () => arguments[0] + n // arguments[0] == n
    
	return f();
};

foo(4); // 4 + 4 = 8

데코레이터를 만들때 유용함 arguments 사용하고 싶으면 ...args 추천

let add = (...args) => {
	let total = 0;
	
    for (let i = 0; i < args.length; i++) {
	    total += args[i];
	}

	return total
};


  제너레이터로 사용 불가
  우선순위가 낮아 ... || () => {... } 해석 불가능

  멀리 떨어진곳의 실행될 함수를 작성할 경우 사용 (함수를 전달하기에 적당함, 다만 컨텍스트를 잃기에 화살표 함수로 컨텍스트 유지)
  자체 컨텍스트가 없는 짧은 코드를 담을 용도로 만듦
  생성자로 사용 불가
  addEventLinstener 함수의 콜백으로 사용하지 말것 (this === window)

 

 

2. 메서드 호출

this : 메소드를 소유한 인스턴스 가리킴 (foo.someFunction( this..... )에서의 this 는 foo)
객체 리터럴로 생성된 객체에서 alpha : funciton() { this... }의 this 는 생성된 객체를 가리킴
Prototype 객체에 할당된 메서드 또한 호출한 인스턴스에 바인딩됨

화살표 함수 사용 불가
마찬가지로 prototype에 메서드로 화살표 함수 사용 불가

 

 

3. 생성자 호출

new 로 함수를 인스턴스화 함
혼란을 방지하고자 첫 문자는 대문자로 기술
constructor 메소드는 클래스의 인스턴스 객체를 생성하고 초기화하는 메서드임

 

this는 인스턴스에 할당된 값들을 가리킴
  1. 빈 객체 생성 및 this 바인딩 (생성자 함수 내에서 사용되는 this가 빈 객체를 가리킴)
  2. this 를 통한 프로퍼티 생성
  3. 생성된 객체 반환
    의 순서대로 생성자 함수가 동작함

객체 리터럴 방식과 생성자 함수 방식의 차이
  객체 리터럴 프로토타입 객체 : object.prototype
  생성자 함수 프로토타입 객체 : Person.prototype

객체 리터럴 방식의 함수 선언 방법

  sayHi : () => {...} 			// 불가
  
  sayHi : function() { ... }  	// 일회성이기에 권장하지 않음
  
  sayHi() {... } 				// 권장



new 없이 생성자 함수 호출하기
  this의 바인딩이 다르게 됨, 일반 함수는 전역객체에, 인스턴스는 생성된 빈 객체에
  new 없으면 그냥 전역 객체에 프로퍼티 추가되는거임

 

 

4. apply, bind, call 호출

 특정 객체에 명시적으로 바인딩하는 방식

 기명함수와 익명함수는 call, bind, apply 로 this 객체를 지정할 수 있음 (화살표 함수는 불가)
 예전의 front-end 에서 많이 보였음...

 

 

 

 

특이사항, setTimeout 함수에서 메서드에서 콜백으로 전달 시 this 가 사라지는 문제

let user = {
  firstName: "John",
  sayHi() {
    alert(`Hello, ${this.firstName}!`);
  }
};
user.sayHi() // 잘 동작함

setTimeout(user.sayHi, 1000); // Hello, undefined!
let f = user.sayHi;
setTimeout(f, 1000); // user 컨텍스트를 잃어버린거여!

node에서는 setTimeout에서 this 가 타이머를, 웹브라우저에서는 window 를 가리킴.

방법1. 그냥 이렇게 써라!

setTimeout(() => user.sayHi()
, 1000);

단점 : 중간에 객체에 변경이 생기면 변경된 메서드 호출 됨

 

방법2. bind로 해결해 봅시다.

let user = {
  firstName: "John",
  sayHi() {
    alert(`Hello, ${this.firstName}!`);
  }
};

let sayHi = user.sayHi.bind(user); // (*)

sayHi(); // Hello, John!
setTimeout(sayHi, 1000); // Hello, John!

1초 이내 firstName 값을 변경시켜도 동일한 결과가 나온다.

 

 

 

특이사항, new Function() 을 통한 함수 생성

new Function() 을 통해 생성된 함수는 현재 렉시컬 환경이 아닌 전역 렉시컬 환경을 참조함

Ex) 일반 익명 함수

function getFunc() {
  let value = "test";
  let func = function() {
  	alert(value);
   };
  
  return func;
};

getFunc();	// test 출력, 현재 렉시컬 환경 참조

 

Ex) new Function 함수

function getFunc() {
  let value = "test";
  let func = new Function('alert(value)');

  return func;
};

getFunc();		// reference error!, 전역 렉시컬 환경 참조

 

 

 

함수 호출 시 전달된 Parameter

전달된 인자는 지역변수에 복사됨, 이후 함수는 복사된 값을 사용, 언제나 복사한 값을 사용
(굳이 새로운 값에 할당 할 필요가 없는듯)

'Javascript' 카테고리의 다른 글

String 값은 어디에 저장이 될까?  (0) 2022.12.01
자바스크립트의 Array  (0) 2022.11.30
변수의 유효범위(Scope)와 클로저, 가비지 컬렉션  (1) 2022.11.30
Closer  (0) 2021.11.14
버블링과 캡처링  (0) 2021.11.12

댓글