---
# System prepended metadata

title: '30 Days of JavaScript [closures]'
tags: [leetCode, javascript]

---

## Day 2 : 2620. Counter
```js=
/**
 * @param {number} n
 * @return {Function} counter
 */
var createCounter = function(n) {
    return function() {
        const result = n
        n +=1
        return result
    };
};

/** 
 * const counter = createCounter(10)
 * counter() // 10
 * counter() // 11
 * counter() // 12
 */
 ```
 
 ### For Example 
 ```js=
const counter = createCounter(10);

const results = [];
results.push(counter()); // A
results.push(counter()); // B
results.push(counter()); // C

console.log(results); //[10, 11, 12]
 ```

#### 解釋
1. 創造一個counter的時候
```js=
n = 10 
counter = function() {
    const result = n
    n +=1
    return result
}
```
2. 當Ａ被call的時候，會
```js=
return n
n += 1
n === 11
```
3. 當Ａ被call的時候，會
```js=
return n
n += 1
n === 12
```
以此類推，在`createCounter`的時候就建立了一個closure並且初始的n為10，透過closure的特性，可以在函式與函式之間保有n的值。這就是為什麼n的值可以繼續的被記住。


## Day 3 2704. To Be Or Not To Be
```js=
function expect(val1) {
  return {
    toBe: function (val2) {
      if (val1 === val2) {
        return true ;
      } else {
        throw new Error("Not Equal");
      }
    },
    notToBe: function (val2) {
      if (val1 !== val2) {
        return true ;
      } else {
        throw new Error("Equal");
      }
    },
  };
}

```
1. 透過expect去創造closure將val1所在function裏面
2. return一個物件，這個物件中有兩個方法，`toBe`, `notToBe`
3. 有問題是，為什麼`return true`會等於 `{"value":true}`


Day 4 :2665. Counter II
```javascript=
/**
 * @param {integer} init
 * @return { increment: Function, decrement: Function, reset: Function }
 */
var createCounter = function(init) {
    let value = init
    return {
        increment:()=>{
            value += 1
            return value
        },
        reset:()=>{
            value = init
            return value
        },
        decrement:()=>{
            value -= 1
            return value
        },
    }
};

/**
 * const counter = createCounter(5)
 * counter.increment(); // 6
 * counter.reset(); // 5
 * counter.decrement(); // 4
 */
```

## 2621. Sleep
Given a positive integer millis, write an asynchronous function that sleeps for millis milliseconds. It can resolve any value.

```javascript=
/**
 * @param {number} millis
 */
async function sleep(millis) {
    await new Promise((res) => {
        setTimeout(res, millis)
    })
}
```
### 心得
1. 不需要賦予值。
2. resolve只是一個method所以不一定要放參數。
3. 如果不放`await`的話就會馬上結束?並不正確

```javascript=
/**
 * @param {number} millis
 */
async function sleep(millis) {
    return new Promise((res) => {
        setTimeout(res, millis)
    })
}
```
在這裡有沒有加上return很重要，因為如果用`await`會等待Promise結束之後才會繼續進行下去（有block的感覺），如果單純使用promise，就會需要return，因為要return result必須要等待promise call resolve所以會等待Promise結束。

## 2715. Timeout Cancellation
```javascript=
/**
 * @param {Function} fn
 * @param {Array} args
 * @param {number} t
 * @return {Function}
 */
var cancellable = function (fn, args, t) {
    const timer = setTimeout(() => {
        fn(...args)
    }, t)
    const cancelFn = () => {
        clearTimeout(timer)
    }
    return cancelFn
};

```

目的是要回傳 cancelFn ，當這個fn被觸發的話可以提早的結束這個function。


## 2637. Promise Time Limit

Given an asynchronous function fn and a time t in milliseconds, return a new time limited version of the input function. fn takes arguments provided to the time limited function.

The time limited function should follow these rules:

1. If the fn completes within the time limit of t milliseconds, the time limited function should resolve with the result.
2. If the execution of the fn exceeds the time limit, the time limited function should reject with the string "Time Limit Exceeded".


```javascript=
/**
 * @param {Function} fn
 * @param {number} t
 * @return {Function}
 */
var timeLimit = function (fn, t) {
    return async function (...args) {
        // 原本的promise 
        const originalPromise = fn(...args)
        
        //  計算timeout準備reject的Promise
        
        const timeoutPromise = new Promise((_, reject) => {
            setTimeout(() => {
                reject('Time Limit Exceeded')
            }, t)
        })

        // Promise.race 可以比較誰最快，並且回傳較快解析出來的result
        return Promise.race([originalPromise, timeoutPromise])
    }
};

/**
 * const limited = timeLimit((t) => new Promise(res => setTimeout(res, t)), 100);
 * limited(150).catch(console.log) // "Time Limit Exceeded" at t=100ms
 */
```
這裡忘記可以使用`Promise.race`，可以比較出誰最快。



## 2622. Cache With Time Limit

```javascript=
class TimeLimitedCache {
    constructor() {
        this.cache = new Map()
    }
};

/** 
 * @param {number} key
 * @param {number} value
 * @param {number} duration time until expiration in ms
 * @return {boolean} if un-expired key already existed
 */
TimeLimitedCache.prototype.set = function (key, value, duration) {
    let cached = this.cache.has(key) 
    if (cached) return clearTimeout(this.cache.get(key).ref)
    this.cache.set(key, {
        value,
        ref: setTimeout(() => this.cache.delete(key), duration)
    })
    return cached
};

/** 
 * @param {number} key
 * @return {number} value associated with key
 */
TimeLimitedCache.prototype.get = function (key) {
    return this.cache.has(key) ? this.cache.get(key).value : -1
};

/** 
 * @return {number} count of non-expired keys
 */
TimeLimitedCache.prototype.count = function () {
    return this.cache.size
};

/**
 * Your TimeLimitedCache object will be instantiated and called as such:
 * var obj = new TimeLimitedCache()
 * obj.set(1, 42, 1000); // false
 * obj.get(1) // 42
 * obj.count() // 1
 */
```