# JavaScript专项算法题（3）：闭包

＠冒泡的马树

## 闭包、作用域和运行上下文

### 挑战1

``````// CHALLENGE 1
function createFunction() {
const innerFunction = () => {
console.log("hello");
}
return innerFunction;
}

/*** Uncomment these to check your work! ***/
const function1 = createFunction();
function1(); // => should console.log('hello');``````

### 挑战2

``````// CHALLENGE 2
function createFunctionPrinter(input) {
const innerValue = input;
const innerFunction = () => {
console.log(innerValue);
}
return innerFunction;
}

/*** Uncomment these to check your work! ***/
const printSample = createFunctionPrinter('sample');
printSample(); // => should console.log('sample');
const printHello = createFunctionPrinter('hello');
printHello(); // => should console.log('hello');
``````

### 挑战3

``````// CHALLENGE 3
function outer() {
let counter = 0; // this variable is outside incrementCounter's scope
function incrementCounter () {
counter ++;
console.log('counter', counter);
}
return incrementCounter;
}

const willCounter = outer();
const jasCounter = outer();

// Uncomment each of these lines one by one.
// Before your do, guess what will be logged from each function call.

/*** Uncomment these to check your work! ***/
willCounter();
willCounter();
willCounter();

jasCounter();
willCounter();

let backpackValue = x ;
const innerFunction = (el) => {
return backpackValue + el;
}
return innerFunction;
}

/*** Uncomment these to check your work! ***/
console.log(addByTwo(1)); // => should return 3
console.log(addByTwo(2)); // => should return 4
console.log(addByTwo(3)); // => should return 5

console.log(addByThree(1)); // => should return 4
console.log(addByThree(2)); // => should return 5

console.log(addByFour(4)); // => should return 8
console.log(addByFour(5)); // => should return 9``````

### 挑战4

``````// CHALLENGE 4
function once(func) {
let counter = 0;
let innerValue = 0;
const innerFunction = (el) => {
counter++;
if(counter == 1) {
innerValue = func(el);
return innerValue;
} else {
return innerValue;
}
}
return innerFunction;
}

/*** Uncomment these to check your work! ***/
console.log(onceFunc(4));  // => should log 6
console.log(onceFunc(10));  // => should log 6
console.log(onceFunc(9001));  // => should log 6``````

### 挑战5

``````// CHALLENGE 5
function after(count, func) {
let counter = count;
const innerFunction = () => {
counter--;
if(counter == 0){
func();
}
}
return innerFunction;
}

/*** Uncomment these to check your work! ***/
const called = function() { console.log('hello') };
const afterCalled = after(3, called);
afterCalled(); // => nothing is printed
afterCalled(); // => nothing is printed
afterCalled(); // => 'hello' is printed
``````

### 挑战6

``````// CHALLENGE 6
function delay(func, wait, ...args) {
setTimeout(() => func(...args), wait);
}

delay(called, 2000);  // "hello" after 2 seconds.``````

### 挑战7

