使用空格符進行縮進;
javascript
四個空格符表示一個縮進層級;
php
function demo() { console.log('hello world'); }
使用分號結尾;
// 正確的代碼 let name = 'Nicholas'; function sayName() { alert(name); }
// 原始代碼 function getData() { return { title: '', author: '' } } // 分析器會理解成 function getData () { return; { title: '', author: '' }; }
指定一行代碼長度限定在80個字符;
當一行長度超過最大字符數限制(80個字符),需手動將一行代碼拆成兩行,且下一行增長兩個層級的縮進;
// 正確作法: 在運算符後換行,第二行追加兩個縮進層級 callAFunction(document, element, window, 'some string value', true, 123, navigator); // 很差的作法:第二行只有一個縮進 callAFunction(document, element, window, 'some string value', true, 123, navigator); // 很差的作法:在運算符以前換行了 callAFunction(document, element, window, 'some string value', true, 123 , navigator);
注意:逗號也算一個運算符,應看成爲前一行當結尾;
css
變量賦值時,第二行的位置應當與賦值運算符的位置保持對齊;
html
// 正確的作法 let result = something + anotherThing + yetAnotherThing + somethingElse + anotherSomethingElse; // 確保代碼的可讀性,並能一眼看清折行的上下文
在方法之間加入空行
前端
在方法中的局部變量和第一條語句之間加入空行
java
在多行或單行註釋以前加入空行
node
在方法內的邏輯片斷之間插入空行,提升可讀性
react
在方法之間加入空行
es6
// 好的寫法 function anther () { for (let i = 0; i < wl.length; i++) { // 內部邏輯 p = wl[i]; if (s.hasOwnProperty(p)) { if (merge && type === 'object') { y.min(r[p], s[p]); } else { r[p] = s[p]; } } } } /* *多行註釋 */ function bather() {}
駝峯式大小寫:小寫字母開始,後續每一個單詞首字母都大寫;
// 好的寫法 let thisIsMyName; let anotherletiable; let aVeryLongariableName;
變量名需老是遵照駝峯式大小寫命名法,且命名前綴爲【名詞】,以名詞作前綴可讓變量與函數區分開來;函數名前綴爲【動詞】
// 變量: 好的寫法 let count = 10; let myName = 'Nicholas'; let found = true; // 很差的寫法:變量看起來像函數 let getCount = 10; let isFound = true; // 函數: 好的寫法 function getName () { return myName; } // 很差的寫法: 函數看起來像變量 function theName() { return myName; }
對於函數和方法命名,第一個單詞應該式動詞;常見的一些使用動詞的約定
動詞 | 含義 |
---|---|
can | 函數返回一個布爾值 |
has | 函數返回一個布爾值 |
is | 函數返回一個布爾值 |
get | 函數返回一個非布爾值 |
set | 函數用來保存一個值 |
常量使用大寫字母和下劃線來命名,下劃線用以分割單詞
let MAX_COUNT = 10; let URL = 'http://www.nczonline.net/';
構造函數以'駝峯式大小寫'命名,首字母爲大寫,名詞
// 好的作法 function Person(name) { this.name = name } Person.prototype.sayName = function() { alert(this.name); }; let me = new Person('Nicholas')
靜態字符串一概使用單引號或反引號,不使用雙引號。動態字符串使用反引號。並從頭至尾保持一種風格
// 很差的寫法 const a = "foobar"; const b = 'foo' + a + 'bar'; // 可接受的寫法 const c = `foobar`; // 好的寫法 const a = 'foobar'; const b = `foo${a}bar`; const c = 'foobar';
在js中不可省略小數部分或者整數部分
// 整數 let count = 10; // 小數 let price = 10.0; let price = 10.00; // 不推薦的小數寫法:沒有小數部分 let price = 10.; //不推薦的小數寫法: 沒有整數部分 let price = .1; //不推薦的寫法: 八進制寫法已經被棄用了 let num = 010; // 十六進制寫法 let num = 0xA2 // 科學計數法 let num = 1e23;
null是個特殊值,切勿與undefind搞混;
null用來初始化一個變量,這個變量可能賦值爲一個對象;
null用來和一個已經初始化的變量比較,這個變量有多是也可能不是一個對象;
當函數的參數指望是對象時,用做參數傳入;
當函數的返回值指望是對象時,用做返回值傳出;
不要使用null來檢測是否傳入了某個參數;
不要用null來檢測一個未初始化的變量
// 好的用法 let person = null; // 好的用法 function getPerson() { if (condition) { return new Person('Nicholas') } else { return null; } } // 好的用法 let person = getPerson() if (person !== null) { doSomething(); } // 很差的寫法: 用來和未初始化的變量比較 let person; if (person !== null) { doSomething(); } // 很差的寫法: 檢測是否傳入了參數 function doSomething(arg1, agr2, arg3, arg4) { if (arg4 !== null) { doSomethingElse(); } }
理解null最好的方式時將它看成對象的佔位符;
未被初始化的變量都有一個初始值,即undefined;表示這個變量等待被賦值
// 很差的寫法 let person; console.log(person === undefined); // true
儘可能避免在代碼中使用undefined,這個值經常與返回'undefined'的typeof運算符混淆。
// foo未被聲明 let person; console.log(typeof person); // 'undefined' console.log(typeof foo); // 'undefined'
經過禁止使用特殊值 undefined, 能夠有效的保證只有一種狀況下typeof纔會返回'undefined'。若是使用了一個可能(或不可能)賦值爲一個對象的變量時,則將其賦值爲null。
// 好的作法 let person = null; console.log(person === null); // true
對象直接量容許將全部的屬性都括在一對花括號中;
// 好的寫法 let book = { title: '', author: '' } // 很差的寫法 let book = new Object(); book.title = ''; book.author = '';
單行定義的對象,最後一個成員不以逗號結尾。多行定義的對象,最後一個成員以逗號結尾。
// bad const a = { k1: v1, k2: v2, }; const b = { k1: v1, k2: v2 }; // good const a = { k1: v1, k2: v2 }; const b = { k1: v1, k2: v2, };
對象儘可能靜態化,一旦定義,就不得隨意添加新的屬性。若是添加屬性不可避免,要使用Object.assign方法。
// bad const a = {}; a.x = 3; // if reshape unavoidable const a = {}; Object.assign(a, { x: 3 }); // good const a = { x: null }; a.x = 3;
若是對象的屬性名是動態的,能夠在創造對象的時候,使用屬性表達式定義。
// bad const obj = { id: 5, name: 'San Francisco', }; obj[getKey('enabled')] = true; // good const obj = { id: 5, name: 'San Francisco', [getKey('enabled')]: true, };
上面代碼中,對象obj的最後一個屬性名,須要計算獲得。這時最好採用屬性表達式,在新建obj的時候,將該屬性與其餘屬性定義在一塊兒。這樣一來,全部屬性就在一個地方定義了。
另外,對象的屬性和方法,儘可能採用簡潔表達法,這樣易於描述和書寫。
var ref = 'some value'; // bad const atom = { ref: ref, value: 1, addValue: function (value) { return atom.value + value; }, }; // good const atom = { ref, value: 1, addValue(value) { return atom.value + value; }, };
使用兩個方括號將數組初始元素括起來,來替代Array的方式建立數組;
// 好的寫法 let colors = ['red', 'green', 'blur']; let numbers = [1,2,3,4]; // 很差的寫法 let color = new Array('red', 'green', 'blur') let numbers = new Array(1,2,3,4);
使用擴展運算符(...)拷貝數組。
// bad const len = items.length; const itemsCopy = []; let i; for (i = 0; i < len; i++) { itemsCopy[i] = items[i]; } // good const itemsCopy = [...items];
使用 Array.from 方法,將相似數組的對象轉爲數組。
const foo = document.querySelectorAll('.foo'); const nodes = Array.from(foo);
使用數組成員對變量賦值時,優先使用解構賦值。
const arr = [1, 2, 3, 4]; // bad const first = arr[0]; const second = arr[1]; // good const [first, second] = arr;
函數的參數若是是對象的成員,優先使用解構賦值。
// bad function getFullName(user) { const firstName = user.firstName; const lastName = user.lastName; } // good function getFullName(obj) { const { firstName, lastName } = obj; } // best function getFullName({ firstName, lastName }) { }
若是函數返回多個值,優先使用對象的解構賦值,而不是數組的解構賦值。這樣便於之後添加返回值,以及更改返回值的順序。
// bad function processInput(input) { return [left, right, top, bottom]; } // good function processInput(input) { return { left, right, top, bottom }; } const { left, right } = processInput(input);
代碼晦澀難懂
可能被誤認爲錯誤的代碼
必要但不明顯的針對特定瀏覽器的代碼
對於對象、方法或者屬性,生成文檔是有必要的(使用恰當的文檔註釋)
獨佔一行,用來解釋下一行代碼,且縮進層級和下一行代碼保持一致;
在代碼行的尾部的註釋,代碼結束到註釋之間至少有一個縮進,且不超過單行最大字符數限制,若是超過,則放置在代碼行的上方;
// 好的寫法 if (condition) { // 代碼執行邏輯 allowed(); } // 很差的寫法:註釋以前沒有空行 if (condition) { // 代碼邏輯 allowed(); } // 很差的寫法: 錯誤的縮進 if (condition) { // 代碼執行邏輯 allowed(); } // 好的寫法 let result = something + somethingElse; // 代碼執行邏輯 // 很差的寫法: 代碼和註釋之間沒有間隔; let result = something + somethingElse;// 代碼執行邏輯
多行註釋以前應當有一個空行,且縮進層級和其描述的代碼保持一致;
// 好的寫法 if (condition) { /* * 代碼執行邏輯 * 代碼執行邏輯 */ allowed(); }
當代碼不夠清晰時添加註釋,當代碼很明瞭時不該當添加註釋;
添加註釋的通常原則是:在須要讓代碼變的更清晰時添加註釋;
// 很差的寫法 // 初始化count let count = 10; // 好的寫法 //改變這個值可能會讓它變成青蛙 let count = 10;
在JavaScript中,不論塊語句包含多行代碼仍是單行代碼,都應該使用花括號
// 好的寫法 if (condition) { doSomething(); } // 很差的寫法 if(condition) doSomething(); // 很差的寫法 if(condition) doSomething(); // 很差的寫法 if (condition) { doSomething(); }
推薦使用的花括號對齊風格是:將左花括號放置在塊語句的第一句代碼的末尾。
// 好的作法 if (condition) { doSomething(); } else { doSomethingElse(); }
推薦風格:在括左圓括號以前和括右圓括號以後各添加一個空格
// 好的作法 if (condition) { doSomething(); }
不管什麼時候都不該該省略default
// 好的作法 switch (condithing) { case 'first' // 代碼 break; default: // default中沒有邏輯 }
ES6 提出了兩個新的聲明變量的命令:let和const。其中,let徹底能夠取代let,由於二者語義相同,並且let沒有反作用。
'use strict'; if (true) { let x = 'hello'; } for (let i = 0; i < 10; i++) { console.log(i); }
建議再也不使用var命令,而是使用let命令取代。
'use strict'; if (true) { console.log(x); // ReferenceError let x = 'hello'; }
let命令存在變量提高效用,let命令沒有這個問題
正則表達式
必須將全部的變量聲明放在函數頂部,而不是散落在各個角落
// 好的作法 function doSomething(items) { let i, len; let value = 10; let result = value + 10; for (i = 0; len = items.length; i < len; i++) { doSomething(); } }
合併let語句,可讓代碼更短更快:每一個變量的初始化獨佔一行,賦值運算符應當對齊,沒有初始值的變量,應當出如今let語句的尾部;
// 好的作法 function doSomething() { let value = 10, result = value + 10, i, len; for (i = 0; len = items.length; i < len; i++) { doSomething(); } }
在let和const之間,建議優先使用const,尤爲是在全局環境,不該該設置變量,只應設置常量
// 很差的寫法 var a = 1, b = 2, c = 3; // 好的寫法 const a = 1; const b = 2; const c = 3; // 最好的寫法 const [a, b, c] = [1, 2, 3];
全部的函數都應該設置常量
必須先聲明javascript函數再使用函數
// 好的寫法 function doSomething() { alert(''); } doSomething(); // 很差的寫法 doSomething(); function doSomething() { alert(''); }
當即執行函數能夠寫成箭頭函數的形式。
(() => { console.log('Welcome to the Internet.'); })();
那些須要使用函數表達式的場合,儘可能用箭頭函數代替。由於這樣更簡潔,並且綁定了 this。
// bad [1, 2, 3].map(function (x) { return x * x; }); // good [1, 2, 3].map((x) => { return x * x; }); // best [1, 2, 3].map(x => x * x);
箭頭函數取代Function.prototype.bind,不該再用 self/_this/that 綁定 this。
// bad const self = this; const boundMethod = function(...params) { return method.apply(self, params); } // acceptable const boundMethod = method.bind(this); // best const boundMethod = (...params) => method.apply(this, params);
簡單的、單行的、不會複用的函數,建議採用箭頭函數。若是函數體較爲複雜,行數較多,仍是應該採用傳統的函數寫法
全部配置項都應該集中在一個對象,放在最後一個參數,布爾值不能夠直接做爲參數。
// bad function divide(a, b, option = false ) { } // good function divide(a, b, { option = false } = {}) { }
不要在函數體內使用 arguments 變量,使用 rest 運算符(...)代替。由於 rest 運算符顯式代表你想要獲取參數,並且 arguments 是一個相似數組的對象,而 rest 運算符能夠提供一個真正的數組。
// bad function concatenateAll() { const args = Array.prototype.slice.call(arguments); return args.join(''); } // good function concatenateAll(...args) { return args.join(''); }
使用默認值語法設置函數參數的默認值。
// bad function handleThings(opts) { opts = opts || {}; } // good function handleThings(opts = {}) { // ... }
不要在全局做用域中使用"use strict"
// 很差的寫法 "use strict" function doSomething() { // 代碼 } // 好的寫法 function doSomething() { "use strict" // 代碼 }
全部情景下都應當使用全等===和不全等!==
儘可能禁止使用原始包裝類型(String、Number、Boolean)來建立新對象
// 很差的作法 let name = new String('Nicholas'); let author = new Boolean(true); let count = new Number(10);
注意區分 Object 和 Map,只有模擬現實世界的實體對象時,才使用 Object。若是隻是須要key: value的數據結構,使用 Map 結構。由於 Map 有內建的遍歷機制。
let map = new Map(arr); for (let key of map.keys()) { console.log(key); } for (let value of map.values()) { console.log(value); } for (let item of map.entries()) { console.log(item[0], item[1]); }
老是用 Class,取代須要 prototype 的操做。由於 Class 的寫法更簡潔,更易於理解。
// bad function Queue(contents = []) { this._queue = [...contents]; } Queue.prototype.pop = function() { const value = this._queue[0]; this._queue.splice(0, 1); return value; } // good class Queue { constructor(contents = []) { this._queue = [...contents]; } pop() { const value = this._queue[0]; this._queue.splice(0, 1); return value; } }
使用extends實現繼承,由於這樣更簡單,不會有破壞instanceof運算的危險。
// bad const inherits = require('inherits'); function PeekableQueue(contents) { Queue.apply(this, contents); } inherits(PeekableQueue, Queue); PeekableQueue.prototype.peek = function() { return this._queue[0]; } // good class PeekableQueue extends Queue { peek() { return this._queue[0]; } }
Module 語法是 JavaScript 模塊的標準寫法,堅持使用這種寫法。使用import取代require。
// bad const moduleA = require('moduleA'); const func1 = moduleA.func1; const func2 = moduleA.func2; // good import { func1, func2 } from 'moduleA';
使用export取代module.exports。
// commonJS的寫法 var React = require('react'); var Breadcrumbs = React.createClass({ render() { return <nav />; } }); module.exports = Breadcrumbs; // ES6的寫法 import React from 'react'; class Breadcrumbs extends React.Component { render() { return <nav />; } }; export default Breadcrumbs;
若是模塊只有一個輸出值,就使用export default,若是模塊有多個輸出值,就不使用export default,export default與普通的export不要同時使用。
不要在模塊輸入中使用通配符。由於這樣能夠確保你的模塊之中,有一個默認輸出(export default)。
// bad import * as myObject from './importModule'; // good import myObject from './importModule';
若是模塊默認輸出一個函數,函數名的首字母應該小寫。
function makeStyleGuide() { } export default makeStyleGuide;
若是模塊默認輸出一個對象,對象名的首字母應該大寫。
const StyleGuide = { es6: { } }; export default StyleGuide;
在瀏覽器中,window對象每每重載並等同於全局對象,,所以任何在全局做用域中聲明點變量和函數都是window對象的屬性;
最佳實踐:將應用邏輯從全部事件處理程序中抽離出來
規則 1: 隔離應用邏輯;
// 好的寫法 let myApplication = { handleClick: function(event) { this.showPopup(event) }, showPopup: function(event) { let popup = document.getElementById('popup'); popup.style.left = event.clientX + 'px'; popup.style.top = event.clientY + 'px'; popup.className = 'reveal' } }; addListener(element, 'click', function(event) { MyApplication.handleClick(event); });
規則 2: 不要分發事件對象, 最佳點辦法是讓事件處理程序使用event對象來處理事件;而後拿到所須要的數據傳給應用邏輯
// 好的寫法 let myApplication = { handleClick: function(event) { this.showPopup(event.clientX, event.clientY) }, showPopup: function(x,y) { let popup = document.getElementById('popup'); popup.style.left = x + 'px'; popup.style.top = y + 'px'; popup.className = 'reveal' } }; addListener(element, 'click', function(event) { MyApplication.handleClick(event); });
let Controller = { process: function(items) { if (items !== null) { // 很差的寫法 items.sort(); items.forEach(function() { // 執行邏輯 }) } } }
javascript有五種原始類型:字符串、數字、布爾值、null、undefined
判斷五種原始類型,最好使用typeo運算符;
typeof運算符會返回一個表示值的類型的字符串
// 檢測字符串 if (typeof name === 'string') { anotherName = name.substring(3); } // 檢測數字 if (typeof count === 'number') { updateCount(count); } // 檢測布爾值 if (typeof found === 'boolean' && found) { message('Found'); } // 檢測undefined if (typeof MyApp === 'undefined') { MyApp = {} }
未定義到變量和值爲undefined的變量,經過typeof都將返回'undefined'
原始值 null ,通常不用於檢測語句,若是須要檢測null,最好使用===或!==
typeof null 返回 'object' 編程時須要杜絕使用typeof來檢測null的類型
檢測某個引用值的類型的最好方法是使用instanceof運算符
value instanceof constructor // 檢測日期 if (value instanceof Date) { console.log(value.getFullYear()); } // 檢測正則表達式 if (value instanceof RegExp) { if (value.test(anotherValue)) { console.log('Mathces'); } } // 檢測Error if (value instanceof Error) { throw value; }
instanceof運算符可用於檢測自定義的類型
function Person(name) { this.name = name; } let me = new Person('Nicholas'); console.log(me instanceof Object); // true console.log(me instanceof Person); // true
javascript中的函數都是引用類型,一樣存在Function構造函數,每一個函數都是其實例;
function myFunc() {}; // 很差的寫法 console.log(myFunc instanceof Function); // true // 然而這個方法不能跨幀(frame)使用,由於每一個幀都有各自的Function構造函數。可是可使用typeof運算符檢測函數 // 好的寫法 console.log(typeof myFunc === 'function')
判斷屬性是否存在的最好辦法是使用in運算符
in運算符僅僅會簡單的判斷屬性是否存在,而不會去讀取屬性到值
let object = { count: 0, related:null } // 好的寫法 if ('count' in object) { // 這裏的代碼會執行 } // 很差的寫法: 檢測假值 if (object['count']) { // 這裏的代碼不會執行 } // 好的寫法 if ('related' in object) { // 這裏的代碼會執行 } // 很差的寫法: 檢測是否爲null if (object['related'] !== null) { // 這裏的代碼不會執行 }
檢測實例對象的某個屬性是否存在,則使用hasOwnProperty()方法,若是實例存在這個屬性則返回true(若是這個屬性只存在於原型裏,則返回false)
// 對於全部非dom對象,這是最好的辦法 if (object.hasOwnProperty('related')) { // 執行這裏的代碼 } // 若是不肯定是否爲dom對象, if ('hasOwnProperty' in object && object.hasOwnProperty('related')) { // 執行這裏的代碼 }
配置數據是應用中寫死的值
function validate(value) { if (!value) { alert('Invalid value') // 可能會修改替換 location.href = '/errors/invalid.php'; // 可能會修改替換 } } function toggleSelected(element) { if (hasClass(element, 'selected')) { // 'selected' 可能會修改替換 removeClass(element, 'selected'); // 'selected' 可能會修改替換 } else { addClass(element, 'selected') // 'selected' 可能會修改替換 } }
URL
須要展示給用戶的字符串
重複的值
設置(好比每頁的配置項)
任何可能發生變動的值
將配置數據從代碼中抽離出來的第一步是將配置數據拿到外部,即將數據從JavaScript代碼之中拿掉
let config = { MSG_INVALID_VALUE: 'Invalid value', URL_INVALID: 'errors/invalid.php', CSS_SELECTED: 'selected' } function validate(value) { if (!value) { alert(config.MSG_INVALID_VALUE); location.href = config.URL_INVALID; } } function toggleSelected(element) { if (hasClass(element, config.CSS_SELECTED)) { // 'selected' 可能會修改替換 removeClass(element, config.CSS_SELECTED); // 'selected' 可能會修改替換 } else { addClass(element, config.CSS_SELECTED) // 'selected' 可能會修改替換 } }
配置數據最好放在單獨的文件中,以便清晰的分隔數據和應用邏輯
將配置文件置於單獨的JavaScript文件中,是一個不錯的開始。一旦配置數據存放於單獨的文件中,就能夠管理這些數據
使用throw操做符,將提供的一個對象做爲錯誤拋出。
任何類型的對象均可以做爲錯誤拋出,Error對象是最經常使用的
throw new Error('something bad happend')
// 很差的寫法 throw 'message';
若是沒有經過try-catch語句捕獲,拋出任何值將引起一個錯誤
惟一不出差錯的顯示自動移動錯誤消息的方式就是使用一個Error對象
拋出本身的錯誤可使用確切的文本供瀏覽器顯示
在錯誤消息中包含函數名稱以及函數失敗的緣由
一旦修復了一個很難調試的錯誤,嘗試增長一兩個自定義錯誤,當再次發生錯誤時,這將有幫助於更容易的解決問題
若是正在編寫代碼,思考一下:「我但願【某些事情】不會發生,若是發生,個人代碼會一團糟糕」。這時,若是「某些事情」發生,就拋出一個錯誤
若是正在編寫的代碼別人也會使用,思考一下他們的使用方式,在特定的狀況下拋出錯誤
請牢記,咱們多目的不是防止錯誤,而是在錯誤發生時能更加容易的調試
將可能引起錯誤的代碼放在try塊中,處理錯誤的的代碼放在catch塊中
try { somethingThatMighCauseAnError(); } catch (ex) { handleError(ex) }
當try塊中發生一個錯誤時,程序當即中止執行,而後跳到catch塊,並傳入一個錯誤對象。檢測該對象能夠肯定從錯誤中恢復的最佳動做。
能夠增長finally塊。finally塊中的代碼無論是否有錯誤發生,最後都會被執行。
try { somethingThatMighCauseAnError(); } catch (ex) { handleError(ex) } finally { continue; }
注意:若是try塊中包含了一個return語句,實際上必須等到finally塊中的代碼執行後才能返回,所以,finally其實不太經常使用,可是若是處理錯誤必要,它還是處理錯誤的一個強大工具;
使用throw仍是try-catch
千萬不要將try-catch中的catch留空,需寫點錯誤處理邏輯來處理錯誤。
// 很差的寫法 try { somethingThatMighCauseAnError(); } catch (ex) { // 空 }
建立本身的錯誤類型,繼承Error,這種作法容許你提供額外的信息,同時可區別與瀏覽器拋出的錯誤。
function MyError(message) { this.message = message; } MyError.prototype = new Error(); 這段代碼有兩個重要的部分:message屬性,瀏覽器必需要知道錯誤消息字符串;設置prototype爲Error的一個實例,對JavaScript引擎就標識它是一個錯誤對象;
throw new MyError('Hello world');
JSDoc是一個根據javascript文件中註釋信息,生成JavaScript應用程序或庫、模塊的API文檔 的工具
JSDoc註釋通常應該放置在方法或函數聲明以前,它必須以/ **開始,以便由JSDoc解析器識別。其餘任何以/*,/***或者超過3個星號的註釋,都將被JSDoc解析器忽略
/** * Book類,表明一個書本. * @constructor * @param {string} title - 書本的標題. * @param {string} author - 書本的做者. */ function Book(title, author) { this.title=title; this.author=author; } Book.prototype={ /** * 獲取書本的標題 * @returns {string|*} */ getTitle:function(){ return this.title; }, /** * 設置書本的頁數 * @param pageNum {number} 頁數 */ setPageNum:function(pageNum){ this.pageNum=pageNum; } };
學習文檔:JSDoc中文文檔
學習資料《編寫可維護的JavaScript》《ECMAScript 6入門》