# util
* `[Doc]` URL
* `[Doc]` Query Strings (查詢字符串)
* `[Doc]` Utilities (實用函數)
* `[Basic]` 正則表達式
## URL
```javascript
┌─────────────────────────────────────────────────────────────────────────────┐
│ href │
├──────────┬┬───────────┬─────────────────┬───────────────────────────┬───────┤
│ protocol ││ auth │ host │ path │ hash │
│ ││ ├──────────┬──────┼──────────┬────────────────┤ │
│ ││ │ hostname │ port │ pathname │ search │ │
│ ││ │ │ │ ├─┬──────────────┤ │
│ ││ │ │ │ │ │ query │ │
" http: // user:pass @ host.com : 8080 /p/a/t/h ? query=string #hash "
│ ││ │ │ │ │ │ │ │
└──────────┴┴───────────┴──────────┴──────┴──────────┴─┴──────────────┴───────┘
```
### 轉義字符
常見的需要轉移的字符列表:
|字符|encodeURI|
|---|---|
|`' '`|`'%20'`|
|`<`|`'%3C'`|
|`>`|`'%3E'`|
|`"`|`'%22'`|
|```|`'%60'`|
|`\r`|`'%0D'`|
|`\n`|`'%0A'`|
|`\t`|`'%09'`|
|`{`|`'%7B'`|
|`}`|`'%7D'`|
|`|`|`'%7C'`|
|`\\`|`'%5C'`|
|`^`|`'%5E'`|
|`'`|'%27'|
想了解更多? 你可以這樣:
```javascript
Array(range).fill(0)
.map((_, i) => String.fromCharCode(i))
.map(encodeURI)
```
range 先來個 255 試試 (doge
## Query Strings
query string 屬于 URL 的一部分, 見上方 URL 的表. 在 Node.js 中有內置提供一個 `querystring` 的模塊.
|方法|描述|
|---|---|
|.parse(str[, sep[, eq[, options]]])|將一個 query string 解析為 json 對象|
|.unescape(str)|供 .parse 調用的內置解轉義方法, 暴露出來以供用戶自行替代|
|.stringify(obj[, sep[, eq[, options]]])|將一個 json 對象轉換成 query string|
|.escape(str)|供 .stringify 調用的內置轉義方法, 暴露出來以供用戶自行替代|
Node.js 內置的 querystring 目前對于有深度的結構尚不支持. 見如下:
```javascript
const qs = require('qs'); // 第三方
const querystring = require('querystring'); // Node.js 內置
let obj = { a: { b: { c: 1 } } };
console.log(qs.stringify(obj)); // 'a%5Bb%5D%5Bc%5D=1'
console.log(querystring.stringify(obj)); // 'a='
let str = 'a%5Bb%5D%5Bc%5D=1';
console.log(qs.parse(str)); // { a: { b: { c: '1' } } }
console.log(querystring.parse(str)); // { 'a[b][c]': '1' }
```
> <a name="q-get-param"></a> HTTP 如何通過 GET 方法 (URL) 傳遞 let arr = [1,2,3,4] 給服務器?
```javascript
const qs = require('qs');
let arr = [1,2,3,4];
let str = qs.stringify({arr});
console.log(str); // arr%5B0%5D=1&arr%5B1%5D=2&arr%5B2%5D=3&arr%5B3%5D=4
console.log(decodeURI(str)); // 'arr[0]=1&arr[1]=2&arr[2]=3&arr[3]=4'
console.log(qs.parse(str)); // { arr: [ '1', '2', '3', '4' ] }
```
通過 `https://your.host/api/?arr[0]=1&arr[1]=2&arr[2]=3&arr[3]=4` 即可傳遞把 arr 數組傳遞給服務器
## util
util.is*() 從 v4.0.0 開始被不建議使用即將廢棄 (deprecated). 大概的廢棄原因, 筆者個人認為是維護這些功能吃力不討好, 而且現在流行的輪子那么多. 那么一下是具體列表:
* util.debug(string)
* util.error([...strings])
* util.isArray(object)
* util.isBoolean(object)
* util.isBuffer(object)
* util.isDate(object)
* util.isError(object)
* util.isFunction(object)
* util.isNull(object)
* util.isNullOrUndefined(object)
* util.isNumber(object)
* util.isObject(object)
* util.isPrimitive(object)
* util.isRegExp(object)
* util.isString(object)
* util.isSymbol(object)
* util.isUndefined(object)
* util.log(string)
* util.print([...strings])
* util.puts([...strings])
* util._extend(target, source)
其中大部分都可以作為面試題來問如何實現.
### util.inherits
> Node.js 中繼承 (util.inherits) 的實現?
https://github.com/nodejs/node/blob/v7.6.0/lib/util.js#L960
```javascript
/**
* Inherit the prototype methods from one constructor into another.
*
* The Function.prototype.inherits from lang.js rewritten as a standalone
* function (not on Function.prototype). NOTE: If this file is to be loaded
* during bootstrapping this function needs to be rewritten using some native
* functions as prototype setup using normal JavaScript does not work as
* expected during bootstrapping (see mirror.js in r114903).
*
* @param {function} ctor Constructor function which needs to inherit the
* prototype.
* @param {function} superCtor Constructor function to inherit prototype from.
* @throws {TypeError} Will error if either constructor is null, or if
* the super constructor lacks a prototype.
*/
exports.inherits = function(ctor, superCtor) {
if (ctor === undefined || ctor === null)
throw new TypeError('The constructor to "inherits" must not be ' +
'null or undefined');
if (superCtor === undefined || superCtor === null)
throw new TypeError('The super constructor to "inherits" must not ' +
'be null or undefined');
if (superCtor.prototype === undefined)
throw new TypeError('The super constructor to "inherits" must ' +
'have a prototype');
ctor.super_ = superCtor;
Object.setPrototypeOf(ctor.prototype, superCtor.prototype);
};
```
## 正則表達式
正則表達式最早生物學上用來描述大腦神經元的一種表達式, 被 GNU 的大胡子拿來做字符串匹配之后在原本的道路上漸行漸遠.
整理中..
## 常用模塊
[Awesome Node.js](https://github.com/sindresorhus/awesome-nodejs)
[Most depended-upon packages](https://www.npmjs.com/browse/depended)
> <a name="q-traversal"></a> 如何獲取某個文件夾下所有的文件名?
一個簡單的例子:
```javascript
const fs = require('fs');
const path = require('path');
function traversal(dir) {
let res = []
for (let item of fs.readdirSync(dir)) {
let filepath = path.join(dir, item);
try {
let fd = fs.openSync(filepath, 'r');
let flag = fs.fstatSync(fd).isDirectory();
fs.close(fd); // TODO
if (flag) {
res.push(...traversal(filepath));
} else {
res.push(filepath);
}
} catch(err) {
if (err.code === 'ENOENT' && // link 文件打不開
!!fs.readlinkSync(filepath)) { // 判斷是否 link 文件
res.push(filepath);
} else {
console.error('err', err);
}
}
}
return res.map((file) => path.basename(file));
}
console.log(traversal('.'));
```
當然也可以 Oh my [glob](https://github.com/isaacs/node-glob):
```javascript
const glob = require("glob");
glob("**/*.js", (err, files) {
if (err) {
throw new Error(err);
}
console.log('Here you are:', files.map(path.basename));
});
```