본문 바로가기
FRONTEND/Javascript

Javascript Function - Function 타입

by 또야또야 2020. 8. 3.
반응형

Function 타입

ECMAScript에서 함수는 사실 객체입니다.
모든 함수는 Function 타입에 대한 인스턴스이며 다른 참조 타입과 마찬가지로 프로퍼티/메서드가 있습니다

함수를 정의하는 방법

function sum (num1, num2) {
  return num1 + num2;
}
  • 함수 선언 방식

함수 선언 호이스팅 과정으로 인하여 함수 선언부를 다른 코드를 실행하기전에 먼저 읽고 모든 실행 컨텍스트에서 접근하고 실행할 수 있습니다.

** 함수 선언 호이스팅(hoisting)
JS 엔진은 코드를 평가할 때 제일 먼저 함수 선언을 찾은 다음 이들을 맨 위로 올립니다.
함수가 선언된 부분이 함수가 실행되는 부분보다 뒤에 있을 경우에도 JS 엔진이 함수 선언을 '끌어올립니다 hoist'.

const sum = function (num1, num2) {
  return num1 + num2;
}
  • 함수 표현식

함수 표현식은 자바스크립트 프로그래밍에서 유용한 도구입니다. 
함수 표현식은 일반적인 변수 할당과 비슷하게, 함수가 선언 되기 이전 줄에서 사용할 수 없습니다.
람다함수, 익명함수 라고 불리기도하며, 함수에 꼭 이름이 필요하지 않게 함으로써 동적인 프로그래밍을 가능하게 합니다.

함수 표현식에 대한 자세한 사용 방법 및 참고는 여기를 참고해주세요.


함수의 내부 구조

함수에는 arguments  , this  라는 특별한 객체가 있습니다.

  •  arguments 객체는 배열과 비슷한 객체이며, 함수에 전달된 매개변수를 모두 표현합니다. (현재 MDN에선 권장하지 않습니다.)

  •  arguments 의 '소유자인 함수'를 가리키는 포인터arguments.callee 라는 프로퍼티도 있습니다. (strict 모드 에서는 사용을 금합니다.)

  • 함수 객체내부에 존재하는 caller 프로퍼티도 있습니다. 해당 함수를 호출한 함수에 대한 참조를 저장하며, 스코프에서 호출했다면 null   이 저장됩니다.  (현재 MDN에선 권장하지 않습니다.)


함수 프로퍼티와 메서드

모든 함수에 공통인 프로퍼티는 length , prototype  입니다.

  • length : 함수가 넘겨 받을 것으로 예상하는 매개변수의 갯수를 의미합니다.

  • prototype 모든 참조 타입의 기본적인 인스턴스 메서드가 존재하는 곳

개발자가 정의한 참조 타입과 상속을 정의할 때 가장 중요합니다.

 

함수는 apply()  , call() ,  bind() 라는 메서드들을 보유하고있습니다.
이 메서드들은 해당 함수를 호출한 '함수의 소유자 객체(owner object)' 를 호출하면서 소유자 object의  this 를 넘길 수 있습니다.
말하자면 소유자 object는 this 의 주체를 가리킨다고 할 수 있습니다. 
결과적으로는 함수 내부에서  this 객체의 값을 바꾸는 것이나 마찬가지입니다.

  •  call() : 함수에 call()  메서드를 사용하므로써 특정 object에서 다른 object에 정의되어있는 메서드를 사용할 수 있게 해줍니다.
    해당 함수의 소유자 object를 매개변수로 하여 메서드를 호출할 수 있습니다. 소유자 Object가 필요하지 않다면 null을 할당 할 수 있습니다.

const person = {
  fullName: function() {
  	return this.firstName + " " + this.lastName;
  }
}
const person1 = {
  firstName: "Jan",
  lastName: "Ding"
}
const person2 = {
  firstName: "Mary",
  lastName: "Ding"
}

person.fullName.call(person2) // "Mary Ding"
person.fullName.call(person1) // "Jen Ding"

두 번째 이후 매개변수에는 필요한 내용들을 각각 나열하면 됩니다.
- 매개변수 ( 함수에 넘길 소유자 object의  this 사용할 매개변수 각각 나열 )

// 매개변수와 함께 사용시
const person = {
  fullName: function (city, country) {
  	return
       this.firstName + " " + this.lastName + "," + city + "," + country
  }
}
const person1 = {
  firstName: "Jen",
  lastName: "Ding"
}

person.fullName.call(person1, "Seoul", "Korea");
// "Jen Ding, Seoul, Korea"

  •  apply() : apply는 call 메서드와 비슷하게 동작하지만, 매개변수를 전달하는 방식만 다릅니다.

- 매개변수 ( 소유자 함수에 넘길this, 매개변수만으로 이루어진배열 )

// 매개변수와 함께 사용시
const person = {
  fullName: function (city, country) {
  	return
       this.firstName + " " + this.lastName + "," + city + "," + country
  }
}
const person1 = {
  firstName: "Jen",
  lastName: "Ding"
}

