MDN Docs 學習筆記
MDN Docs
JavaScript 教程 | 廖雪峰的官方網站
在 .html
檔案中引入 JavaScript
<!-- 在 </body> 標籤前的新行新增以下程式碼 -->
<script> src="scripts/main.js" defer></script>
瀏覽器會按照程式碼在檔案中的順序載入 HTML。如果先載入的 JavaScript 想要修改其下方的 HTML,那麼它可能由於 HTML 尚未被載入而失效。因此,將 JavaScript 程式碼放在 HTML 頁面的底部附近通常是最好的策略。
如何確保 JavaScript 程式碼在 HTML 載入完成後再執行?
- 在
<script>
標籤中新增defer
屬性 - HTML 文件全部載入完畢時會觸發 window.onload 事件,可以在這個事件中執行 JavaScript 程式碼
window.onload = function() {
// JavaScript 程式碼
}
匯入匯出
import something from '@/path_to_something' // 如果 path 是目錄,則會自動匯入目錄下的 index.js
import { some_method } from 'some_package' // 從 some_package 中解構出 some_method 函式
export default {
// 要向其他包暴露的資訊
}
變數
使用關鍵字 let
或 var
宣告變數。
let myVariable; // 儘管分號不是必需的,但建議加上
var beatles = [];
Object 與 Array
// Object
let person = {
name: 'Bob',
age: 20,
tags: ['js', 'web', 'mobile'], // Array
city: 'Beijing',
hasCar: true,
zipCode: null
};
console.log(person.name); // 輸出 Bob
console.log(person.tags); // 輸出 [js, web, mobile]
console.log(person.arr[0]); // 輸出 js
運算子
全等 ===
非全等 !==
普通的相等 ==
運算子允許型別轉換,而全等不允許:
var a = 25;
var b = "25";
console.log(a == b); // 輸出 true
console.log(a === b); // 輸出 false
表示式和運算子 | MDN Docs
函式
function add(num1, num2 = 0) { // 可以使用引數預設值
let result = num1 + num2;
return result;
}
// 函式可以儲存在變數,物件,陣列中
let fun = function() { // 這也叫做函式表示式
console.log("http://c.biancheng.net/js/");
}
// 函式還可以作為引數傳遞給其他函式,或者從其他函式返回
function createGreeting(name) {
return "Hello, " + name;
}
function displayGreeting(greetingFunction, userName) {
return greetingFunction(userName);
}
let result = displayGreeting(createGreeting, "Peter");
console.log(result); // 輸出 Hello, Peter
JS 輸出語句
alert(message); // 彈出一個提示框,只能輸出文字內容
confirm(message); // 彈出一個對話方塊
console.log(message); // 在瀏覽器的控制檯輸出內容,可以輸出物件
document.write(exp1, exp2, exp3, ...); // 將內容寫入到 HTML 文件中
// 和前面的函式不一樣,innerHTML 是一個屬性而不是函式。可以獲取或設定 HTML 標籤中的內容。
var demo = document.getElementById("demo");
console.log(demo.innerHTML);
demo.innerHTML = "<h2>innerHTML</h2>"
JS 結構語句
JavaScript 中的 if else
,while
,for
語句都和 Java 相同。除此之外,JavaScript 還擁有 for in
和 for of
語句。
for in
for in
迴圈用來遍歷 Object,在每次迴圈中,會將 Object 中的一個屬性的 key 賦給迴圈變數。
let person = {"name": "Clark", "surname": "Kent", "age": "36"};
for (let prop in person) {
console.log(prop + " = " + person[prop]); // 輸出鍵及對應的值
}
for of
// 遍歷陣列
let arr = ['a', 'b', 'c', 'd'];
for (let value of arr) {
console.log(value + ", "); // 輸出 a, b, c, d
}
// 遍歷字串
let str = "Hello";
for (let value of str) {
console.log(value + ", "); // 輸出 H, e, l, l, o,
}
JavaScript 中的 break
和 continue
也和 Java 的用法一樣(可以使用 label
)
I/O
終端輸入
使用前需要安裝 readline-sync 包:npm install readline-sync
const readlineSync = require("readline-sync");
let ans = readlineSync.question("What's your answer?\n");
檔案輸入
const fs = require("fs");
const content = fs.readFileSync("fileName", "utf8");
如果使用 readFile
輸入,需要注意其有一個回撥函式非同步呼叫的問題:用於接受輸入內容的回撥函式並不會立即執行,最先執行的語句是 readFile
下面的語句。而回撥函式則是等系統呼叫完成以後才執行。
const fs = require("fs");
fs.readFile(file, "utf8", (err, content) => {
if (err) {
// 處理錯誤
console.log("No such file");
process.exit(1);
}
console.log(content); // 使用讀取內容
});
console.log("我先被呼叫");
檔案輸出
const fs = require("fs");
fs.writeFile(file, JSON.stringify(data, null, " "), (err) => {
if (err) {
console.log("Write file error");
process.exit(1);
}
console.log("success");
});
正規表示式
正規表示式 | MDN Docs
RegExp 物件 | Runoob
DOM
文件物件模型(DOM) | MDN Docs
HTML-DOM
DOM Core 適用於所有標記文件,而 HTML-DOM 只適用於 HTML 文件。
node.href = "";
node.src = "";
node.nodeType; // 獲取節點型別;1:元素 2:屬性 3:文字
node.nodeName; // 獲取節點名
node.nodeValue; // 獲取節點值
node.childNodes; // 獲取子節點
node.firstChild; // 獲取第一個子節點
node.lastChild; // 獲取最後一個子節點
node.getAttribute('name'); // 獲取屬性值
node.setAttribute('name', 'value'); // 設定屬性值
node.onclick = function() {}; // 為元素新增事件處理程式
document.getElementByID("id");
document.getElementsByClassName("class_name");
document.getElementsByTagName("tag_name");
常用語句
document.getElementByTagName("name"); // 透過標籤名獲得一個標籤集
document.querySelector("selector"); // 使用 CSS 選擇器選擇元素
elem.innerHTML("content"); // 設定 elem 標籤的內容,可解析 HTML 元素。
elem.textContent = "message"; // 設定 elem 標籤的內容
elem.getAttribute("name");
elem.setAttribute("name", "value");
localStorage.setItem("name", "value");
elem.addEventListener('click', func); // 為元素新增事件監聽器
console
console.table(arr); // 以表格的形式輸出陣列和物件
console.time("label");
console.timeEnd("lebel"); // 計算過程用時
console.dir(elem); // 輸出 HTML 元素
console.log 輸出顏色
npm install colors
const colors = require("colors");
console.log("hello".green);
console.log("I like cake and pies".underline.red);
console.log("Inverse the color".inverse);
console.log("OMG Rainbows!".rainbow);
console.log("Run the trap".trap);
Troubleshooting
npm install Error: rollbackFailedOptional
npm config rm proxy
npm config rm https_proxy
npm config set registry https://registry.npmjs.org/
JavaScript 高階程式設計
- ECMAScript: JavaScript 的標準
- ECMA ("ek-ma-script")
European Computer Manufacturers Association (歐洲計算機制造商協會)
with 語句
// 可以將這些語句
var qs = location.search.substring(1);
var hostName = location.hostname;
var url = location.href;
// 改寫為
with(location) {
var qs = search.substring(1);
var hostName = hostname;
var url = href;
}
在 with
語句的程式碼塊內部,每個變數首先被認為是一個區域性變數,而如果在區域性環境中找不到該變數的定義,就會查詢 location
物件中是否有同名的屬性。
由於大量使用
with
語句會導致效能下降,同時也會給除錯程式碼造成困難,因此在開發大型應用時,不建議使用with
語句。
switch
JavaScript 的 switch
的 case
表示式可以不是常量表示式:
var num = 25;
switch (true) {
case num < 0:
alert("Less than 0.");
break;
case num >= 0 && num <= 10:
alert("Between 0 and 10.");
break;
case num > 10 && num <= 20:
alert("Between 10 and 20");
break;
default:
alert("More than 20.");
}
switch
語句在比較值時使用的是全等運算子,因此不會發生型別轉換(例如,字串 "10" 不等於數值 10)。
function
ECMAScript 中函式的引數在內部是用一個陣列來表示的,函式接收到的始終都是這個陣列,而不關心陣列中包含哪些引數(如果有引數的話)。如果這個陣列中不包含任何元素,無所謂;如果包含多個元素,也沒有問題。實際上,在函式體內可以透過 arguments
物件來訪問這個引數陣列,從而獲取傳遞給函式的每一個引數。
其實,arguments
物件只是與陣列類似(它並不是Array
的例項),因為可以使用方括號語法訪問它的每一個元素(即第一個元素是 arguments[0]
,第二個元素是arguments[1]
,以此類推),使用 length
屬性來確定傳遞進來多少個引數。
function sayHi() {
alert("Hello " + arguments[0] + "," + arguments[1]);
}
這個例子說明了 ECMAScript 函式的一個重要特點:命名的引數只提供便利,但不是必須的。
關於 arguments
的行為,還有一點比較有意思。那就是它的值永遠與對應命名引數的值保持同步。例如:
function doAdd(num1, num2) {
arguments[1] = 10;
alert(arguments[0] + num2);
}
每次執行這個 doAdd()
函式都會重寫第二個引數,將第二個引數的值修改為10。因為 arguments
物件中的值會自動反映到對應的命名引數,所以修改 arguments[1]
,也就修改了 num2
,結果它們的值都會變成10。不過,這並不是說讀取這兩個值會訪問相同的記憶體空間;它們的記憶體空間是獨立的,但它們的值會同步。另外還要記住,如果只傳入了一個引數,那麼為 arguments[1]
設定的值不會反映到命名引數中。這是因為 arguments
物件的長度是由傳入的引數個數決定的,不是由定義函式時的命名引數的個數決定的。
關於引數還要記住最後一點:沒有傳遞值的命名引數將自動被賦予 undefined
值。這就跟定義了變數但又沒有初始化一樣。例如,如果只給 doAdd()
函式傳遞了一個引數,則 num2
中就會儲存 undefined
值。
ECMAScript 中的所有引數傳遞的都是值,不可能透過引用傳遞引數。
ECMAScript 函式不能像傳統意義上那樣實現過載。而在其他語言(如 Java)中,可以為一個函式編寫兩個定義,只要這兩個定義的簽名(接受的引數的型別和數量)不同即可。如前所述,ECMAScript 函式沒有簽名,因為其引數是由包含零或多個值的陣列來表示的。而沒有函式簽名,真正的過載是不可能做到的。
如果在 ECMAScript 中定義了兩個名字相同的函式,則名字只屬於後定義的函式。
透過檢查傳入函式的引數的型別和數量並作出不同的反應,可以模仿函式過載。
reference
對引用資料型別的賦值,複製的是物件的引用:
var obj1 = new Object();
var obj2 = obj1;
obj1.name = "Nicholas";
alert(obj2.name); // "Nicholas"
在向函式引數傳遞引用型別的值時,會把這個值在記憶體中的地址複製給一個區域性變數,因此這個區域性變數的變化會反映在函式的外部。
function setName(obj) {
obj.name = "Nicholas";
}
var person = new Object();
setName(person);
alert(person.name); // "Nicholas"
檢測型別
要檢測一個變數是不是基本資料型別,可以用 typeof
運算子,它可以確定一個變數是 string
,number
,boolean
,undefined
,還是 object
:
var s = "Nicholas";
alert(typeof s); // string
為了檢測物件是哪種類的例項,可以使用 instanceof
運算子。如果變數是給定引用型別(根據它的原型鏈來識別)的例項,那麼 instanceof
運算子就會返回 true
。
alert(person instanceof Object); // ECMAScript 的所有物件都是 Object 的例項
alert(pattern instanceof RegExp);
執行環境及作用域
每個執行環境都有一個與之關聯的變數物件(variable object),環境中定義的所有變數和函式都儲存在這個物件中。
全域性執行環境是最外圍的一個執行環境。根據 ECMAScript 實現所在的宿主環境不同,表示執行環境的物件也不一樣。在 Web 瀏覽器中,全域性執行環境被認為是 window
物件,因此所有全域性變數和函式都是作為 window
物件的屬性和方法建立的。
每個函式都有自己的執行環境。當執行流進入一個函式時,函式的環境就會被推入一個環境棧中。而在函式執行之後,棧將其環境彈出,把控制權返回給之前的執行環境。
當程式碼在一個環境中執行時,會建立變數物件的一個作用域鏈(scope chain)。作用域鏈的用途,是保證對執行環境有權訪問的所有變數和函式的有序訪問。作用域鏈的前端,始終都是當前執行的程式碼所在環境的變數物件。如果這個環境是函式,則將其活動物件(activation object)作為變數物件。活動物件在最開始時只包含一個變數,即 arguments
物件(這個物件在全域性環境中是不存在的)。作用域鏈中的下一個變數物件來自包含(外部)環境,而再下一個變數物件則來自下一個包含環境。這樣,一直延續到全域性執行環境;全域性執行環境的變數物件始終都是作用域鏈中的最後一個物件。
延長作用域鏈
雖然執行環境的型別總共只有兩種——全域性和區域性(函式),但還是有其他辦法來延長作用域鏈。這麼說是因為有些語句可以在作用域鏈的前端臨時增加一個變數物件,該變數物件會在程式碼執行後被移除。
當執行流進入下列任何一個語句時,作用域鏈就會得到加長:
try-catch
語句的catch
塊;with
語句。
對 with
語句來說,會將指定的物件新增到作用域鏈中。對 catch
語句來說,會建立一個新的變數物件,其中包含的是被丟擲的錯誤物件的宣告。
function buildUrl() {
var qs = "?debug=true";
with(location){
var url = href + qs; // var url = location.href + qs
}
return url;
}
在此,with
語句接收的是 location
物件,因此其變數物件中就包含了 location
物件的所有屬性和方法,而這個變數物件被新增到了作用域鏈的前端。buildUrl()
函式中定義了一個變數 qs
。當在 with
語句中引用變數 href
時(實際引用的是 location.href
),可以在當前執行環境的變數物件中找到。當引用變數 qs
時,引用的則是在 buildUrl()
中定義的那個變數,而該變數位於函式環境的變數物件中。至於 with
語句內部,則定義了一個名為 url
的變數,因而 url
就成了函式執行環境的一部分,所以可以作為函式的值被返回。
沒有塊級作用域
在 ECMAScript 中,除了函式以外,任何花括號程式碼塊都不會產生新的作用域。
使用 var
宣告的變數會自動被新增到最接近的環境中。在函式內部,最接近的環境就是函式的區域性環境;在 with
語句中,最接近的環境是函式環境。如果初始化變數時沒有使用 var
宣告,該變數會自動被新增到全域性環境。
在 Web 瀏覽器中可以用 window.variable
的形式訪問全域性 variable
變數。
引用型別
雖然 ECMAScript 的引用型別與類看起來類似,但它們並不是相同的概念。
Object 型別
建立 Object
例項的方式有兩種。第一種是使用 new
運算子後跟 Object
建構函式:
var person = new Object();
person.name = "Nicholas";
person.age = 29;
另一種方式是使用物件字面量表示法。物件字面量是物件定義的一種簡寫形式,目的在於簡化建立包含大量屬性的物件的過程。下面的例子定義了與前面那個例子中相同的 person
物件:
var person = {
name: "Nicholas", // 使用逗號來分隔不同的屬性
age: 29 // 屬性名也可以用字串 "age"
};
出現在表示式上下文中的 {
表示物件字面量的開始,而出現在語句上下文中的 {
表示一個語句塊的開始。
表示式上下文(expression context):指該上下文期待一個值(表示式)
使用物件字面量語法來定義物件的方式更為常見。實際上,物件字面量也是向函式傳遞大量可選引數的首選方式:
function displayInfo(args) {
var output = "";
if (typeof args.name == "string") {
output += "Name: " + args.name + "\n"; // 檢測屬性是否存在
}
if (typeof args.age == "number") {
output += "Age: " + args.age + "\n";
}
alert(output);
}
displayInfo({
name: "Nicholas",
age: 29
});
displayInfo({
name: "Greg"
});
一般來講,命名引數雖然容易處理,但在有多個可選引數的情況下就會顯示不夠靈活。最好的做法是對那些必需值使用命名引數,而使用物件字面量來封裝多個可選引數。
一般來說,訪問物件屬性時使用的都是點表示法。不過,在JavaScript也可以使用方括號表示法來訪問物件的屬性。在使用方括號語法時,應該將要訪問的屬性以字串的形式放在方括號中:
alert(person["name"]); //"Nicholas"alert(person.name); //"Nicholas"
從功能上看,這兩種訪問物件屬性的方法沒有任何區別。但方括號語法的主要優點是可以透過變數來訪問屬性,例如:
var propertyName = "name";alert(person[propertyName]); //"Nicholas"
如果屬性名中包含會導致語法錯誤的字元,或者屬性名使用的是關鍵字或保留字,也可以使用方括號表示法。例如:
person["first name"] = "Nicholas";
由於 "first name"
中包含一個空格,所以不能使用點表示法來訪問它。然而,屬性名中是可以包含非字母非數字的,這時候就可以使用方括號表示法來訪問它們。
通常,除非必須使用變數來訪問屬性,否則我們建議使用點表示法。
Array 型別
和 Object 一樣,Array 也有兩種建立方法。第一種是使用 Array 建構函式:
var colors = new Array();
var colors = new Array(20); // 陣列長度為 20
var colors = new Array("red", "blue", "green");
var names = Array("Greg"); // 也可以省略 new 運算子
第二種是使用陣列字面量表示法:
var colors = ["red", "blue", "green"];
var colors = [];
與物件一樣,在使用陣列字面量表示法時,也不會呼叫
Array
建構函式。
陣列的 length
屬性很有特點——它不是隻讀的。因此,透過設定這個屬性,可以從陣列的末尾移除項或向陣列中新增新項:
var colors = ["red", "blue", "green"];
colors.length = 2;
alert(colors[2]); // undefined
colors.length = 3; // 新增的每一項都會取得 undefined 值
alert(colors[3]); // undefined
檢測陣列
對於一個網頁,或者一個全域性作用域而言,使用 instanceof
運算子就能得到滿意的結果:
if (value instanceof Array) {
// TODO
}
instanceof
運算子的問題在於,它假定只有一個全域性執行環境。如果網頁中包含多個框架,那實際上就存在兩個以上不同的全域性執行環境,從而存在兩個以上不同版本的 Array
建構函式。如果你從一個框架向另一個框架傳入一個陣列,那麼傳入的陣列與在第二個框架中原生建立的陣列分別具有各自不同的建構函式。
為了解決這個問題,ECMAScript 5 新增了 Array.isArray()
方法。這個方法的目的是最終確定某個值到底是不是陣列,而不管它是在哪個全域性執行環境中建立的。這個方法的用法如下。
if (Array.isArray(value)) {
// TODO
}
轉換陣列
可以使用 toString()
或 join()
方法來將陣列轉換為字串。toString()
使用逗號分隔陣列元素,而 join()
則使用指定的分隔字串來分隔陣列元素。
var colors = ["red", "green", "blue"];
alert(colors.toString()); // red,green,blue
alert(colors.join("||")); // red||green||blue
如果陣列中的某一項的值是
null
或undefined
,那麼該值在join()
,toLocaleString()
,toString()
和valueOf()
方法返回的結果中以空字串表示。
棧方法
ECMAScript 為陣列專門提供了 push()
和 pop()
方法,以便實現類似棧的行為。
push()
方法可以接收任意數量的引數,把它們逐個新增到陣列末尾,並返回修改後陣列的長度。而 pop()
方法則從陣列末尾移除最後一項,減少陣列的 length
值,然後返回移除的項。
佇列方法
push()
已經實現了向陣列末尾新增項的方法,而從陣列前端取得項的方法是 shift()
,它能夠移除陣列中的第一個項並返回該項,同時將陣列長度減 1。
ECMAScript 還為陣列提供了一個 unshift()
方法,它能夠在陣列前端新增任意個項並返回新陣列的長度。
重排序方法
reverse()
可以反轉陣列項的順序,sort()
可以為陣列排序。
為了實現排序,sort()
方法會呼叫每個陣列項的 toString()
轉型方法,然後比較得到的字串,即使陣列中的每一項都是數值:
var values = [0, 1, 5, 10, 15];
values.sort();
alert(values); // 0,1,10,15,5
不用說,這種排序方式在很多情況下都不是最佳方案。因此 sort()
方法可以接收一個比較函式作為引數:
function compare(val1, val2) {
if (val1 < val2) {
return -1;
} else if (val1 > val2) {
return 1;
} else {
return 0;
}
}
var values = [0, 1, 5, 10, 15];
values.sort(compare);
alert(values); // 0,1,5,10,15
對於數值型別或者其 valueOf()
方法會返回數值型別的物件型別,可以使用一個更簡單的比較函式:
function compare(val1, val2) {
return val2 - val1; // 比較函式透過返回一個小於零、等於零或大於零的值來影響排序結果
}
操作方法
concat()
:拼接陣列
var colors = ["red", "green", "blue"];
var colors2 = colors.concat("yellow", ["black", "brown"]); // 將 "yellow", "black", "brown" 拼接到 colors 末尾
slice()
:取出陣列的一個範圍
var colors = ["red", "green", "blue", "yellow", "purple"];
var colors2 = colors.slice(1); // 獲取 [1, 4] 的元素
var colors3 = colors.slice(1, 4); // 獲取 [1, 4) 的元素
splice()
:向陣列的中部刪除及插入項
splice()
方法始終都會返回一個陣列,該陣列中包含從原始陣列中刪除的項。
var colors = ["red", "green", "blue"];
var removed = colors.splice(0, 1); // 從第 0 項開始刪除 1 項
alert(colors); // green,blue
alert(removed); // red
removed = colors.splice(1, 0, "yellow", "orange"); // 從第 1 項開始刪除 0 項,並插入 2 項
alert(colors); // green,yellow,orange,blue
alert(removed); // 空陣列
removed = colors.splice(1, 1, "red", "purple"); // 從第 1 項開始刪除 1 項,並插入 2 項
alert(colors); // green,red,purple,orange,blue
alert(removed); // yellow
位置方法
indexOf()
:從陣列的開頭開始向後查詢
lastIndexOf()
:從陣列的末尾開始向前查詢
兩個方法都返回要查詢的項在陣列中的位置或 -1。比較時使用全等運算子。
var numbers = [1,2,3,4,5,4,3,2,1];
alert(numbers.indexOf(4)); // 3
alert(numbers.lastIndexOf(4)); // 5
alert(numbers.indexOf(4,4)); // 5, 第二個參數列示查詢起點的索引
alert(numbers.lastIndexOf(4,4)) // 3
迭代方法
ECMAScriopt 5 為陣列定義了 5 個迭代方法。每個方法都接收兩個引數:要在每一項上執行的函式和(可選的)執行該函式的作用域物件——影響 this
的值。傳入這些方法中的函式會接收三個引數:陣列項的值、該項在陣列中的位置和陣列物件本身。根據使用的方法不同,這個函式執行後的返回值可能會也可能不會影響方法的返回值。
every()
: 對陣列中的每一項執行給定函式,如果該函式對每一項都返回true
,則方法返回true
。filter()
: 對陣列中的每一項執行給定函式,返回該函式會返回true
的項組成的陣列。forEach()
: 對陣列中的每一項執行給定函式。無返回值。map()
: 對陣列中的每一項執行給定函式,返回每次函式呼叫的結果組成的陣列。some()
: 對陣列中的每一項執行給定函式,如果該函式對任意項返回true
,則返回true
。
以上方法都不會修改陣列中包含的值。
var numbers = [1,2,3,4,5,4,3,2,1];
var everyResult = numbers.every(function(item, index, array) {
return (item > 2);
}); // false
var someResult = numbers.some(function(item, index, array) {
return (item > 2);
}); // true
var filterResult = numbers.filter(function(item, index, array) {
return (item > 2);
}); // [3,4,5,4,3]
var mapResult = numbers.map(function(item, index, array) {
return item * 2;
}); // [2,4,6,8,10,8,6,4,2]
numbers.forEach(function(item, index, array) {
// 對陣列元素要執行的操作
});
歸併方法
ECMAScript 5 還新增了兩個歸併陣列的方法:reduce()
和 reduceRight()
。這兩個方法都會迭代陣列的所有項,然後構建一個最終返回的值。其中,reduce()
方法從陣列的第一項開始,逐個遍歷到最後。而reduceRight()
則從陣列的最後一項開始,向前遍歷到第一項。
這兩個方法都接收兩個引數:一個在每一項上呼叫的函式和(可選的)作為歸併基礎的初始值。傳給 reduce()
和 reduceRight()
的函式接收4個引數:前一個值、當前值、項的索引和陣列物件。這個函式返回的任何值都會作為第一個引數自動傳給下一項。第一次迭代發生在陣列的第二項上,因此第一個引數是陣列的第一項,第二個引數就是陣列的第二項。
使用 reduce()
方法可以執行求陣列中所有值之和的操作,比如:
var values = [1,2,3,4,5];
var sum = values.reduce(function(prev, cur, index, array) {
return prev + cur;
}); // 15