---
# System prepended metadata

title: TreeHouse JS

---

# TreeHouse JS
## JS with DOM
[difference between htmlcollection and nodelist](https://dev.to/jharteaga/difference-between-htmlcollection-and-nodelist-25bp)
![](https://i.imgur.com/uM1D6Ja.png)
[event lists](https://developer.mozilla.org/en-US/docs/Web/Events#event_listing) | [在哪設eventHandler](https://javascript.info/bubbling-and-capturing) | [事件委托](https://javascript.info/event-delegation) | [Event](https://developer.mozilla.org/en-US/docs/Web/API/Event) object,常用來觀察事件目標:
```
document.addEventListener('click' , (e) => {
    console.log(e.target); //用來觀察事件觸發的目標是誰
});
```
### Linters & Validators:
[Linters in Visual Studio Code](https://code.visualstudio.com/docs/languages/javascript#_linters) | [Beautify Tools : JavaScript Validator](https://beautifytools.com/javascript-validator.php)
### JSdocs
[JSdocs](https://jsdoc.app/index.html) | [JSdocs cheat sheet](https://devhints.io/jsdoc) | [VScode plug-in](https://code.visualstudio.com/docs/languages/javascript#_jsdoc-support)
## Asynchronous
### How it works
[MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop) | [Visualize Demo](http://latentflip.com/loupe/?code=JC5vbignYnV0dG9uJywgJ2NsaWNrJywgZnVuY3Rpb24gb25DbGljaygpIHsKICAgIHNldFRpbWVvdXQoZnVuY3Rpb24gdGltZXIoKSB7CiAgICAgICAgY29uc29sZS5sb2coJ1lvdSBjbGlja2VkIHRoZSBidXR0b24hJyk7ICAgIAogICAgfSwgMjAwMCk7Cn0pOwoKY29uc29sZS5sb2coIkhpISIpOwoKc2V0VGltZW91dChmdW5jdGlvbiB0aW1lb3V0KCkgewogICAgY29uc29sZS5sb2coIkNsaWNrIHRoZSBidXR0b24hIik7Cn0sIDUwMDApOwoKY29uc29sZS5sb2coIldlbGNvbWUgdG8gbG91cGUuIik7!!!PGJ1dHRvbj5DbGljayBtZSE8L2J1dHRvbj4%3D)
![](https://i.imgur.com/lQCwrg4.gif)
```
function func3() {
  console.log('Students!');
}

function func2() {
  console.log('Treehouse');
}

function func1() {
  console.log('Hi');
  setTimeout(func2, 1000)
  func3();
}

func1();

// Hi
// Students!
// Treehouse
```
#### event loop
![](https://i.imgur.com/4NDBGyH.gif)
### Callback Functions
1. DOM Events
```
btn.addEventListener('click', () => {
  // Perform some action on click inside this callback
  console.log('I was clicked!');
});
```
2. Iteration methods
```
map()
const capitalizedFruits = fruits.map( fruit => fruit.toUpperCase() );

filter()
const sNames = names.filter( name => {
  return name.charAt(0) === 'S';
});

forEach()
fruits.forEach( fruit => console.log(fruit) );
```
3. Continuation-passing style (CPS) (callback hell)
```
function add(x, y, callback) {
  callback(x + y)
}
function subtract(x, y, callback) {
  callback(x - y);
}
function multiply(x, y, callback) {
  callback(x * y);
}
function calculate(x, callback) {
  callback(x);
}

calculate(5, (n) => {
  add(n, 10, (n) => {
    subtract(n, 2, (n) => {
      multiply(n, 5, (n) => {
        console.log(n); // 65
      });
    });
  });
});
```
#### return callback() vs. only callback()
using `return` to ensure that execution in the current scope does not continue past invoking `callback(data)`. This might prevent multiple callbacks from being accidentally invoked
#### (legacy)用API1的資料改網址抓API2的資料例(wiki)
```
const astrosUrl = 'http://api.open-notify.org/astros.json';
const wikiUrl = 'https://en.wikipedia.org/api/rest_v1/page/summary/';

function getJSON(url, callback) {...};
function generateHTML() {...};

getJSON(astrosUrl, (json) =>{    //用astroUrl先抓取所有太空人資料(array of objects)
    json.people.map(person =>{    //物件取出太空人資料,再map array
      getJSON(wikiUrl + person.name, generateHTML);    //wikiUrl網址直接加上人名來抓取wikiAPI的資料
    });
  });
```
## [非同步函示](https://www.casper.tw/development/2020/10/16/async-await/) | [瀏覽器處理非同步的原理](https://www.freecodecamp.org/news/javascript-asynchronous-operations-in-the-browser/)
### promises
A promise is a regular **JavaScript object** that changes from a *pending state* to either a *fulfilled* or *rejected* state
* methods
**then()**: status changes to resolved
**catch()**: status changes to rejected *(It's best to specify a rejection reason and call catch() on a promise – if you don’t, the promise will silently fail)*

You can pass *then* and *catch* references to named functions.
* Promise Chaining
Remember: `.then()` itself always **returns a new promise**. By chaining multiple thens together, you can transform values or run additional async operations one after another.
```
function addFive(n) {
  return n + 5;
}
function double(n) {
  return n * 2;
}
function finalValue(nextValue) {
  console.log(`The final value is ${nextValue}`);
}

const mathPromise = new Promise( (resolve, reject) => {
  setTimeout( () => {
    // resolve promise if 'value' is a number; otherwise, reject it
    if (typeof value === 'number') {
      resolve(value);
    } else {
      reject('You must specify a number as the value.')
    }
  }, 1000);
});

const value = 5;
mathPromise
  .then(addFive)
  .then(double)
  .then(addFive) // called twice
  .then(finalValue)
  .catch( err => console.log(err) )

// The final value is 25
```
#### Promise.all()
an efficient way to fire off and keep track of multiple asynchronous operations with this **method**. `Promise.all` is useful when your program needs to wait for more than one promise to resolve.(只要有一個request錯就會回傳catch, all or nothing)
#### finally()
It gets called once a promise is fully settled, regardless of whether it's fulfilled or rejected. Finally is useful when you need to do some clean up after the promise sequence finished.
### Fetch
現代抓api方法, `fetch()` returns a  `Promise` that resolves to a `Response` object.
```
 fetch('api位址')    //從網址抓取資料
    .then( response => response.json() )    //轉化資料格式為json
    .then.....
```
(legacy)直接取代以下抓取資料功能
```
//以下可被fetch()取代

function getJSON(url) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open('GET', url);
    xhr.onload = () => {
      if(xhr.status === 200) {
        let data = JSON.parse(xhr.responseText);
        resolve(data);
      } else {
        reject( Error(xhr.statusText) );
      }
    };
    xhr.onerror = () => reject( Error('A network error occurred') );
    xhr.send();
  });
}
```
### Async/Await
Async/await is a supplement [syntactic sugar](https://javascript.info/async-await) to `Promise` for creating functions that return and wait for promises.
#### Examples of async/await patterns
```
// Anonymous async function
(async function() {
  const response = await fetch('...');
})();

// Async function assignment
const getData = async function() {
  const response = await fetch('...');
};

// Arrow functions
const getData = async () => {
  const response = await fetch('...');
};

// Async Function as an argument
btn.addEventListener('click', async () => {
  const response = await fetch('...');
});
```
#### try...catch
try...catch is the most common way to handle exceptions when using async/await.
```
async function getJSON(url) {
  try {
    const response = await fetch(url);    //抓資料
    return await response.json();    //將資料轉為json格式
  } catch (error) {    //錯誤處理
    throw error;
  }
}
```
[throw](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/throw)
#### Using `try...catch` and `async/await` to handle errors in the event listener:
```
btn.addEventListener('click', async (event) => {
  event.target.textContent = 'Loading...';
  try {
    const astros = await getPeopleInSpace(astrosUrl);
    generateHTML(astros);
  } catch(e) {
    peopleList.innerHTML = '<h3>Something went wrong!</h3>';
    console.error(e);    
  } finally {
    event.target.remove();
  }
});
```
## Fetch API
前置觀念: promise / http
(通常瀏覽器有內建)[Fetch polyfill](https://github.com/github/fetch) | [Sending cookies with fetch()](https://github.com/github/fetch#sending-cookies) | [Response methods](https://developer.mozilla.org/en-US/docs/Web/API/Response#Methods) | [Sending a request with credentials included](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#sending_a_request_with_credentials_included)
```
fetch('https://api.com/api')
```
`fetch()` returns a  `Promise` that resolves to a `Response` object.
#### reuseable data fetching function
```
function fetchData(url){
    return fetch(url)
            .then(checkStatus)    //用HELPER FUNCTIONS檢查response status
            .then(res => res.json())    //轉json格式
            .catch(error => console.log('Something went wrong!',error))    //出錯處理
}

Promise.all([    //等到複數筆資料成功抓回才一起回傳
  fetchData('API1'),
  fetchData('API2')  
])
.then(data => {    //回傳的是一個array, with兩個response objects
  const dataForFunc1 = data[0].message;
  const dataForFunc2 = data[1].message;
  
  func1(dataForFunc1);    //使用回傳資料
  func2(dataForFunc2);
})

//  HELPER FUNCTIONS
function func1(data){...};
function func2(data){...};

function checkStatus(response) {    //檢查response status的function
  if (response.ok) {
    return Promise.resolve(response);
  } else {
    return Promise.reject(new Error(response.statusText));    //抓response status
  }
}
```
#### another way to compose promises with `fetch()` and `Promise.all`
```
// store urls to fetch in an array
const urls = [
  'https://dog.ceo/api/breeds/list',
  'https://dog.ceo/api/breeds/image/random'
];

// use map() to perform a fetch and handle the response for each url
Promise.all(urls.map(url =>
  fetch(url)
    .then(checkStatus)                 
    .then(parseJSON)
    .catch(logError)
))
.then(data => {
  // do something with the data
})
```
#### Posting Data with `fetch()`
[JSONPlaceholder API](https://jsonplaceholder.typicode.com/)
```
form.addEventListener('submit', postData);

function postData(e) {
  e.preventDefault();
  const name = document.getElementById('name').value;
  const comment = document.getElementById('comment').value;
  
  const config = {    //*request config設定,放入fetch第二個參數
    method: 'POST',    //request method都要大寫
    headers: {
      'Content-Type': 'application/json'    //json格式
    },
    body: JSON.stringify({ name, comment })    //轉成json string, ES2015{name: name, comment:comment}key-value若相同則可以縮寫
  }
  
  fetch('https://jsonplaceholder.typicode.com/comments', config)    //*重點 fetch('api', {request config}) 第二個參數可放request config設定
    .then(checkStatus)
    .then(res => res.json())
    .then(data => console.log(data))
}

```
## Callback
a function passed into another function as a parameter

主要用途:
* One off and repeating timers
* Triggered by a user interaction
* Loading data from a server using AJAX
* Opening files in Node.js

```
const callbackFunction = function(){
//Do something
}

function executeCallback(callback){
//Do something
}

executeCallback(callbackFunction);    //注意callbackFunction不加(),把callbaclFunction當成var來使用

======

function executeCallback(() => {});    //anonumous callback functions,注意在{}後不能放';'
```
* `setTimeout(callback, delay)`: delay執行一次
* `setInterval(callback, delay)`: delay執行好多次,第一次也會delay執行,所以如果需要第一次立即執行則不適合用anonumous callback
#### event handler
把callback用在Async event-base programming
event handler有一個argument: event object
```
function(event){
    //Do something
}

=== or ===

event => {
    //Do something
}
```
![](https://i.imgur.com/0Viw975.png)
* **event object**: use the same callback for multiple types of events or elements.
`event.type`: what type of event triggered the callback
---`'focus'`: 被click或是tab選到
---`'blur'`: 沒被選到
`event.target`: the element that event was triggered on
## Array iteration Methods
Array: List-like Object
#### `forEach()`
* bugs easier to avoid:
--- Infinite loops impossible
--- Avoids incrementing mistakes
--- Wrong contition
* cons:
--- Can't breakout early (use **For** or **While** instead)
```
array.forEach(function callback(currentValue [, index][, array]){
    //your iterator
}[,thisArg]);
```
#### [`filter()`]
Doesn't infect the origin array, returns a filted new array.
```
//過濾掉開頭不是大寫'S'的名字
const newArray = array.filter(name => name.charAt(0) === 'S');
```
* Removing Duplicates from an Array
This works because the indexOf method will return the index of the first occurrence that is found in the array.
```
const numbers = [1, 1, 2, 3, 4, 3, 5, 5, 6, 7, 3, 8, 9, 10];

const unique = numbers.filter(function(number, index, array) {
  return index === array.indexOf(number);
});

console.log(unique); // => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
```
#### [`map()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map)
Doesn't infect the origin array, returns a mapped new array with same amount of item.
#### [`reduce()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce)
Use values of an array and return a single value.
```
const result = arr.reduce((acc, cur) => { /* … */ }, initValue)    //如果沒給initialValue,會直接拿arr[0]當成initialValue
```
--- accumulator: 購物車
--- currentValue: arr裡的item
--- initialValue: accumulator起始值
* Array Flattening
```
//use spread operator
const flatArr = arr
    .reduce((flatArr, innerArr) => [...flatArr, ...innerArr], []);

//use arr.concat method
const flatArr = arr
    .reduce((flatArr, innerArr) => flatArr.concat(innerArr), []);
```
### Chaining Array Methods
[How numbers work in JavaScript](https://www.youtube.com/watch?v=MqHDDtVYJRI): 如果result有很多小數點,可以用resault.toFixed(2)來抓取小數點後兩位
* Combine `filter()` and `map()`: to clean an array of unwanted values before transforming the leftover items.
* Combine `filter()` with `reduce()`:   remove values from an array, using the results to compute some value.
* Combine `map()` with `reduce` for advanced array problems:
```
const users = [
  {
    name: 'Samir',
    age: 27,
    favoriteBooks:[
      {title: 'The Iliad'},
      {title: 'The Brothers Karamazov'}
    ]
  },
  {
    name: 'Angela',
    age: 33,
    favoriteBooks:[
      {title: 'Tenth of December'},
      {title: 'Cloud Atlas'},
      {title: 'One Hundred Years of Solitude'}
    ]
  },
  {
    name: 'Beatrice',
    age: 42,
    favoriteBooks:[
      {title: 'Candide'}
    ]
  }
];

    // Result: ['The Iliad', 'The Brothers Karamazov', 'Tenth of December', 'Cloud Atlas', 'One Hundred Years of Solitude', 'Candide'];
```
```
const books = users
    .map(user => user.favoriteBooks.map(book => book.title))
    .reduce((arr, titles) => [ ...arr, ...titles ], []);
```