# arr.containsSubarray()

{% tabs %}
{% tab title="💾 程式" %}
{% hint style="success" %}
💡 祕技：下面的 <mark style="color:blue;">`valueIsInArraySequentially`</mark> 用了一個內含參數 <mark style="color:yellow;">`i`</mark> 的 <mark style="color:yellow;">**closure**</mark>，讓每次測試「一個值是否在陣列中」，都從<mark style="color:yellow;">新的位置</mark>開始搜尋：

```javascript
// ⭐️ 注意：函數的參數都是變數(var)
// intial value of `i` = 0  ￣￣￣￣￣￣⤵︎
(i => v => i = this.indexOf(v, i) + 1)(0)
```

簡直是太聰明了:thumbsup:
{% endhint %}

<img src="https://2527454625-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MfvEFZnSBhKT6fJmus0%2Fuploads%2FoxMMv5tnjZfqYle9ntHV%2Ffile.drawing.svg?alt=media&#x26;token=f50e2613-8837-4f6f-a710-70d37c4d25d9" alt="when calling array.containsSubarray(), this === array" class="gitbook-drawing">

* [replit](https://replit.com/@pegasusroe/array-contains-subarray#index.js)

```javascript
// 🔸 arr.containsSubarray()
Array.prototype.containsSubarray = function(subarray, orderIsRelevant=false) {
    
    // ⭐ closure with internal parameter `i`
    const valueIsInArraySequentially = (i => v => i = this.indexOf(v, i) + 1)(0);
    
    const valueIsInArray = (v => this.includes(v));
    const valuePassedTest = orderIsRelevant ? valueIsInArraySequentially : valueIsInArray;
    return subarray.every(valuePassedTest);
};
```

* valueIsInArraySequentially is equivalent to:

```javascript
// closure (with internal variable `startFromIndex`)
const valueInArraySequentially = (()=>{
    // internal variable in clusure
    let startFromIndex = 0;
    // when calling `array.containsSubarray()`, `this === array`
    return (value) => startFromIndex = this.indexOf(value, startFromIndex) + 1;
})();
```
{% endtab %}

{% tab title="💈範例" %}
💈範例：

{% hint style="danger" %}
⭐️ 注意：

當 <mark style="color:blue;">`orderIsRelevant`</mark> 參數設為 <mark style="color:red;">`false`</mark> (預設值)，<mark style="color:yellow;">重複的值</mark>(如下面<mark style="color:yellow;">第三例</mark>)不管重複幾次，都會被當作有在陣列中(<mark style="color:blue;">`valueIsInArray`</mark>)，依然會傳回 <mark style="color:green;">`true`</mark>❗️
{% endhint %}

```javascript
// test array
const array = [12, 44, 22, 66, 222, 777, 22, 22, 22, 6, 77, 3];

[
    // order is relevant: NO  | YES
    // -----------------------------------
    [777, 22, 22],    // true | true
    [777, 22, 3],     // true | true
    [77, 77],         // true | false (true when order is irrelevant❗duplicate values neglected)
    [22, 44],         // true | false (false when order is relevant ⭐)
    
].forEach(arr => 
    console.log(
        array.containsSubarray(arr),            // order is irrelevant
        array.containsSubarray(arr, true)       // order IS relevant
    )
)
```
{% endtab %}

{% tab title="🗣 討論" %}
* [Javascript array contains/includes sub array](https://stackoverflow.com/a/34152244/5409815) ⭐️
* [How to make function parameter constant in JavaScript?](https://stackoverflow.com/a/31745585/5409815)
{% endtab %}

{% tab title="📘 手冊" %}
* [Array.prototype.every()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every)
  * #### [Check if one array is a subset of another array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every#check_if_one_array_is_a_subset_of_another_array) <a href="#check_if_one_array_is_a_subset_of_another_array" id="check_if_one_array_is_a_subset_of_another_array"></a>
* [Array.prototype.indexOf()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf)
{% endtab %}

{% tab title="⬇️ 應用" %}
* [no-make-up-exam](../../../../../appendix/gas/projects/no-make-up-exam "mention")
* [class-average](../../../../../appendix/gas/projects/class-average "mention")
* [gas](../../../../../appendix/gas "mention") app [helpers](../../../../../appendix/gas/app/helpers "mention").
{% endtab %}

{% tab title="👥 相關" %}
* [tips](../../../../tips "mention")
* [arrow](../../../func/arrow "mention") <mark style="color:red;">**doesn't have**</mark> its own <mark style="color:blue;">`this`</mark>.
{% endtab %}
{% endtabs %}
