안녕하세요.
계속해서 underscore 관련 포스팅을 이어나가겠습니다.
이번에 다룰 내용은 함수입니다.
bind, bindAll, partial, memoize 로 함수를 합성해보겠습니다.
1. _.bind( function, object, *arguments)
원본 function파라미터에 대한 새로운 wrapper함수를 반환합니다.
var accu = {
currentValue : 0,
add: function (val) {
this.currentValue += val;
},
substract: function(val) {
this.currentValue -= val;
}
};
accu.currentValue = 5;
accu.add(2);
accu.substract(3);
console.log('현재 값', accu.currentValue); // 현재값 4
var accTest1 = {
currentValue : 1
};
var accTest2 = {
currentValue : 2
};
var addFunction = _.bind(accumulator.add, accTest1);
var substractFunction = _.bind(accu.substract, accTest2);
addFunction(2);
substractFunction(3);
console.log('테스트1 값', accTest1.currentValue); // 테스트1값 3
console.log('테스트2 값', accTest2.currentValue); // 테스트 2값 -1
위의 코드를 보자.
5의 값을 설정해두고 2를 더하고 3을 빼서 4가 나오는 계산기 이다.
_.bind(사용할 함수, 바뀔 this값)인 셈이다.
this값을 바꿔주고 싶을때 사용하면 적절할것같다.
2. _.bindAll(object, methodNames)
여기에서 methodNames는 object 파라미터에 속한 함수명 파라미터 목록을 가지는 object 파라미터의 메소드명이다.
이 함수에서는 methodNames 파라미터에 명시된 메소드 전체가 object 파라미터에 설정되는 this값을 가지고 있다.
이는 이벤트 핸들러 컨텍스트에서 사용될 때 매우 유용하므로,
다음의 예제에서 accu 객체를 재사용하고 add1()과 substract1() 메소드를 ㅅ ㅐ롭게 정의하는 데 이벤트 핸들러로
사용하면 적합하다.
예제는 1번과 매우 비슷하다.
var accu = {
currentValue : 0,
add: function (val) {
this.currentValue += val;
},
substract: function(val) {
this.currentValue -= val;
},
add1 : function () {
this.currentValue += 1;
},
substract1 : function () {
this.currentValue -= 1;
}
};
accu.currentValue = 5;
accu.add(2);
accu.substract(3);
console.log('현재 값', accu.currentValue);
var addFunction = _.bindAll(accu, 'add1', 'substract1');
_.bindAll 이 되었다면 'add1'이나 'substract1'이 메서드가 호출될때 this.currentValue 값이 바뀔것이다.
3. _.partial(function, arguments)
_.bindAll과 비슷한데 this값을 미리 설정하지 않은 경우이다.
arguments 파라미터 중 _로 명시된 것들은 인수 값이 설정되지 않은 상태이고,
반환되는 함수가 사용 될때 사용되는 명시값으로 대체된다.
var propertyFormatter = (function() {
"use strict";
var extractDataPropertiesForDisplayAsArray = function(source, ignoreId) {
var propertiesForDisplay = [];
if (_.isNull(source) || _.isUndefined(source) ||
_.isEmpty(source) || (!ignoreId && !_.isNumber(source.id))) {
return propertiesForDisplay;
}
_.each(_.pairs(source), function(keyValue) {
var key = keyValue[0];
var value = keyValue[1];
if (_.isDate(value) || _.isBoolean(value) ||
_.isNumber(value) || _.isString(value)) {
propertiesForDisplay.push("Property '" +
key + "' of type: " + typeof value + " has value: " + value);
} else if (!_.isFunction(value)) {
propertiesForDisplay.push("Property: " + keyValue[0] + " cannot be displayed.");
}
});
return propertiesForDisplay;
};
var extractDataPropertiesForDisplayForAnyObject =
_.partial(extractDataPropertiesForDisplayAsArray, _, true);
return {
extractPropertiesForDisplayAsArray: function(source, ignoreId) {
var propertiesForDisplay = [];
if (_.isNull(source) || _.isUndefined(source) ||
_.isEmpty(source) || (!ignoreId && !_.isNumber(source.id))) {
return propertiesForDisplay;
}
_.each(_.pairs(source), function(keyValue) {
var key = keyValue[0];
var value = keyValue[1];
if (_.isDate(value) || _.isBoolean(value)
|| _.isNumber(value) || _.isString(value)) {
propertiesForDisplay.push("Property '"
+ key + "' of type: " + typeof value + " has value: " + value);
} else {
propertiesForDisplay.push("Property '" + key + "' cannot be displayed.");
}
});
return propertiesForDisplay;
},
extractDataPropertiesForDisplayAsArray: extractDataPropertiesForDisplayAsArray,
extractDataPropertiesForDisplayForAnyObject: extractDataPropertiesForDisplayForAnyObject,
extractPropertiesForDisplayAsString: function(source, ignoreId) {
if (_.isNull(source) || _.isUndefined(source)
|| _.isEmpty(source) || (!ignoreId && !_.isNumber(source.id))) {
return [];
}
return _.reduce(source, function(memo, value, key) {
if (memo && memo !== "") {
memo += "<br/>";
}
var isDate = typeof value === 'object' && value instanceof Date;
if (_.isDate(value) || _.isBoolean(value)
|| _.isNumber(value) || _.isString(value)) {
return memo + "Property: " + key +
" of type: " + typeof value + " has value: " + value;
}
return memo + "Property: " + key + " cannot be displayed.";
},
"");
}
};
}());
_.partial()의 파라미터를 보면 이 파라미터로 extractDataPropertiesForDisplayForAnyObject가 실행될 때
source값이 전달된다.
extractDataPropertiesForDisplayAsArray를 간단하게 대체할 수 있다.
4. _.memoize로 함수 합성하기
_.memoize(function, [hashFunction])은 최적화하는 방식을 제공한다.
이 함수를 사용하면 첫번째 함수 파라미터 값을 기본 key로 해서 function 호출의 결과를 메모리에 저장한다.
함수 _.memoize()를 사용하면 첫 번째 인수와 같은 값으로 호출 될때마다 저장된 결과를 반환하는
함수가 생성된다.
인수 목록이 더 복잡해지면, 선택적 파라미터인 [hashFunction]을 사용해 function 결과를 저장하는 데 사용되는 키를
현재 인수 목록 기반으로 정의 할 수 있다.
_.memoize(function, [hashFunction]) {
var fibonacci = _.memoize(function(n) {
return n < 2 ? n: fibonacci(n - 1) + fibonacci(n - 2);
});
}
피보나치를 생각하면 된다.
5. _.wrap(function, wrapper)
이 함수는 function 파라미터가 실행되기 전이나 실행된 후에 실행할 코드에 대한 함수를 생성한다.
_.wrap(함수, wrapper)
var hello = function (name) {
return "hello" + name
};
hello = _.wrap(hello, function (func) {
return "before, " + func("moe") ", after";
});
hello();
이처럼 내가 원하는 내용으로 감쌀수 있다.
jquery의 wrap 함수와 비슷한 구성을 가지고 있다.
후속 포스팅에서 계속 이어나가도록 하겠습니다.
'프론트엔드' 카테고리의 다른 글
Node.js 기초부터 튼튼히 (3) 이벤트 (1) | 2018.01.08 |
---|---|
디자인 구현을 위한 원칙 (0) | 2017.11.02 |
마이크로서비스 UI - 마이크로프론트엔드 (0) | 2017.09.14 |
underscore 알아보기 (2) (0) | 2017.09.07 |
underscore 알아보기 (1) (0) | 2017.07.19 |