前言
上一篇筆記了很基本的 JavaScript 常識,這一篇要繼續整理剩下的部分,如 ES6 語法,與模組等等,最後講一下 npm 與 yarn
Module ( 模組 )
概念
將常用的函式獨立成一個模組,以後有需求可以直接引入這個模組來使用。Node.js 其中就有不少內建模組可以使用 ( 內建模組前面不用加 ./ 等檔案路徑 )。
require ( 拉來用 )
以 Node.js 內建的模組 os 為例,我可以要求使用,並使用裡面的其中一個名為 platform 的方法,官方文件表示這個函式會回傳一個字串來表示你的作業系統平台
var os = require('os')
console.log(os.platform()) // Win32 ( 乾買不起 MAC )
通常變數名稱可以自己改,但習慣上會使用你要引入的該 Module,這樣比較好辨別
export (借出去用)
我們當然也可以自己建立一個 Module 供別人使用
假設我建立一個檔名叫做 threeTimes.js,我在裡面放一個函式,你可以取用這個模組內的函式功能 - 將帶入的值乘以 3
第一種輸出方法 ( 好理解 )
// threeTimes.js
function triple(x) {
return x*3
}
module.export = triple
如此一個可以供人使用的 Module 就完成了,這時我要如何引入 threeTimes.js 呢 ?
var threeTimes = require('./threeTimes') // 加上檔案路徑,可以不加副檔名 js
console.log(triple(3)) // 9
第二種輸出方法
如果你一次要輸出多個函式,不只一個 triple,那你可以用物件把各函式打包送出
// threeTimes.js
function triple(x) {
return x*3
}
function triple2(x) {
return (x*3)*2
}
module.exports = {
fun1 : triple,
fun2 : triple2
}
你也可以建立一個變數,假設叫做 obj
,然後將函式放入物件之中,最後使 module.exports = obj
但是要注意的是在 require 這一端的變數 threeTimes 也會是一個物件,所以使用方法上就會不同,需要使用物件的方式存取
var threeTimes = require('./threeTimes') // 加上檔案路徑,可以不加副檔名 js
console.log(threeTimes.fun1(3), threeTimes.fun2(3)) // 6 18
第三種輸出方法
此外,你也可以換一種輸出形式,這樣的輸出也是同上面的物件形式
exports
本身就是一個空的物件,後面所接的就像是 { }
內中的屬性
// threeTimes.js
function triple(x) {
return x*3
}
function triple2(x) {
return (x*3)*2
}
exports.fun1 = triple
exports.fun2 = triple2
第一種輸出方法的好處是,module.exports =
之後可以輸出你想輸出的任何東西,如一個字串或陣列,取用端可以直接引用,就如同在同一個檔案底下那樣,相當好理解,你輸出什麼,require 就是什麼。
第二種和第三種方法都是輸出一個物件,相對於取用端來說,也要用取用物件的方式做引用。
第四種輸出方法 ( ES6 新增 )
也就是 export
與 import{}
,export
你想輸出的東西
輸出端 threeTimes.js 如下
// threeTimes.js
export function triple(x) {
return x*3
}
export const A = '123'
而取用端可以這樣寫 import {} from './路徑'
import {triple, A} from './threeTimes'
console.log(triple(5)) // 15
console.log(A) // '123'
第五種輸出方法
ES6 新增,概念上與第二種方法類似,差別在於這樣的用法也不會使輸出的東西為物件
其實就是第四種輸出方法的另一種形式,將你要輸出的東西用 { }
打包,但它並不是物件
// threeTimes.js
function triple(x) {
return x*3
}
const A = '123'
export = {
triple,
A
}
如果你想使輸出的東西以你想要的新名稱輸出出去,你可以使用 as
為其取別名
// threeTimes.js
function triple(x) {
return x*3
}
const A = '123'
export = {
triple as fun1,
A as str
}
或者你也可以將 as
用在輸入端
import { triple as fun1, A as str } from './threeTimes'
console.log(triple(5))
接著,如果你想引入該 Module 全部有輸出的東西,可以使用 import * as from '<./Module>'
如果這樣做,那麼輸出的部分都會被包成一個名為 的模組,所以如果要存取,必須在前面加上模組名稱
import * as allFunction from './threeTimes'
console.log(allFunction.triple(5)) // 需要先加上 allFunciton 這個模組名稱
第六種輸出方法 export default
// threeTimes.js
export default function triple(x) {
return x*3
}
那取用端就可以這樣寫
import triple from './threeTimes'
console.log(triple(5))
有點像第一種使用方法,可以直接做取用,但更好的理解是,這樣的輸出方法與第四種的差別在於,import 時不用加大括號。
// threeTimes.js
export default function triple(x) {
return x*3
}
export const A = '123'
那取用端就可以這樣寫
import triple, { A } from './threeTimes' // A 要加 {},注意逗號
console.log(triple(5), A)
ES6 ( 由於在 2015 年發布,又稱 ES 2015 )
這邊簡單筆記 ES6 語法,但不是全部。
const / let
const ( 常數 )
你無法對 const 建立的變數重新賦值,但若是被賦予物件型別,你仍然可以更改內中記憶體位置指向的值。
let
作用域 ( 變數的生存範圍 )
變數運行機制會從最內層找到最外層
function abc() {
var a = 5
console.log(a)
}
abc()
console.log(a)
得到的結果會是 5 與一個錯誤
原因是因為第三行的 console.log()
找到了函式內層的 a
,值為 5
但在函式外層的 console.log()
卻找不到內層的 a
,所以顯示錯誤
let 性質
正常來說,JS 的作用域是以函式為邊界,但若是一個變數使用 let
宣告,那該變數的生存範圍就會以離他最近的區域為僅有的生存範圍,可能是 if
的 {}
或 for loop
的 ()
或 {}
,const
也有同樣性質
新版字串 - 淘汰舊版字串方法吧 !
多行字串
console.log(
`
haha
haha2
haha3
`
)
/*
印出
haha
haha2
haha3
*/
串接變數
將你想插入字串中的變數 / 物件 / 陣列等等放入 ${}
,再放入`之中,不用再帶入任何
+` 號
var a = 100
console.log( `潮爽德撿到${a}塊內`) // 潮爽德撿到100塊內
解構
用途:當你需要將陣列或物件的元素各個拿出來放入變數之中,可以使用
陣列的解構方法:
var [a,b,c,d,e,f,e] = [1,2,3,4,5,6] console.log(b) // 2 console.log(e) // undefined
簡而言之就是一組對一個陣列元素,b 對上 2,e 沒有可以對應的元素,所以是 undefined
物件的解構方法:
const obj = { a : 15, b : 27, c : 33 } var { a,b,c } = obj console.log(a) // 15
注意,物件解構時變數的名字一定要和物件的元素名稱相同,如
var { a , b }
一定要對應到該物件中的a
與b
,否則變數會接收不到。另外就是解構完之後該變數本身內含物件元素,如果這個物件元素底下還有物件,那你也可以再對該變數進行解構一次,取它的元素。
const obj = {
a : {
aa : 55
},
b : {
bb : 66
},
c : 33
}
var { a : { aa },b,c } = obj
// 注意 a 與 aa,這邊是解構再解構的意思,別和物件的 {} 搞混
var { bb } = b
// 經過上一行的解構,已經有個物件變數為 b,所以我再解構這個物件變數一次,和上一行的 a 與 aa 同意義但不同寫法
console.log(aa) // 55 , 這邊的 aa 是個變數
console.log(bb) // 66
展開運算子 ...
簡單來說就是在陣列變數前面加上「...」,那麼它會取消掉陣列的 []
與性質,或是物件的 {}
,只展現裡面的元素。
var arr = [1,2,3,4]
console.log(...arr) // 1 2 3 4
function sum(a,b,c,d) {
return (( a + b + c + d ) * 2)
}
console.log(sum(...arr)) // 20
你也可以用來複製 Array
var arr = [2,3,4]
var arr2 = [...arr]
console.log(arr2) // [2,3,4]
物件也可以使用,見下例子
var obj1 = {
x:1,
y:2
}
var obj2 = {
obj1,
z:3
}
var obj3 = {
...obj1,
z:3
}
console.log(obj2) // { obj1: { x: 1, y: 2 }, z: 3 }
console.log(obj3) // { x: 1, y: 2, z: 3 }
可以看到 obj2 與 obj3 的差別,很簡單地可以了解,展開運算子之於物件也是解開 {}
的束縛。
若展開之後元素有重疊,則以較之後的元素值為準
var obj1 = {
x:1,
y:2
}
var obj3 = {
...obj1,
y:22
}
console.log(obj3) // { x: 1, y: 22 }
用展開運算子複製物件或陣列,會是一個全新的物件或陣列,新的記憶體位置與新的值,所以可以不用擔心在更改過程中改到原本被複製的物件 / 陣列的值。
簡單來說,用展開運算子複製物件 / 陣列,是複製值,也是兩個截然不同的記憶體位置。
而用一般賦值複製,如 obj2 = obj1
,是複製兩個相同的記憶體位置,指向同一個值。
反向展開 ( Rest Parameters )
var arr = [1,2,3,4]
var [a,...rest] = arr
console.log(rest) // [2,3,4]
通常與解構搭配使用,可以理解為 rest 前的 ... 將剩下的 2,3,4 打包起來給 rest,打包的概念正如同展開的相反,故稱反向展開。
注意 ...rest
只能放在解構的最後一個區塊,你沒辦法在後面再接變數
所以 var [a,...rest, theLast ] = arr
這樣的寫法是行不通的
物件也是同樣寫法
obj1 = {
a:1,
b:2,
c:3
}
var {a , ...obj2} = obj1
console.log(obj2) // { b: 2, c: 3 }
反向展開也可以用在函式,參考下面兩個例子
function sum(...args) {
console.log(args)
return args[0] + args[1]
}
console.log(sum(3,5))
function sum(a,...args) {
console.log(args)
return a + args[0]
}
console.log(sum(3,5,50,60,70))
可以發現這樣的用法很像函式的 arguments,差別在於上述例子中使用反向展開的 args 本質是陣列,而之前的 arguments 是長得像陣列的物件
default Parameters
可以用在 function 的參數上,可以直接幫參數賦予預設值
function sum(a,b,c = 10) {
return (a + b)*c
}
console.log(sum(3,5)) // 80
也可以用在解構上,替 = 左邊的變數設定預設值。
npm 與 yarn
npm - Node Package Manager
回想 Module 的概念,我們可以寫 Module 供自己使用,然而在世界各地也有不少人分享他們所寫的 Module 在網路上。而 npm 就是我們可以取用這些 Module 的工具,而 npm 在安裝 Node.js 的時候就會連帶安裝。
- 安裝套件與 node_modules
在 npm 找到你想安裝的套件之後,在 CLI 使用語法安裝 : npm install <套件名稱>
這時候你的專案資料夾底下會多出 node_modules 這個資料夾,它統一集中存放你所安裝的套件
- package.json
在安裝套件的時候之前,先輸入 npm init
並連續 Enter 跳過那些詢問,然後你可以在你的專案資料夾看到 package.json,這個就很像你的設定檔,裡面也會記錄你所這個專案所使用的 npm 套件有哪些 ( 記錄在 "dependencies" 底下)
所以如果你換了一個新的開發環境,只要持有你專屬的 package.json,然後在 CLI 輸入 npm install
,npm 就會自動根據你 package.json 底下所使用的套件紀錄全部下載下來,就不用帶著沉重的套件到處跑了。
所以 node_modules 通常不會納入 Git 控管,我們會將它放入 .gitignore ,我們只要記錄 package.json 即可。
但是你安裝套件的紀錄不會自動幫你寫入 package.json 底下的 dependencies,你必須在安裝的時候使用在最後面加入 --save
( npm install <套件名稱> --save
),那這個套件將會寫入 dependencies 底下;如果你是要安裝在 devDependencies 底下,則是使用 --save-dev
( npm install <套件名稱> --save-dev
)。
dependencies 與 devDependencies 的差別在於後者為開發環境才會使用到的套件。
- package.json 底下的 script 區塊
內中可以設定你想執行的指令名稱,指令名稱後面可以指定你要執行什麼。
"script" : {
"start": "node index.js"
}
這時候輸入 npm run start,就等同於輸入 node index.js
yarn 基本上和 npm 概念都相同,只列出不同的點
可以去官方網站安裝
npm | yarn |
---|---|
npm -v | yarn -v |
npm install | yarn install |
npm install <套件名稱> | yarn add <套件名稱> |
npm install <套件名稱> --save | yarn add <套件名稱> (即 yarn 會自動將套件寫入 package.json ) |
結語
個人覺得模組化的部分,在日後使用框架開發都會很常用到,有時也會忘記 export
與 export default
的差別,所以偶爾會回來翻資料。
很多一開始的知識不容易記住,都是因為沒有用到,但那也沒關係,曾經有個印象就好,重點是知道要從哪個方向找資料。
而 npm 與 yarn,原本想說 npm 順順用就好,但最近開始轉用 yarn 了,喜新厭舊在這時候好像變好習慣了 ? 雖然 yarn 也不新就是了,但至少用 yarn 安裝 Vue cli 不會出現錯誤 QQ
大概就是這樣了,本篇筆記結束。