person.fullName.apply(person1, ["Seoul", "Korea"]);
// "Jen Ding, Seoul, Korea"

두 메서드는 소유자 객체 - this 를 바꾸는데에 가장 효과적으로 사용할 수 있습니다. 

window.color = "red";
const o = { color: "blue" };

function sayColor() {
  console.log(this.color)
}

sayColor();	           // red -> owner object :: Window

sayColor.call(this)    // red -> owner object :: Window
sayColor.call(window)  // red -> owner object :: Window
sayColor.call(o)       // blue -> owner object :: o

전역 함수로 정의된 sayColor() 는 전역 scope에서 호출하면 this.color 를 window.color 로 평가하여 'red'를 표시합니다.

call() 이나 apply() 를 써서 scope를 바꾸면 객체마다 일일히 같은 메서드를 등록하지 않아도 된다는 장점이 있습니다.


  • bind() : 이 메서드를 사용하면 함수의  this 는 bind() 에 전달된 object로 고정되어 해당 object를 가리킵니다.
const o = { color: 'blue' }

function sayColor () {
  console.log(this.color)
}

const objectSayColor = sayColor.bind(o);
// bind() 로 인해 sayColor 함수는 객체 o 로 고정됩니다.
// sayColor의 this는 지금부터 o를 가리킵니다.

objectSayColor(); // 'blue'

bind() 는 특정 객체나 class안에 정의된 메서드에서도 바인딩 할 수 있습니다.

class SayColor {
  constructor (a, b) {
    this.a = a
    this.b = b
  }

  colorType () {
    console.log('this is: ', this)
    console.log(`a is..${this.a}, b is..${this.b}`)
  }
}

const o = { a: 'pink', b: 'salmon' }

const color = new SayColor('red', 'blue')

color.colorType()
// this is.. SayColor { a: "red", b: "blue" }
// "a is..red, b is.. blue"

color.colorType.bind(o)()
// this is.. { a: "pink", b: "salmon" }
// a is..pink, b is.. salmon

this 는 이미 sayColor object에 binding 되어있는 상태지만, 그 위에 새로 o object로 새로 binding을 할 수 있습니다.


Arrow Function

Arrow Function은 일반 Function과 비슷하게 동작하지만, 문법 / 바인딩 등에서 차이점이있습니다.
문법은 생략하고 그 외 차이점에 대해 확인해 보겠습니다.

1. arguments 바인딩

Arrow Function은 arguments  객체에 대한 바인딩(매개변수 전체에 접근)이 없습니다. 다시말해, arguments 사용이 불가능합니다.

// Regular Function
const foo = {
  showArgs () {
    console.log(arguments)
  }
}
foo.showArgs(1, 2, 3, 4);    // 1, 2, 3, 4
// Arrow Function
const foo = {
  showArgs: () => {
    console.log( ...arguments )
  }
}
foo.showArgs(1, 2, 3, 4)   // Error: arguments is not defined

2. this 의 사용

Arrow Function의 this 의 값은 상위 scope의 this 를 가리킵니다. (Lexical this 라고 합니다)

const aboutMe = {
  name: "JJ",
  thisInArrow: () => {
    console.log("My name is " + this.name)
    // no 'this' binding here
  },
  thisInRegular () {
    console.log("My name is " + this.name)
    // 'this' binding works here
  }
}

aboutMe.thisInArrow()    // My name is     -> window object
aboutMe.thisInRegular()  // My name is JJ 

3. new 키워드의 사용

선언함수나 함수 표현식으로 생성된 일반 Function은 생성과 호출이 모두 가능합니다. 일반 Function은 생성(construct)할 수 있기 때문에, new 키워드를 사용하면서 생성자 함수로쎠 호출될 수 있습니다.

그러나, Arror Function은 호출은 가능하지만 생성될 수는 없기 때문에 constructor function으로서 사용될 수 없습니다. 그러므로, new  키워드를 사용하여 호출될 수 없습니다.

const add = (x, y) => console.log(x + y);
new add(2, 3)
// Error: add is not a constructor

4. 이름이 동일한 매개변수 사용 불가능

(물론 사용할일은 없겠지만,) Arrow Function은 strict 모드에서든 일반모드에서든, 이름이 같은 매개변수(named parameters)를 절대 사용할 수 없습니다.

const add (x, x) => {}
// SyntaxError: duplicate argument names not allowed in this context

** 일반 Function 에서는, 일반모드일 때만 이름이 동일한 매개변수를 사용할 수 있습니다. (strict 모드 불가능)

참고 : medium.com/better-programming/difference-between-regular-functions-and-arrow-functions-f65639aba256


pure function

반응형

'FRONTEND > Javascript' 카테고리의 다른 글

Javascript의 프로토타입  (0) 2020.09.03
Javascript의 this  (0) 2020.08.19
참조타입  (0) 2020.07.29
웹 브라우저의 메모리 관리 - 가비지 컬렉션(Garbage Collection)  (0) 2020.07.29
LocalStorage & SessionStorage  (0) 2020.05.09

댓글