JavaScript
===
###### tags: `JavaScript`
###### tags: `JavaScript`, `frontend`, `backend`
:::success
:bulb: [**[github] javascript-study**](https://github.com/tsungjung411/javascript-study)
:::
<br>
[TOC]
<br>
## Tutorial
### W3school
- [JavaScript](https://www.w3schools.com/js)
- [JavaScript Reference](https://www.w3schools.com/jsref)
<br>
## 運算子
### Nullish coalescing Operator 空值合併運算子 ??
> 關鍵字:JavaScript, JS, TypeScript, TS, operator, double question mark, ??, Nullish coalescing Operator, 空值合併運算子
> doc:
> - [使用空值合併運算子](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Operators/Optional_chaining#使用空值合併運算子)
> - [Nullish coalescing operator (??)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator)
```javascript
> x=100
< 100
> y=undefined
< undefined
> z=null
< null
> x ?? 123
< 100
> y ?? 123
< 123
> z ?? 123
< 123
```
- 簡單講:如果不是空值,就直接拿來用,否則使用 default
```
f = (x, def) => x ? x : def;
f(x, 123);
f(y, 123);
f(z, 123);
```
<br>
<hr>
<br>
## async & await, Promise
### MDN Web Docs (mozilla)
- [async function](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Statements/async_function)
### test1: resolved
```javascript==
new Promise((x, y)=>{
console.log('x:', x);
console.log('y:', y);
x();
}).then(()=> {
console.log('succeeded');
}).catch(() => {
console.log('failed');
})
```

### test2: rejected
```javascript==
new Promise((x, y)=>{
console.log('x:', x);
console.log('y:', y);
y();
}).then(()=> {
console.log('succeeded');
}).catch(() => {
console.log('failed');
})
```

### 待消化
- [[Javascript]非同步的救星Promise](http://mis101bird.js.org/promise/)
- [[JavaScript] 一次搞懂同步與非同步的一切:待會叫你 — 回呼函式(Callback Function)]([0](https://medium.com/itsems-frontend/javascript-callback-function-993abc2c0b42))
<br>
<hr>
<br>
## 字串
### 格式化
- ### 使用 `${xxx}`
測試:
```javascript=
var name = 'John'
`Hello, ${name}`
```
執行結果:
```
Hello, John
```
- ### 實作 prototype
```javascript=
String.prototype.format = function() {
var args = arguments;
console.log('args:', args);
console.log('string:', this);
return this.replace(/{(\d+)}/g, function(match, number) {
console.log('matcher:', match, number);
return args[number]??match;
});
};
```
測試:
`'[[x={0} y={1} ?={3} z={2} ?={10} y={1} x={0} ]]'.format('x' ,'y', 'z')`
執行結果:

- ### [JavaScript: 如何使用 format 格式化字符串](https://www.letianbiji.com/web-front-end/js-string-format.html)
定義 prototype:
```javascript==
String.prototype.format = function() {
var args = arguments;
var formated = this;
for (var idx in args) {
//console.log(idx, args[idx]);
formated = formated.replaceAll('{' + idx + '}', args[idx]);
}
return formated;
}
```
測試:
```
'{1} {0} {0} {1}'.format('x', 'y')
```
執行結果:
```
'y x x y'
```
### 子字串
- ### [js字串擷取函式slice、substring和substr的比較](https://codertw.com/%E5%89%8D%E7%AB%AF%E9%96%8B%E7%99%BC/266378/)
- `slice(start,[end])`
行為同 java.substring, 以及可允許 負索引
- `substring(start,[end])`
行為同 java.substring, 但負索引皆被修正為 0
- `substr(start,[length])`
可允許 負索引
<br>
<hr>
<br>
## RegExp
### W3school
- [JavaScript RegExp g Modifier](https://www.w3schools.com/jsref/jsref_regexp_g.asp)
- `g`: A global match finds all matches (compared to only the first).
<br>
<hr>
<br>
## DOM (Document Object Model)
### img
```typescript=
const img = document.createElement('img');
img.src = 'https://edge.aif.tw/content/images/2020/10/EDGE2.png';
img.setAttribute('width', '100%');
img.setAttribute('style','margin: 1em;');
console.log(img);
```

- [[MDN Web Docs] HTMLImageElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement)
<br>
### ul+li
```typescript=
const ul = document.createElement('ul');
let li;
li = document.createElement('li');
li.innerHTML = 'abc';
ul.appendChild(li);
li = document.createElement('li');
li.appendChild(document.createTextNode('xyz'))
ul.appendChild(li);
console.log(ul);
```

- [[MDN Web Docs] HTMLUListElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement)
- [[MDN Web Docs] HTMLLIElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement)
<br>
<hr>
<br>
## JavaScript 特殊性質
### Curry
- ### [第 4 章:Curry(柯里化)](https://jigsawye.gitbooks.io/mostly-adequate-guide/content/ch4.html)
### call / apply / bind
- ### [JavaScript - call,apply,bind](https://ithelp.ithome.com.tw/articles/10195896)
- call 和 apply 差別
- call: 一個一個代入參數
- apply: 使用 array 代入
### closure
- ### [JavaScript - Closure (1)](https://ithelp.ithome.com.tw/articles/10195343)
<br>
<hr>
<br>
## Operations
### iterate object
> iterating key/value pairs
- [How to Iterate through an object keys and values in JavaScript](https://attacomsian.com/blog/javascript-iterate-objects)
### remove all children
- [Remove all child elements of a DOM node in JavaScript](https://stackoverflow.com/questions/3955229)
### is integer
- [Check if character is number?](https://stackoverflow.com/questions/8935632)
### [Array](https://www.w3schools.com/jsref/jsref_obj_array.asp)
- ### [JavaScript Array.from()](https://www.w3schools.com/jsref/jsref_from.asp)
- Case1
```javascript=
Array.from("ABCDEFG")
```
執行結果:
```
(7) ['A', 'B', 'C', 'D', 'E', 'F', 'G']
```
- Case2: [從 arguments 型別轉成 array](https://ithelp.ithome.com.tw/articles/10195896)
```javascript=
call1 = () => console.log(arguments)
call1()
// Uncaught ReferenceError: arguments is not defined
call2 = function() {
console.log(arguments);
console.log('arguments.reduce:', arguments.reduce);
console.log('array.reduce:', Array.from(arguments).reduce);
}
call2(1,2,3)
```
執行結果:
```
Arguments(3) [1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ]
arguments.reduce: undefined
array.reduce: ƒ reduce() { [native code] }
```
- ### [JavaScript Array includes()](https://www.w3schools.com/jsref/jsref_includes_array.asp)
- includes 類似於 `indexOf(searchElement, fromIndex)`
- ### [JavaScript Array reduce()](https://www.w3schools.com/jsref/jsref_reduce.asp)
- 就是彙整所有資訊,類似於 aggregate 概念
```javascript=
x = [1, 2, 3, 4]
x.reduce((total, num) => {
console.log(`total=${total} + num=${num}`);
return total + num;
}, 100)
```
```
total=100 + num=1
total=101 + num=2
total=103 + num=3
total=106 + num=4
110
```
### encode / decode, escape / unescape
- [try](https://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_encodeuri)

```html=
<!DOCTYPE html>
<html>
<body>
<h1>JavaScript Global Methods</h1>
<h2>The encodeURI() Method</h2>
<p id="demo1"></p>
<p id="demo2"></p>
<p id="demo3"></p>
<p id="demo4"></p>
<p id="demo5"></p>
<p id="demo6"></p>
<script>
let uri = "my test.asp?name=ståle&car=saab";
let encoded = encodeURI(uri);
document.getElementById("demo1").innerHTML = encodeURI(uri);
document.getElementById("demo2").innerHTML = encodeURIComponent(uri);
document.getElementById("demo3").innerHTML = escape(uri);
document.getElementById("demo4").innerHTML = decodeURI(encodeURI(uri));
document.getElementById("demo5").innerHTML = decodeURIComponent(encodeURIComponent(uri));
document.getElementById("demo6").innerHTML = unescape(escape(uri));
</script>
</body>
</html>
```
- [`escape()`](https://www.w3schools.com/jsref/jsref_escape.asp) :warning: deprecated
Use [encodeURI()](https://www.w3schools.com/jsref/jsref_encodeuri.asp) or [encodeURIComponent()](https://www.w3schools.com/jsref/jsref_encodeuricomponent.asp) instead.
### fetch
- [[MDN] Response](https://developer.mozilla.org/en-US/docs/Web/API/Response)
- status: the status code
- statusText: the status message
<br>
### throw new Error
- ### Question
在 js 中,想要 throw new Error()
但要攜帶 msg='Network response was not ok!', status_code=response.status
在 catch 之後要取出 msg & status_code
- ### ChatGPT4
在 JavaScript 中,`Error` 物件通常只帶有一個 `message` 屬性。 如果你想要附加額外的數據,例如一個狀態碼,你可以擴展 `Error` 對象,或者在拋出錯誤時直接附加額外的屬性。 以下是兩種方法:
- ### 方法 1: 擴展 `Error` 對象
你可以建立一個自訂的錯誤類,包含 message 和 statusCode:
```javascript=
class NetworkError extends Error {
constructor(message, statusCode) {
super(message);
this.statusCode = statusCode;
}
}
// 使用自訂的錯誤類
fetch(`${apiUrl}/list_model`)
.then(response => {
if (!response.ok) {
throw new NetworkError('Network response was not ok!', response.status);
}
return response.json();
})
.catch(error => {
console.log(error.message); // "Network response was not ok!"
console.log(error.statusCode); // 狀態碼,例如 404 或 500
});
```
- ### 方法 2: 在拋出時附加屬性
如果你不想創建一個新的類,你也可以簡單地為 Error 物件添加屬性:
```javascript=
fetch(`${apiUrl}/list_model`)
.then(response => {
if (!response.ok) {
const error = new Error('Network response was not ok!');
error.statusCode = response.status;
throw error;
}
return response.json();
})
.catch(error => {
console.log(error.message); // "Network response was not ok!"
console.log(error.statusCode); // 狀態碼,例如 404 或 500
});
```
<br>
### store data
- [How to store data in the DOM ?](https://www.geeksforgeeks.org/how-to-store-data-in-the-dom/)
> 關鍵字:html dom store data
<br>
<hr>
<br>
## fecth
### POST with json data
```javascript
const url = "https://www.prisma-gene.com.tw/User/UsageLimits";
const data = {
ApiUserId: "your_api_user_id",
ApiUserKey: "your_user_key",
Name: "your_name"
};
fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error));
```
<br>
### stream
```javascript=
const url = 'http://10.78.26.241:83/api/models/generate';
const data = {
model: 'llama2-7b-chat-0821-ft',
inputs: 'Hello~',
parameters: {'max_new_tokens': 100},
stream: true,
};
fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
})
.then(response => {
// 檢查 HTTP 狀態碼
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
// 開始以流的方式處理數據
const reader = response.body.getReader();
// 定義 TextDecoder
const textDecoder = new TextDecoder();
// 開始讀取數據
return reader.read().then(function processResult(result) {
// 檢查是否已讀取完畢
if (result.done) {
console.log('Stream ended');
return;
}
// 將二進制數據轉換為字符串
var chunk = textDecoder.decode(result.value);
chunk = chunk.substr(6);
chunk = JSON.parse(chunk)
console.log('Received chunk:', chunk["generated_text"]);
// 繼續讀取下一個數據块
return reader.read().then(processResult);
});
})
.catch(error => console.error('Error:', error));
```
<br>
<hr>
<br>
## script
### 範例1:打 request
```javascript=
console.log('Hello, World!');
const url = 'http://10.78.26.241:30080/completion';
const data = {
n_predict: 20,
prompt: 'How are you?'
};
const headers = {
'Content-Type': 'application/json'
};
fetch(url, {
method: 'POST',
headers: headers,
body: JSON.stringify(data)
}).then(res => {
console.log('status_code: ' + res.status);
return res.json();
}).then(data => {
console.log('data: ', data);
}).catch(err => {
console.log('err:', err);
});
console.log('DONE!')
```
- 建立環境
```
$ conda create -n nodejs python=3.10 nodejs -y
$ node -v
v18.18.2
```
- 執行方式
```
$ node script.js
```
- 執行結果:
```json
Hello, World!
DONE!
status_code: 200
data: {
content: " How has your week been? I'm feeling pretty good today, but a bit tired. It'",
generation_settings: {
frequency_penalty: 0,
grammar: '',
ignore_eos: false,
logit_bias: [],
min_p: 0.05000000074505806,
mirostat: 0,
mirostat_eta: 0.10000000149011612,
mirostat_tau: 5,
model: '/home/***/LLM_Models/TheBloke/Llama-2-7b-Chat-GGUF/llama-2-7b-chat.Q4_K_M.gguf',
n_ctx: 2048,
n_keep: 0,
n_predict: 20,
n_probs: 0,
penalize_nl: true,
presence_penalty: 0,
repeat_last_n: 64,
repeat_penalty: 1.100000023841858,
seed: 4294967295,
stop: [],
stream: false,
temp: 0.800000011920929,
tfs_z: 1,
top_k: 40,
top_p: 0.949999988079071,
typical_p: 1
},
model: '/home/***/LLM_Models/TheBloke/Llama-2-7b-Chat-GGUF/llama-2-7b-chat.Q4_K_M.gguf',
prompt: 'How are you?',
slot_id: 2,
stop: true,
stopped_eos: false,
stopped_limit: true,
stopped_word: false,
stopping_word: '',
timings: {
predicted_ms: 622.838,
predicted_n: 20,
predicted_per_second: 32.111078643242706,
predicted_per_token_ms: 31.1419,
prompt_ms: 200.311,
prompt_n: 5,
prompt_per_second: 24.961185356770223,
prompt_per_token_ms: 40.062200000000004
},
tokens_cached: 25,
tokens_evaluated: 5,
tokens_predicted: 20,
truncated: false
}
```

<br>
### Q&A
- ### run script.js
- Question
`script.js` 這種檔案要如何在 ubuntu 執行?
- ChatGPT
要在 Ubuntu 上執行 JavaScript 檔案(例如 `script.js`),你需要安裝 Node.js。Node.js 是基於 Chrome V8 引擎的 JavaScript 執行時,它使你能夠在伺服器端執行 JavaScript。
以下是在 Ubuntu 上安裝 Node.js 並執行 JavaScript 檔案的步驟:
### 步驟 1:安裝 Node.js
打開終端機,執行以下命令安裝 Node.js:
```bash
sudo apt-get update
sudo apt-get install nodejs
```
這將安裝 Node.js 執行時。
### 步驟 2:安裝 npm(Node.js 套件管理器)
```bash
sudo apt-get install npm
```
### 步驟 3:建立並編輯 JavaScript 檔案
使用你喜歡的文字編輯器建立一個 JavaScript 檔案,例如 script.js。你可以使用命令列編輯器 nano:
```bash
nano script.js
```
在編輯器中,輸入你的 JavaScript 代碼,然後保存並退出。
### 步驟 4:執行 JavaScript 檔案
在終端機中,使用以下命令執行你的 JavaScript 檔案:
```bash
node script.js
```
這將執行 `script.js` 中的 JavaScript 代碼,並在終端機中顯示輸出。
請確保你的 JavaScript 代碼不依賴於瀏覽器環境,因為 Node.js 是在伺服器端執行 JavaScript,並沒有 DOM(文件物件模型)等瀏覽器相關的功能。如果你需要在瀏覽器中執行 JavaScript,你可以使用瀏覽器的開發者工具或將代碼嵌入到 HTML 頁面中。