``````// CHALLENGE 7
function rollCall(names) {
const innerArray = new Array;
for(let i=0; i {
if(innerArray.length == 0){
console.log("Everyone accounted for");
} else {
console.log(innerArray.shift());
}
}
return innerFunction;
}

/*** Uncomment these to check your work! ***/
const rollCaller = rollCall(['Victoria', 'Juan', 'Ruth'])
rollCaller() // => should log 'Victoria'
rollCaller() // => should log 'Juan'
rollCaller() // => should log 'Ruth'
rollCaller() // => should log 'Everyone accounted for'``````

### 挑战8

``````// CHALLENGE 8
function saveOutput(func, magicWord) {
const storedMagicWord = magicWord;
const storedInputArray = new Array;
const storedOutputArray = new Array;
const exitObject = new Object;
let tempOutput = 0;
const innerFunction = (el) => {
if(el !== storedMagicWord) {
storedInputArray.push(el);
tempOutput = func(el);
storedOutputArray.push(tempOutput);
return tempOutput;
} else {
if(storedInputArray.length == storedOutputArray.length) {
for(let i=0; i should log 4
console.log(multBy2AndLog(9)); // => should log 18
console.log(multBy2AndLog('boo')); // => should log { 2: 4, 9: 18 }``````

### 挑战9

``````// CHALLENGE 9
function cycleIterator(array) {
let counter = 0;
const innerFunction = () => {
counter++;
if(counter > array.length){
counter = 0;
return array[counter];
} else{
return array[counter-1];
}
}
return innerFunction;
}

/*** Uncomment these to check your work! ***/
const threeDayWeekend = ['Fri', 'Sat', 'Sun'];
const getDay = cycleIterator(threeDayWeekend);
console.log(getDay()); // => should log 'Fri'
console.log(getDay()); // => should log 'Sat'
console.log(getDay()); // => should log 'Sun'
console.log(getDay()); // => should log 'Fri'``````

### 挑战10

``````// CHALLENGE 10
function defineFirstArg(func, arg) {
const innerFunction = (el) =>{
return func(arg, el);
}
return innerFunction;
}

/*** Uncomment these to check your work! ***/
const subtract = function(big, small) { return big - small; };
const subFrom20 = defineFirstArg(subtract, 20);
console.log(subFrom20(5)); // => should log 15
``````

### 挑战11

``````// CHALLENGE 11
function dateStamp(func) {
let dateInfo;
const innerObj = new Object;
const innerFunction = (el) => {
dateInfo = new Date();
innerObj['date'] = dateInfo.toString();
innerObj['output'] = func(el);
return innerObj;
}
return innerFunction;
}

/*** Uncomment these to check your work! ***/
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 }``````

### 挑战12

``````// CHALLENGE 12
function censor() {
let parameterInfoObj = new Object;
let oneParameterArray = new Array;
let punctuationArray = new Array;
const innerFunc = (el1, el2) => {
if(el1 && el2) {
oneParameterArray = [];
punctuationArray = [];
parameterInfoObj[el1] = el2;
return parameterInfoObj;
}
else if(el1 && !el2){
oneParameterArray = el1.match(/\b(\w+)\b/g);
punctuationArray = el1.match(/([,. ]+)/g);
for(let i = 0; i should log 'The slow, brown fox jumps over the lazy cats.'
``````

### 挑战13

JavaScript对象中并没有私有属性的定义，然而或许可以自定义一个？构建createSecretHolder(secret)函数，接受任何值作为secret参数，并且仅返回两个方法，返回secret值的getSecret()和设置secret值的setSecret()。

``````// CHALLENGE 13
function createSecretHolder(secret) {
let secretInfo = secret;
const innerObj = new Object;
innerObj.getSecret = ()=>{
return secretInfo;
}
innerObj.setSecret = (el)=>{
secretInfo = el;
}
return innerObj;

}

/*** Uncomment these to check your work! ***/
const obj = createSecretHolder(5)
console.log(obj.getSecret()) // => returns 5
console.log(obj.setSecret(2)) // => undefined
console.log(obj.getSecret()) // => returns 2
``````

### 挑战14

``````// CHALLENGE 14
function callTimes() {
let counter = 0;
const innerFunction = () => {
return ++counter;
}
return innerFunction;
}

/*** Uncomment these to check your work! ***/
let myNewFunc1 = callTimes();
let myNewFunc2 = callTimes();
console.log(myNewFunc1()); // => 1
console.log(myNewFunc1()); // => 2
console.log(myNewFunc2()); // => 1
console.log(myNewFunc2()); // => 2
``````

### 挑战15

``````// CHALLENGE 15
function russianRoulette(num) {
let counter = num;
const innerFunction = () => {
counter--;
if(counter>0) {
return "click";
} else if(counter==0){
return "bang";
} else{
}
}
return innerFunction;
}

/*** Uncomment these to check your work! ***/
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'``````

### 挑战16

``````// CHALLENGE 16
function average() {
let averageValue = 0;
let argumentCounter = 0;
let argumentSum = 0;
const innerFunction = (el) => {
if(el == undefined) {
return averageValue;
} else{
argumentCounter++;
argumentSum += el;
averageValue = argumentSum / argumentCounter;
return averageValue;
}
}
return innerFunction;
}

/*** Uncomment these to check your work! ***/
const avgSoFar = average();
console.log(avgSoFar()); // => should log 0
console.log(avgSoFar(4)); // => should log 4
console.log(avgSoFar(8)); // => should log 6
console.log(avgSoFar()); // => should log 6
console.log(avgSoFar(12)); // => should log 8
console.log(avgSoFar()); // => should log 8``````

### 挑战17

``````// CHALLENGE 17
function makeFuncTester(arrOfTests) {
const firstLayerArray = [];
for(let i = 0; i {
for(let i=0; i str.toUpperCase();
const capLastAttempt2 = str => str.slice(0, -1) + str.slice(-1).toUpperCase();
console.log(shouldCapitalizeLast(capLastAttempt1)); // => should log false
console.log(shouldCapitalizeLast(capLastAttempt2)); // => should log true``````

### 挑战18

``````// CHALLENGE 18
function makeHistory(limit) {
const limitNumber = limit;
let parameterStack = [];
const innerFunction = (stringElement) => {
if(stringElement === "undo"){
if(parameterStack.length == 0) {
return "nothing to undo";
} else{
return `\${parameterStack.pop()} undone`;
}
} else{
parameterStack.push(stringElement);
if(parameterStack.length > limit){
parameterStack = parameterStack.slice(-limit);
}
return `\${stringElement} done`;
}
}
return innerFunction;
}

/*** Uncomment these to check your work! ***/
const myActions = makeHistory(2);
console.log(myActions('jump')); // => should log 'jump done'
console.log(myActions('undo')); // => should log 'jump undone'
console.log(myActions('walk')); // => should log 'walk done'
console.log(myActions('code')); // => should log 'code done'
console.log(myActions('pose')); // => should log 'pose done'
console.log(myActions('undo')); // => should log 'pose undone'
console.log(myActions('undo')); // => should log 'code undone'
console.log(myActions('undo')); // => should log 'nothing to undo'``````

### 挑战19

1. 输入blackjack函数的数值型数组的第一个数值加上输入DEALER函数中的两个数值参数之和得到的和，如果和小于等于21，返回此和；
2. 如果和大于21，返回字符串“bust”。

1. 最近一次的和值加上数值型数组的下一个数值元素，如果这个求和结果小于等于21的话，返回此和；
2. 返回“bust”如果求和结果大于21。

``````
// CHALLENGE 19
function blackjack(array) {
const dealer = (num1, num2) => {
let first = true;
let bust = false;
let sum = num1 + num2;
const player = () => {
if(first) {
first = false;
return sum;
}
if(bust) {
return "you are done!";
}
if(sum + array[0] <= 21){
sum += array.shift();
return sum;
} else {
array.shift();
bust = true;
return "bust";
}
}
return player;
}
return dealer;
}

/*** Uncomment these to check your work! ***/

/*** DEALER ***/
const deal = blackjack([2, 6, 1, 7, 11, 4, 6, 3, 9, 8, 9, 3, 10, 4, 5, 3, 7, 4, 9, 6, 10, 11]);

/*** PLAYER 1 ***/
const i_like_to_live_dangerously = deal(4, 5);
console.log(i_like_to_live_dangerously()); // => should log 9
console.log(i_like_to_live_dangerously()); // => should log 11
console.log(i_like_to_live_dangerously()); // => should log 17
console.log(i_like_to_live_dangerously()); // => should log 18
console.log(i_like_to_live_dangerously()); // => should log 'bust'
console.log(i_like_to_live_dangerously()); // => should log 'you are done!'
console.log(i_like_to_live_dangerously()); // => should log 'you are done!'

/*** BELOW LINES ARE FOR THE BONUS ***/

/*** PLAYER 2 ***/
const i_TOO_like_to_live_dangerously = deal(2, 2);
console.log(i_TOO_like_to_live_dangerously()); // => should log 4
console.log(i_TOO_like_to_live_dangerously()); // => should log 15
console.log(i_TOO_like_to_live_dangerously()); // => should log 19
console.log(i_TOO_like_to_live_dangerously()); // => should log 'bust'
console.log(i_TOO_like_to_live_dangerously()); // => should log 'you are done!
console.log(i_TOO_like_to_live_dangerously()); // => should log 'you are done!

/*** PLAYER 3 ***/
const i_ALSO_like_to_live_dangerously = deal(3, 7);
console.log(i_ALSO_like_to_live_dangerously()); // => should log 10
console.log(i_ALSO_like_to_live_dangerously()); // => should log 13
console.log(i_ALSO_like_to_live_dangerously()); // => should log 'bust'
console.log(i_ALSO_like_to_live_dangerously()); // => should log 'you are done!
console.log(i_ALSO_like_to_live_dangerously()); // => should log 'you are done!'
``````