반응형

closure(클로저)는 함수와 그 함수가 선언된 스코프(scope) 사이의 관계를 말합니다. closure는 함수가 정의될 때의 환경을 기억하고, 그 환경에서 정의된 변수에 접근할 수 있는 기능을 제공합니다.

JavaScript의 함수는 first-class citizen이므로, 변수에 할당하거나 다른 함수의 인자로 전달할 수 있습니다. closure는 이러한 특징을 이용하여 함수를 반환하거나 함수를 전달할 때, 함수가 정의된 스코프에서 선언된 변수에 접근할 수 있는 것을 가능하게 합니다.

이는 외부 함수가 종료되어도 내부 함수가 참조하는 변수들이 유지되어 외부 함수의 변수에 접근할 수 있게 합니다.

function outerFunction(x) {
  return function innerFunction(y) {
    return x + y;
  };
}

const add5 = outerFunction(5);
console.log(add5(3)); // 8

위의 코드에서 outerFunction은 x 값을 매개변수로 받습니다. 그리고 innerFunction 함수를 반환합니다. innerFunction 함수는 y 값을 매개변수로 받습니다.

그리고 add5 변수에 outerFunction(5)의 결과를 할당합니다. 이 결과는 innerFunction 함수입니다. 그러므로 add5(3)을 실행하면 innerFunction 함수가 실행되고 x+y의 결과인 8이 출력됩니다.

아래의 코드에서는 createCounter 함수가 closure를 생성합니다.

function createCounter() {
  let count = 0;
  return function() {
    return ++count;
  };
}

const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3

createCounter 함수가 반환하는 함수는 count 변수에 접근할 수 있어서, counter 변수에 저장된 함수를 호출할 때마다 count 값이 1씩 증가합니다.

closure는 코드의 캡슐화(encapsulation)에 많이 사용됩니다. 내부 함수가 외부 함수의 변수에 접근할 수 있기 때문에, 외부 함수의 변수를 숨기고 내부 함수만을 통해서 접근할 수 있는 기능을 구현할 수 있습니다.
위의 소스에서 count 변수는 closure를 통해 은닉화 되었습니다.

closure는 애플리케이션의 구조화와 모듈화에 큰 도움이 될 수 있습니다. 예를 들어, 아래의 코드에서는 private 변수를 통해서 외부에서 접근할 수 없는 값을 저장할 수 있습니다.

function Person(name) {
  let privateName = name;
  
  return {
    getName: function() {
      return privateName;
    },
    setName: function(newName) {
      privateName = newName;
    }
  };
}

const person = Person("John");
console.log(person.getName()); // John
person.setName("Jane");
console.log(person.getName()); // Jane

closure를 사용하면, 객체의 내부 상태를 외부에서 변경할 수 없게 할 수 있습니다. 그리고 내부에서만 접근할 수 있는 메소드를 구현할 수 있어서, 애플리케이션의 코드를 깔끔하게 유지할 수 있습니다.

closure의 장단점

장점

  1. 변수의 유지

closure는 외부 함수의 변수를 저장하여 외부 함수가 종료된 후에도 변수를 사용할 수 있습니다. 이는 메모리 효율성을 높여줍니다.

  2. 은닉성

closure를 사용하면 외부 함수의 변수와 내부 함수를 숨길 수 있어 변수의 접근을 제어할 수 있습니다.

  3. 단일 책임 원칙

closure는 함수의 역할을 구분하여 각각의 역할이 담당하는 변수와 함수를 분리할 수 있습니다. 이는 단일 책임 원칙을 준수하는 코드를 작성할 수 있게 해줍니다.

단점

  1. 메모리 낭비

closure를 사용하면 외부 함수가 종료된 후에도 내부 함수가 참조하는 변수를 메모리에 저장해야 하므로 메모리 낭비가 생길 수 있습니다.

  2. 코드 가독성

closure를 많이 사용하면 코드가 복잡해지고 이해하기 어렵습니다. 따라서 클로저를 사용할 때에는 적절한 주석과 코드 구조를 갖추어야 합니다.

반응형
반응형

구독하고 있는 chris@gomakethings.com의 메일링 리스트로 온 내용을 번역했습니다.

Array.prototype.find() 메서드는 배열에서 콜백 함수로 전달한 테스트와 일치하는 첫 번째 항목을 찾습니다. 콜백은 배열의 현재 항목을 참조하는 참조 변수를 위한 인수를 제공합니다.

다음은 샌드위치 배열에서 참치를 찾는 간단한 예입니다.

let sandwiches = ['turkey', 'chicken salad', 'tuna', 'pb&j', 'egg salad'];

let tuna = sandwiches.find(function (sandwich) {
	return sandwich === 'tuna';
});

console.log(tuna); // logs "tuna"

항목을 찾지 못하면 undefined를 반환합니다.

