Self-defining function 패턴
앞서 살펴본 Init-time branching 패턴은 처음 웹페이지 초기화 단계에서 컴퓨팅 자원을 소모하여 향후 어떠한 방법으로 함수가 호출될 지 결정하는 것이었다면, Self-defining function 패턴은 위의 함수가 최초 실행되는 시기에 이것을 결정하여 설정하게 됩니다. 이렇게 Init-time branching 패턴의 초기화 시기를 조절하기 위한 상황 이외에도 함수 실행 전 초기화가 필요할 때 호출됩니다.
Self-defining function 패턴의 또 다른 사용 방법은 바로 함수가 한 번만 호출되어야할 때, 특히 XMLHttpRequest 등으로 서버에 요청을 보낼 때 사용하면 편리합니다.
예시1 - Self-defining function 패턴을 이용한 getXHR 정의
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<script type="application/javascript">
// Self-defining function 패턴을 이용한 getXHR 정의
let getXHR = (function () {
let xhr;
if (window.XMLHttpRequest) {
getXHR = function () {
return new XMLHttpRequest();
};
return new XMLHttpRequest();
}
try {
xhr = new ActiveXObject("MSXML2.XMLHTTP.6.0");
getXHR = function () {
return new ActiveXObject("MSXML2.XMLHTTP.6.0");
}
return xhr;
} catch (e) {
try {
xhr = new ActiveXObject("MSXML2.XMLHTTP.3.0");
getXHR = function () {
return new ActiveXObject("MSXML2.XMLHTTP.3.0");
}
return xhr;
} catch (e) {
console.log("This browser does not support XMLHttpRequest");
}
}
})
</script>
</body>
</html>
예시2 - Self-defining function 패턴을 이용한 함수 초기화
간단한 방명록을 만들어봅니다. 코멘트와 이름을 작성한 뒤 Sumit 버튼을 누르면 작성한 내용으로 Element가 추가되는 것을 확인할 수 있습니다. 이처럼 처음에 초기화 단계를 거치고 나면 이후에 같은 작업을 계속 반복하지 않아도 될 때는 초기화 단계의 정보를 클로저에 보관하고 변경되는 내용만 변경되도록 Self-defining function 패턴을 이용하면 좋습니다.
<!DOCTYPE html>
<html>
<head>
<style>
#commentWrapper {
width: 500px;
}
.comment {
width: 200px;
display: inline-block;
}
.name {
width: 200px;
display: inline-block;
}
</style>
</head>
<body>
<div id="commentWrapper">
<div>
<div class="comment">Comment</div>
<div class="name">Name</div>
</div>
</div>
<form action="" id="formComment">
<label>Comment: <input type="text" id="comment"/></label>
<label>Name: <input type="text" id="name"/></label>
<input type="submit"/>
</form>
<script>
(function () {
let addComment = function () {
let divCommentWrapper = document.getElementById("commentWrapper"),
divCommentRow = document.createElement("div"),
divComment = document.createElement("div"),
divName = document.createElement("div"),
inputComment = document.getElementById("comment"),
inputName = document.getElementById("name");
divComment.className = "comment";
divName.className = "name";
divCommentRow.appendChild(divComment);
divCommentRow.appendChild(divName);
addComment = function () {
divComment.innerHTML = inputComment.value;
divName.innerHTML = inputName.value;
inputComment.value = "";
inputName.value = "";
divCommentWrapper.appendChild(divCommentRow.cloneNode(true));
};
addComment();
};
document.getElementById("formComment").addEventListener("submit", function () {
addComment();
event.returnValue = false;
return false;
});
}());
</script>
</body>
</html>
예시3. Self-defining function 패턴을 이용한 인증 중복 방지
인증을 여러 번 요청하면 인증 절차에 문제가 발생하거나 계정 잠금이 발생할 수 있습니다. 이러한 상황은 페이지 새로고침이나 특히 사용자가 버튼을 여러 번 클릭하거나 엔터를 여러 번 누를 때 자주 발생합니다. 이럴 때는 Self-defining function을 통해 함수를 다시 정의하여 현재 요청 중일 때는 경고 창을 띄우도록 활용할 수 있습니다. 인증 이후에는 원래 인증 요청 함수로 설정해놔도 되고 다르게 응용할 수 있습니다.
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<script>
(function () {
let requestAuthentication = function (information) {
let _requestAuthentication = requestAuthentication;
requestAuthentication = function (information) {
console.log("Already requesting");
}
sendRequest(information);
function sendRequest(information) {
let xhr = new XMLHttpRequest();
xhr.open("POST", "/auth");
xhr.onload = function () {
console.log("Authorized!");
requestAuthentication = _requestAuthentication;
};
xhr.onerror = function () {
if (confirm("Error occurred, send again?")) {
sendRequest(information);
}
}
xhr.send(information);
}
}
requestAuthentication("name=hello&password=word");
}());
</script>
</body>
</html>
예시4. Self-defining function 패턴을 이용한 인증 정보 보관 및 중복 요청 방지
예시3과 같은 예를 보완하여 클로저에 해당 정보를 저장하고 있어도 좋습니다. 해당 변수를 한 번만 사용하고 사용하지 않을 것이라면 불필요한 클로저가 생성되고 데이터가 메모리에 계속 남아있을 수 있으니 undefined로 초기화 해주는 것이 좋습니다.
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<script>
(function () {
let requestAuthentication = function (information) {
let _requestAuthentication = requestAuthentication,
authInformation = null; // 인증 정보 보관용
requestAuthentication = function (information) {
if (authInformation === null) {
console.log("Already requesting");
return;
} else {
return authInformation; // 인증 정보가 null이 아닐 경우 인증 정보 반환
}
}
sendRequest(information);
function sendRequest(information) {
let xhr = new XMLHttpRequest();
xhr.open("POST", "/auth");
xhr.onload = function () {
console.log("Authorized!");
//requestAuthentication = _requestAuthentication; //기존소스 주석
authInformation = xhr.responseText; //인증성공! 인증 정보를 담는다.
};
xhr.onerror = function () {
if (confirm("Error occurred, send again?")) {
sendRequest(information);
}
}
xhr.send(information);
}
}
requestAuthentication("name=hello2&password=word2");
}());
</script>
</body>
</html>
참고도서 : 속깊은 자바스크립트
'Study Note > Javascript' 카테고리의 다른 글
javascript #디자인패턴 - Self-invoking constructor 패턴 (0) | 2021.02.13 |
---|---|
javascript #디자인패턴 - 메모이제이션 패턴 (memoization pattern) (0) | 2021.02.13 |
javascript #디자인패턴 - Init-time branching 패턴 (0) | 2021.02.10 |
javascript #디자인패턴 - 함수 기반 데커레이터 패턴(decorator pattern) (0) | 2021.02.10 |
javascript #디자인패턴 - 객체 기반 데커레이터 패턴(decorator pattern) (0) | 2021.02.10 |
댓글