연습 11
함수를 받고 함수를 반환하는 함수 dateStamp를 만듭니다. 반환 된 함수는 전달 된 함수가 허용하는 많은 인수를 허용하고 호출 시간이 있는 타임 스탬프가 포함 된 날짜 키와 전달 된 함수 호출의 결과를 포함하는 출력 키가 있는 객체를 반환합니다. 힌트 : Date 객체에 대한 정보에 액세스하는 방법을 조사해야 할 수도 있습니다.
https://dev.to/ryanameri/mastering-hard-parts-of-javascript-closure-iii-56m3
function dateStamp() {}
const stampedMultBy2 = dateStamp((n) => n * 2);
console.log(stampedMultBy2(4));
// => should log { date: (today's date), output: 8 }
console.log(stampedMultBy2(6));
// => should log { date: (today's date), output: 12 }
솔루션 11
function dateStamp(func) {
const logTime = {};
function stamping(input) {
logTime.date = new Date();
logTime.output = func(input);
return logTime;
}
return stamping;
}
함수 메모리를 제공하는 또 다른 방법은 여기에서 함수가 호출 된 횟수를 세는 대신에 함수가 호출 된 시기를 추적하는 것입니다. 우리 함수는 메모리가 필요하기 때문에 외부 범위, 즉 클로저에 영구 객체가 있어야 합니다. 그런 다음이 객체는 함수가 호출 될 때로 설정된 날짜 속성과 두 번째 함수의 매개 변수를 인수로 사용하여 원래 매개 변수의 반환 값으로 설정된 출력 속성을 가져옵니다.
우리는 지금 우리의 함수에 메모리를 부여하는 것에 대해 꽤 확신을 가질 것입니다. 이것이 기본적으로 클로저의 요점입니다.
연습 12
인수를 받지 않는 함수 검열을 만듭니다. 검열은 두 개의 문자열 또는 하나의 문자열을 받아들이는 함수를 반환합니다. 두 개의 문자열이 주어지면 반환 된 함수는 나중에 사용하기 위해 두 문자열을 한 쌍으로 유지합니다. 하나의 문자열이 주어지면 반환 된 함수는 동일한 문자열을 반환합니다. 단, 첫 번째 문자열 (저장된 쌍)의 모든 인스턴스는 해당하는 두 번째 문자열 (저장된 쌍)로 대체됩니다.
function censor() {}
const changeScene = censor();
changeScene("dogs", "cats");
changeScene("quick", "slow");
console.log(changeScene("The quick, brown fox jumps over the lazy dogs."));
// => should log 'The slow, brown fox jumps over the lazy cats.'
솔루션 12
function censor() {
const phrases = new Map();
function actualFn(...args) {
if (args.length === 2) {
phrases.set(args[0], args[1]);
} else {
let input = args[0];
for (let [key, value] of phrases) {
let regex = new RegExp(key, "g");
input = input.replace(regex, value);
}
return input;
}
}
return actualFn;
}
이제 우리의 기능이 조금 더 흥미로워지고 있습니다. 하지만 이 연습을 세분화해도 이전 연습에서 연습했던 것과 동일한 작업을 수행하는 것입니다. 즉, 일종의 기억이 필요합니다. 함수는 전달 된 인수의 수에 따라 다른 동작을 가져야 합니다.
이 연습에서는 메모리 부분에 Map()을 사용하기로 결정했지만 객체도 사용할 수 있습니다. 나머지 매개 변수를 사용하여 내부 함수에 전달 된 모든 인수를 캡처 한 다음 배열의 크기를 확인하여 얼마나 많은 인수가 있는지 확인합니다.
두 개의 인수가 전달되면 구문 맵에 저장하고 완료됩니다. 인수가 하나만 전달 된 경우 string.prototype.replace()를 사용하고 구문 맵에 이전에 저장된 값과 일치하는 문자열의 모든 항목을 바꿉니다.
새로운 String.prototype.replaceAll()을 사용하고 싶었지만 이 글을 쓰는 시점에서는 아직 널리 지원되지 않습니다 (예를 들어 연습을 실행하는 데 사용하는 node.js 14 버전에서는 지원되지 않습니다). replaceAll()에 대한 지원이 더 널리 보급되면 이를 사용할 수 있으며 정규식을 구성 할 필요가 없습니다.
연습 13
JavaScript 객체에는 개인 속성과 같은 것이 없습니다! 그러나 아마도 있습니까? 모든 값을 비밀로 받아들이고 두 개의 메서드 만 있는 객체를 반환하는 함수 createSecretHolder(secret)를 구현합니다.
비밀을 설정하는 비밀 setSecret()를 반환하는 getSecret()
function createSecretHolder() {}
const obj = createSecretHolder(5);
console.log(obj.getSecret());
// => returns 5
obj.setSecret(2);
console.log(obj.getSecret());
// => returns 2
솔루션 13
function createSecretHolder(secret) {
let num = secret;
const obj = {
getSecret() {
return num;
},
setSecret(n) {
num = n;
},
};
return obj;
}
하아! getter 및 setter를 구현하는 흥미로운 방법! 4 장, 클래스와 프로토 타입에서 더 자세히 다룰 것이지만, 여기서는 JS의 클래스가 (대부분) 구문 적 설탕이기 때문에 이러한 게터와 세터가 어떻게 이면에서 구현 될 수 있는지 살펴 보겠습니다.
또한 이제 ES2019에 추가 된 개인 클래스 필드의 형태로 JS의 개체에 개인 속성을 설정할 수 있다고 생각합니다 (이 두 단락이 이해가 되지 않더라도 걱정하지 마세요. 여전히 운동을 해결할 수 있어야 합니다!)
그래서 이것을 어떻게 해결 했습니까? 함수를 반환하는 대신 여기에서 객체를 반환했습니다. 그러나 우리의 객체에는 두 가지 메소드가 있습니다. 하나는 매개 변수를 받지 않고 대신 외부 범위에 저장된 num 변수의 값을 반환하는 getter입니다. 다른 하나는 그 값을 변경하는 setter입니다. 객체는 지속적이고 값을 유지하기 때문에 Java와 같은 OOP 언어에서 일반 getter 및 setter가 작동하는 방식과 유사하게 작동합니다.
연습 14
새 함수를 반환하는 함수 callTimes를 작성합니다. 새 함수는 호출 된 횟수를 반환해야 합니다.
function callTimes() {}
let myNewFunc1 = callTimes();
let myNewFunc2 = callTimes();
console.log(myNewFunc1()); // => 1
console.log(myNewFunc1()); // => 2
console.log(myNewFunc2()); // => 1
console.log(myNewFunc2()); // => 2
솔루션 14
function callTimes() {
let counter = 0;
function insideFn() {
counter++;
return counter;
}
return insideFn;
}
최근의 몇 가지 연습과 비교하면 이것은 다소 간단하지만 함수가 호출 된 횟수를 계산하는 방법을 기억하는 것이 좋습니다. COVE (외부 변수)에 액세스 할 수 있고 둘 다 검색하거나 변경할 수 있다는 좋은 데모입니다.
연습 15
숫자를 받아들이고 (n이라고 부르겠습니다) 함수를 반환하는 함수 russianRoulette를 만듭니다. 반환 된 함수는 인수를 취하지 않으며 처음 n-1 번 호출 될 때 문자열 'click'을 반환합니다. 바로 다음 호출 (n 번째 호출)에서 반환 된 함수는 문자열 'bang'을 반환합니다. 그 이후의 모든 호출에서 반환 된 함수는 '다시 재생하려면 다시 로드 '문자열을 반환합니다.
function russianRoulette() {}
const play = russianRoulette(3);
console.log(play());
// => should log 'click'
console.log(play());
// => should log 'click'
console.log(play());
// => should log 'bang'
console.log(play());
// => should log 'reload to play again'
console.log(play());
// => should log 'reload to play again'
해결책 15
function russianRoulette(num) {
let count = 0;
function closureFn() {
count++;
if (count < num) return "click";
else if (count === num) return "bang";
else return "reload to play again";
}
return closureFn;
}
러시안 룰렛은 무섭게 들리지만 이것은 지난 몇 번의 연습에서 해결했던 것과 동일한 문제의 변형입니다. 함수가 호출 된 횟수를 세고 그에 따라 다른 작업을 수행합니다. 여기서 우리가 하는 일은 원래 함수 (숫자)에 전달 된 매개 변수에 따라 달라집니다.
closure의 유연성과 힘은 여기에서 매우 분명해야 합니다. Java와 같은 전통적인 OOP 언어를 사용하여 이 기능을 구현하려면 훨씬 더 많은 코드 라인이 필요합니다.
등록된 댓글이 없습니다.