let hamburger = sandwiches.find(function (sandwich) {
	return sandwich === 'hamburger';
});

console.log(hamburger); // logs undefined

Array.prototype.find() 메서드가 진짜 잘 작동하는 곳은 복잡한 배열입니다.

예를 들어, todo 객체가 포함된 배열을 가지는 JSON 파일을 반환하는 API가 있다고 가정해봅시다.

let todos = [
	{
		item: 'Wash the dog',
		added: 20180322,
		completed: false
	},
	{
		item: 'Plan surprise party for Bailey',
		added: 20180314,
		completed: false
	},
	{
		item: 'Go see Black Panther',
		added: 20180312,
		completed: true
	},
	{
		item: 'Launch a podcast',
		added: 20180305,
		completed: false
	}
];

어떻게 하면 'Go see Black Panther' 아이템이 언제 추가됐는지, 완료됐는지 확인할 수 있을까?

Array.prototype.find() 메서드가 없을 경우, 각각의 할 일을 반복하여 아이템을 확인하고, 일치하는 결과를 저장하고, 루프을 종료해야 합니다.

let item;
for (let todo of todos) {
	if (todo.item === 'Go see Black Panther') {
		item = todo;
		break;
	}
}

Array.prototype.find() 메서드를 사용할 경우, todo.item 속성이 'Go see Black Panther' 인 것을 확인하면 됩니다.

let item = todos.find(function (todo) {
	return todo.item === 'Go see Black Panther';
});
반응형
반응형

javascript에서는 함수를 3가지 방법으로 정의할 수 있습니다.

1. Function 생성자 함수 이용

let add = Function('a', 'b', 'return a + b;');

console.log(add(10, 20));

가장 일반적이지 않은 방법으로서 실무적으로는 사용할 일이 거의 없을 것 같습니다. 다만 다른 함수정의 방식으로 함수를 생성하더라도 내부적으로는 생성자 함수를 통해서 함수가 만들어지게 됩니다. 때문에 javascript에서 모든 함수는 그 자체로 객체 입니다.

2. 함수 선언문 이용

function add(a, b)
{
  return a + b;
}

console.log(add(10, 20));

function 다음에 함수명을 반드시 포함해야 하며, 이 이름으로 함수를 호출할 수 있습니다. 함수 선언문을 이용해 함수를 정의하면 함수 호이스팅(function hoisting)이 일어납니다. 함수 호이스팅은 함수 정의를 소스 유효범위 내 가장 위로 끌어 올리는 것을 말합니다.
그래서 다음과 같이 함수 정의를 하기 전에 함수를 사용하더라도 오류가 발생하지 않습니다.

console.log(add(10, 20));

function add(a, b)
{
  return a + b;
}

3. 함수 표현식 이용

let add = function (a, b)
{
  return a + b;
}

console.log(add(10, 20));

function 다음에 함수명이 없는 익명 함수 리터럴을 사용할 수 있으며 이를 변수에 할당하여 함수를 생성 합니다.
할당된 변수이름 뒤에 괄호를 붙여서 함수 호출을 할 수 있습니다.
이 경우에는 함수 호이스팅이 일어나지 않아서 만약 함수 정의 전에 함수를 사용하면 오류가 발생 합니다.

일반적으로는 익명 함수 형태로 사용하며 함수 내에서 재귀 호출이 필요한 경우에는 다음과 같이 함수명을 사용할 수도 있습니다. 다만 이때의 함수명은 함수 정의 밖에서는 사용할 수 없습니다.

let factorial = function _factorial (num)
{
  if (num > 1)
  {
    return num * _factorial(num - 1);
  }
  else
  {
    return 1;
  }
}

console.log(factorial(5));  // 120
console.log(_factorial(5)); // not defined 에러

 

반응형
반응형

자바스크립트에는 !를 두 개 붙인 !! 연산자가 있는데 !! 다음의 값(피연산자)에 대하여 불린값을 반환한다.

console.log(!!0);
console.log(!!1);
console.log(!!'');
console.log(!!'hello');
console.log(!!false);
console.log(!!true);
console.log(!!null);
console.log(!!undefined);
console.log(!!{});
console.log(!![]);

null 과 undefined는 모두 false 이고, 빈 배열 및 빈 객체는 모두 true 인 점을 주의할 필요가 있다.

당연하겠지만 not 연산자인 !와 함께 !!!를 사용하면 반대되는 불린값을 얻게 된다.

console.log(!!!0);
console.log(!!!1);
console.log(!!!'');
console.log(!!!'hello');
console.log(!!!false);
console.log(!!!true);
console.log(!!!null);
console.log(!!!undefined);
console.log(!!!{});
console.log(!!![]);

false를 다음과 같이 Boolean 객체로 만들면

console.log(!!(new Boolean(false)));

값(valueOf())이 false 라도 객체이기 때문에 true가 된다.

 

반응형

+ Recent posts