var outer = function(){
var a = 1;
var inner = function(){
return ++a;
};
return inner;
};
var outer2 = outer();
console.log(outer2()); //2
console.log(outer2()); //3
위의 함수의 동작을 자세히보면, 함수 inner가 반환되고
outer2가 inner함수를 받게된다. outer()함수는 이미 실행되고
outer2 함수가 실행될때에는 이미 outer함수는 끝이나서 가비지 컬렉터로
수집되어서 var a = 1이라는것은 나타나지않아야하는데 여기서는 a라는 변수가 그대로 남아있게 된다. 이것은 왜그런것일까???!
가비지 컬렉터는 사용하지 않는 메모리의 데이터를 지워주는 역활을 하는데, 어떤 값을 참조하는 변수가 하나라도 남아있다면 그 값은 수집 대상에 포함시키지 않고 그대로 남기게된다. 위와 같은 경우도 outer2에 inner를 넣음으로써 a라는 변수를 사용할수도 있다는것을 가비지 컬렉터는 알게되기 때문. 즉 클로저는 이러한 원리로 동작하게된다.
클로저라는것을 정리하자면 어떤 함수 A에서 선언한 변수 a를 참조하는
내부함수 B를 외부로 전달할경우 실행 컨택스트가 종료된 이후에도
변수 a가 사라지지않는 현상. 이라고 말할수있다👌
___또한 setInterval/setTimeout, eventListener같은 경우에도
외부 객체인 window, DOM에 함수내에서 지역변수를 참조하게된다.
Clousure의 메모리관리는 식별자에 NULL을 입력해주면된다.
var fruits = ['apple', 'banana', 'peach'];
var $ul = document.createElement('ul');
fruits.forEach(function (fruit){
var $li = document.createElement('li');
$li.innerText = fruit;
$li.addEventListener('click', function(){
alert('your choice is ' + fruit);
});
$ul.appendChild($li);
});
document.body.appendChild($ul)
var fruits = ['apple', 'banana', 'peach'];
var $ul = document.createElement('ul');
var alertFruit = function(fruit){
alert('your choice is ' + fruit);
}
fruits.forEach(function (fruit){
var $li = document.createElement('li');
$li.innerText = fruit;
$li.addEventListener('click', alertFruit.bind(null, fruist));
$ul.appendChild($li);
});
document.body.appendChild($ul)
alertFruit(fruits[1]);
var fruits = ['apple', 'banana', 'peach'];
var $ul = document.createElement('ul');
var alertFruitBuiler = function(fruit){
return function(){
alert('your choice is ' + fruit);
};
};
fruits.forEach(function (fruit){
var $li = document.createElement('li');
$li.innerText = fruit;
$li.addEventListener('click', alertFruitBuiler(fruit));
$ul.appendChild($li);
});
document.body.appendChild($ul)
alertFruitBuiler(fruits[1]);
var outer = function(){
var a = 1;
var inner = function(){
return ++a;
};
return inner;
};
var outer2 = outer();
console.log(outer2());
console.log(outer2());
앞에서 봣던 이코드를 다시보면 외부에서는 outer라는 함수에 접근을 할수가없다. 단 inner 함수를 return 해줌으로써 a라는값이 증가되는것을 알수있다. 즉 외부로 알려줄것들은 return으로 알려줄수잇고, 그렇지 않은것들은 return을 사용하지 않으면 된다.
var createCar = function () {
var fuel = Math.ceil(Math.random() * 10 + 10);
var power = Math.ceil(Math.random() * 3 + 2);
var moved = 0;
var publicMembers = {
get moved(){
return moved;
},
run : function(){
var km = Math.ceil(Math.random() * 6);
var wasteFuel = km / power;
if(fuel < wasteFuel){
console.log('이동불가');
return;
}
fuel -= wasteFuel;
moved += km;
console.log(km + 'km 이동 ( 총 ' + moved + 'km) 남은 연료 : ' + fuel);
}
}
Object.freeze(publicMembers);
return publicMembers;
};
var car = createCar();
console.log(car)
위의 코드는 생성자를 만들때 return 해주는것이 Object.freeze를 해준 객체이다. 즉 객체의 값을 변경할수없이 returnd을 하였기 때문에
외부에서 fuel, power, moved 같은 값을 변경할수가 없다.
만약 var publicMembers로 묶어서 freeze를 해주지 않고 return을 했다면 fuel, power, move에 접근이 가능했을것이다
var add = function(){
var result = 0;
for ( var i = 0; i < arguments.length; i++){
console.log("result",result)
console.log("arguments",arguments[i]);
result += arguments[i];
}
return result;
};
var addPartial = add.bind(null,1,2,3,4,5);
console.log(addPartial(6,7,8,9,10));
var partical = function(){
console.log("arguments",arguments)
var originalParitialArgs = arguments;
var func = originalParitialArgs[0];
if(typeof func !== 'function'){
throw new Error('첫번째 인자가 함수가 아닙니다.');
}
return function(){
var particalArgs = Array.prototype.slice.call(originalParitialArgs, 1);
console.log("particalArgs",particalArgs);
var restArgs = Array.prototype.slice.call(arguments);
console.log("restArgs",restArgs);
return func.apply(this, particalArgs.concat(restArgs));
};
};
var add = function(){
var result = 0;
for(var i = 0 ; i < arguments.length;i++){
result += arguments[i];
}
return result;
};
var addPartial = partical(add, 1 ,2 ,3 , 4, 5);
console.log(addPartial(6,7,8,9,10));
var dog = {
name : '강아지',
greet: partical(function(prefix, suffix){
return prefix + this.name + suffix;
}, '왈왈',)
};
console.log(dog.greet('입니다!'));
디바운스는 짧은 시간 동안 동일한 이벤트가 많이 발생할경우 이를 전부 처리하지않고 처음 또는 마지막에 발생한 이벤트에 대해 한번만 처리하는것을 의미하며, 프론트엔트 성능 최적화에 큰 도움을 주는 기능중 하나.
scroll, wheel, mousemove, resize 등에 적용하기 좋다.
var debounce = function(eventName, func, wait){
var timeoutId = null;
return function(event){
var self = this;
console.log(eventName, 'event 발생');
clearTimeout(timeoutId);
timeoutId = setTimeout(func.bind(self, event), wait);
};
var moveHandler = function(e){
console.log('move event 처리');
}
var wheelHandler = function(e){
console.log('wheel event 처리');
}
};
document.body.addEventListener('mousemove', debounce('move', moveHandler, 500));
document.body.addEventListener('mousewheel', debounce('wheel', wheelHandler, 700));
커링함수란 여러개의 인자를 받는 함수를 하나의 인자만 받는 함수로 나눠서 순차적으로 호출할수있게 체인형식으로 만들어주는것,
커링은 한번에 하나의 인자만 전달하는것을 원칙으로한다.
var curry3 = function(func){
console.log("func",func)
return function (a){
console.log("a",a)
return function (b){
console.log("b",b)
return func(a, b);
};
};
};
var getMaxWith10 = curry3(Math.max)(10);
console.log(getMaxWith10(8));
console.log(getMaxWith10(25));
//func [Function: max]
//a 10
//b 8
//10
//b 25
//25
var curry5 = function(func){
return function(a){
return function(b){
return function(c){
return function(d){
return function(e){
return func(a, b, c, d, e);
}
}
}
}
}
}
var getMax = curry5(Math.max);
console.log(getMax(1)(2)(3)(4)(5));
----------------------------------------------
var curry5 = func => a => b => c => d => e => func(a, b, c, d, e);
var getMax = curry5(Math.max);
console.log(getMax(1)(2)(3)(4)(5));
ES6 부터 화살표 함수를 사용하여 위와 같이 사용이 가능하다
var getInformation = function(baseUrl){
return function(path){
return function(id){
return fetch(baseUrl + path + '/' + id);
};
};
}
//ES6
var getInformation = baseUrl => path => id => fetch(baseUrl + path + '/' + id);
최근은 프레임워크나 라이브러리에서 커링이 광범위하게 사용되고있다.
!!이내용은 코어 자바스크립트(정재남지음) 책을보고 정리한 내용입니다