定義
function abs(x)
{
//argument 所有參數(shù)的數(shù)組;rest是剩余參數(shù)數(shù)組
...
}
函數(shù)是一個對象,匿名函數(shù)賦值 `abs` 對象 可定義為:
var abs = function(x)
{
...
};
- JavaScript允許傳入任意個參數(shù)而不影響調(diào)用,因此傳入的參數(shù)比定義的參數(shù)多也沒有問題。
- ES6引入了新的關(guān)鍵字let,用let替代var可以申明一個塊級作用域的變量。
- 由于var和let申明的是變量,如果要申明一個常量,在ES6之前是不行的,我們通常用全部大寫的變量來表示“這是一個常量,不要修改它的值”,ES6標(biāo)準(zhǔn)引入了新的關(guān)鍵字
const來定義常量,const與let都具有塊級作用域:
'use strict';
const PI = 3.14;
PI = 3; // 某些瀏覽器不報錯,但是無效果!
PI; // 3.14
- 從ES6開始,JavaScript引入了解構(gòu)賦值,可以同時對一組變量進(jìn)行賦值。對數(shù)組元素進(jìn)行解構(gòu)賦值時,多個變量要用
[...]括起來。
var [x, y, z] = ['hello', 'JavaScript', 'ES6'];
如果數(shù)組本身還有嵌套注意嵌套層次和位置要保持一致:let [x, [y, z]] = ['hello', ['JavaScript', 'ES6']];
解構(gòu)賦值還可以忽略某些元素:let [, , z] = ['hello', 'JavaScript', 'ES6']; // 忽略前兩個元素,只對z賦值第三個元素
如果需要從一個對象中取出若干屬性,也可以使用解構(gòu)賦值,便于快速獲取對象的指定屬性,變量名和屬性名應(yīng)保持一致,如果不一致,使用{屬性名:變量名} = 對象:
var person = {
name: '小明',
age: 20,
gender: 'male',
passport: 'G-12345678',
school: 'No.4 middle school'
};
// 把passport屬性賦值給變量id:
let {name, passport:id} = person;
name; // '小明'
id; // 'G-12345678'
// 注意: passport不是變量,而是為了讓變量id獲得passport屬性:
passport; // Uncaught ReferenceError: passport is not defined
// 如果person對象沒有single屬性,默認(rèn)賦值為true:
var {name, single=true} = person;
交換變量值
var x=1, y=2;
[x, y] = [y, x]
高階函數(shù)可把函數(shù)作為一個參數(shù),還可以把函數(shù)作為結(jié)果值返回
- map
map()方法定義在JavaScript的Array中,我們調(diào)用Array的map()方法,傳入我們自己的函數(shù),就得到了一個新的Array作為結(jié)果
'use strict';
function pow(x) {
return x * x;
}
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
var results = arr.map(pow); // [1, 4, 9, 16, 25, 36, 49, 64, 81]
console.log(results);
- reduce Array的
reduce()把一個函數(shù)作用在這個Array的[x1, x2, x3...]上,這個函數(shù)必須接收兩個參數(shù),reduce()把結(jié)果繼續(xù)和序列的下一個元素做累積計算,其效果就是:[x1, x2, x3, x4].reduce(f) = f(f(f(x1, x2), x3), x4)
- filter 和
map()類似,Array的filter()也接收一個函數(shù)。和map()不同的是,filter()把傳入的函數(shù)依次作用于每個元素,然后根據(jù)返回值是true還是false決定保留還是丟棄該元素。把一個Array中的空字符串刪掉,可以這么寫:
var arr = ['A', '', 'B', null, undefined, 'C', ' '];
var r = arr.filter(function (s) {
return s && s.trim(); // 注意:IE9以下的版本沒有trim()方法
});
r; // ['A', 'B', 'C']
數(shù)組去重
r = arr.filter(function (element, index, self) {
return self.indexOf(element) === index;
});
- sort JavaScript的Array的
sort()方法就是用于排序的,字符串根據(jù)ASCII碼進(jìn)行排序
- 閉包 定義在一個函數(shù)內(nèi)部的函數(shù),就是能夠讀取其他函數(shù)內(nèi)部變量的函數(shù)。將函數(shù)內(nèi)部和函數(shù)外部連接起來的橋梁。
function sum(arr) {
return arr.reduce(function (x, y) {
return x + y;
});
}
sum([1, 2, 3, 4, 5]); // 15
但是,如果不需要立刻求和,而是在后面的代碼中,根據(jù)需要再計算怎么辦?可以不返回求和的結(jié)果,而是返回求和的函數(shù)!
function lazy_sum(arr) {
var sum = function () {
return arr.reduce(function (x, y) {
return x + y;
});
}
return sum;
}
var f = lazy_sum([1, 2, 3, 4, 5]); // function sum()
f(); //15調(diào)用函數(shù)f時,才真正計算求和的結(jié)果
我們調(diào)用lazy_sum()時,每次調(diào)用都會返回一個新的函數(shù),即使傳入相同的參數(shù)
var f1 = lazy_sum([1, 2, 3, 4, 5]);
var f2 = lazy_sum([1, 2, 3, 4, 5]);
f1 === f2; // false
注意到返回的函數(shù)在其定義內(nèi)部引用了局部變量arr,
所以,當(dāng)一個函數(shù)返回了一個函數(shù)后,其內(nèi)部的局部變量還被新函數(shù)引用。
返回閉包時牢記的一點就是:返回函數(shù)不要引用任何循環(huán)變量,或者后續(xù)會發(fā)生變化的變量。
function count() {
var arr = [];
for (var i=1; i<=3; i++) {
arr.push(function () {
return i * i;
});
}
return arr;
}
var results = count();
var f1 = results[0];
var f2 = results[1];
var f3 = results[2];
f1(); // 16
f2(); // 16
f3(); // 16
改進(jìn)版:
function count() {
var arr = [];
for (var i=1; i<=3; i++) {
arr.push((function (n) {
return function () {
return n * n;
}
})(i));
}
return arr;
}
var results = count();
var f1 = results[0];
var f2 = results[1];
var f3 = results[2];
f1(); // 1
f2(); // 4
f3(); // 9
注意這里用了一個“創(chuàng)建一個匿名函數(shù)并立刻執(zhí)行”的語法:
(function (x) {
return x * x;
})(3); // 9
Java和C++,要在對象內(nèi)部封裝一個私有變量,可以用private修飾一個成員變量。
在沒有class機制,只有函數(shù)的語言里,借助閉包,同樣可以封裝一個私有變量。我們用JavaScript創(chuàng)建一個計數(shù)器:
function create_counter(initial) {
var x = initial || 0;
return {
inc: function () {
x += 1;
return x;
}
}
}
var c1 = create_counter();
c1.inc(); // 1
c1.inc(); // 2
c1.inc(); // 3
- Arrow Function(箭頭函數(shù))相當(dāng)于匿名函數(shù),并且簡化了函數(shù)定義:
x => x * x相當(dāng)于:function (x) { return x * x; }還有一種可以包含多條語句,這時候就不能省略{ ... }和return,如果參數(shù)不是一個,就需要用括號()括起來:
// 兩個參數(shù):
(x, y) => x * x + y * y
// 無參數(shù):
() => 3.14
// 可變參數(shù):
(x, y, ...rest) => {
var i, sum = x + y;
for (i=0; i<rest.length; i++) {
sum += rest[i];
}
return sum;
}
如果要返回一個對象`x => ({ foo: x })`
箭頭函數(shù)內(nèi)部的this是詞法作用域,由上下文確定。
- generator 看上去像一個函數(shù),但可以返回多次,
generator由function*定義(注意多出的*號),并且,除了return語句,還可以用yield返回多次。
function* fib(max) {
var
t,
a = 0,
b = 1,
n = 0;
while (n < max) {
yield a;
[a, b] = [b, a + b];
n ++;
}
return;
}
var f = fib(5);
f.next(); // {value: 0, done: false}
f.next(); // {value: 1, done: false}
f.next(); // {value: 1, done: false}
f.next(); // {value: 2, done: false}
f.next(); // {value: 3, done: false}
f.next(); // {value: undefined, done: true}
`fib(5)`僅僅是創(chuàng)建了一個`generator`對象,還沒有去執(zhí)行它
調(diào)用generator對象有兩個方法,一是不斷地調(diào)用generator對象的next()方法,next()方法會執(zhí)行g(shù)enerator的代碼,
每次遇到y(tǒng)ield x;就返回一個對象{value: x, done: true/false},
然后“暫?!?。返回的value就是yield的返回值,done表示這個generator是否已經(jīng)執(zhí)行結(jié)束了.
第二個方法是直接用for ... of循環(huán)迭代generator對象,這種方式不需要我們自己判斷done:
for (var x of fib(10)) {
console.log(x); // 依次輸出0, 1, 1, 2, 3, ...
}