一.sort()
排序的核心荔燎?比較兩個(gè)元素的大小
問題:
[1,10,5,45].sort();
//(4) [1, 10, 45, 5]
因?yàn)椋篈rray的sort()方法默認(rèn)把所有元素先轉(zhuǎn)換為String再排序病线,同時(shí)4的ASCll碼比5小皱蹦。
- 解決
//常規(guī)方式
var arr = [1,10,45,5];
arr.sort(function(x,y){
if(x > y){
return 1;
}
if(x < y){
return -1;
}
return 0;
});
//(4) [1, 5, 10, 45]
//優(yōu)雅的方式
var arr = [1,10,45,5];
arr.sort(function(a,b){
return a-b;
});
//(4) [1, 5, 10, 45]
- sort()方法會(huì)直接修改原數(shù)組Array,同時(shí)沒有"另起爐灶"---copy,返回的結(jié)果仍然是當(dāng)前Array。
var a1 = ['b','a','c'];
var a2 = a1.sort();
console.log(a1);//["a", "b", "c"]
console.log(a2);//["a", "b", "c"]
二. 閉包
1. 函數(shù)作為返回值
function parent(arr){
var child = function(){
return arr.reduce(function(a,b){
return a+b;
});
}
return child;
}
var f = parent([1,2,3,4,5]);
f();//15
More:該子函數(shù)可以引用父函數(shù)中的參數(shù)和局部變量北秽;當(dāng)從父函數(shù)中返回子函數(shù)時(shí),相關(guān)的參數(shù)和變量仍保存在返回的子函數(shù)內(nèi)最筒。
注意:當(dāng)我們調(diào)用父函數(shù)時(shí)贺氓,每次調(diào)用都會(huì)返回一個(gè)新的函數(shù),即使傳入相同的參數(shù):
var f1 = parent([1,2,3,4,5]);
var f2 = parent([1,2,3,4,5]);
f1 === f2;//false
2. 返回的函數(shù)并沒有立刻執(zhí)行
- 什么意思床蜘?
function count(){
var arr = [];
for(var i = 1;i <=3;i++){
arr.push(function(){
return i*i;
});
}
return arr;
}
var result = count();
var f1 = result[0];
var f2 = result[1];
var f3 = result[2];
console.log(f1());//16
console.log(f2());//16
console.log(f3());//16
- 變量result是一個(gè)指向函數(shù)count執(zhí)行結(jié)果arr的引用掠归,該數(shù)組中包含了三個(gè)函數(shù):
? (){
return i*i;
}
這三個(gè)函數(shù)都引用了父函數(shù)count中的局部變量 i,但這三個(gè)返回的子函數(shù)并沒有立即執(zhí)行悄泥。當(dāng)這三個(gè)函數(shù)都返回時(shí),它們所引用的變量i已經(jīng)變成了4肤粱,所以三次結(jié)果均為16弹囚。
返回閉包時(shí)要牢記一點(diǎn):返回的函數(shù)不要引用任何循環(huán)變量,或者后續(xù)會(huì)發(fā)生變化的變量领曼。
這里你想要的結(jié)果是:1 4 9鸥鹉,可以用以下方法實(shí)現(xiàn):
var arr = [1,2,3];
function square(arr){
return arr.map(function(a){
return a*a;
});
}
square(arr);//[1, 4, 9]
- 如果你非要用嵌套函數(shù)的方式
//創(chuàng)建一個(gè)匿名函數(shù)并立即執(zhí)行
function count(){
var arr = [];
for(var i = 1;i <=3;i++){
arr.push((function(a){
return function(){
return a*a;
}
})(i));
}
return arr;
}
var result = count();
var f1 = result[0];
var f2 = result[1];
var f3 = result[2];
console.log(f1());//1
console.log(f2());//4
console.log(f3());//9
//優(yōu)雅點(diǎn)的---let
function count(){
var arr = [];
for(let i = 1;i <=3;i++){
arr.push(function(){
return i*i;
});
}
return arr;
}
var result = count();
var f1 = result[0];
var f2 = result[1];
var f3 = result[2];
console.log(f1());//1
console.log(f2());//4
console.log(f3());//9
3. 閉包的真正威力
模擬私有變量:
設(shè)計(jì)一個(gè)計(jì)數(shù)器,執(zhí)行一下庶骄,加1毁渗,而不是人工加1:
function counter(i){
return i++;
}
counter(0);
//0
counter(1);
//1
counter(2);
//2
counter(3);
//3
//自動(dòng)化
function counter(initial){
var x = initial || 0;//防止initial = undefined
return {
inc : function(){
return x++;
}
};
}
var c1 = counter();
c1.inc();//0
c1.inc();//1
c1.inc();//2
c1.inc();//3
閉包就是攜帶狀態(tài)的函數(shù),并且它的狀態(tài)可以對外完全隱藏单刁。
4. 使用閉包將多參數(shù)的函數(shù)變成單參數(shù)的函數(shù)灸异。
- 比如:x^y 可以使用Math.pow(x,y)函數(shù),但對于x^2 或x^3有點(diǎn)大材小用了羔飞,使用閉包弄個(gè)簡潔版的肺樟。
function make_pow(y){
return function(x){
return Math.pow(x,y);
};
}
var pow2 = make_pow(2);
var pow3 = make_pow(3);
pow2(5);//25
pow3(3);//27
三. 箭頭函數(shù)(Arrow Function)
1.箭頭函數(shù) & 匿名函數(shù) 區(qū)別?
箭頭函數(shù)內(nèi)部的this是詞法作用域逻淌,由上下文決定么伯。
//匿名函數(shù)
var obj = {
birth : 1996,
getAge : function(){
var b = this.birth;
var fn = function(){
return (new Date().getFullYear() - this.birth);
}
return fn();
}
}
obj.getAge();//NaN
2017 - undefined;//NaN
//箭頭函數(shù)
var obj = {
birth : 1996,
getAge : function(){
var fn = () => new Date().getFullYear() - this.birth;
return fn();
}
}
obj.getAge();//21
//由于箭頭函數(shù)中的this已綁定了詞法作用域,
//因此call()或者apply()調(diào)用箭頭函數(shù)時(shí)卡儒,傳入的第一個(gè)參數(shù)無效田柔。
var obj = {
birth : 1996,
getAge : function(year){
var f = (y) => y - this.birth;//this.birth仍為1996,而非2000
return f.call({birth: 2000},year);
}
}
obj.getAge(2017);//21
四.generator(生成器)
1.調(diào)用函數(shù):傳入?yún)?shù)骨望,返回結(jié)果
//常規(guī)方法
function fib(count){
var a = 0,
b = 1,
temp,
arr = [0,1];
while(arr.length < count){
temp = a + b;
a = b;
b = temp;
arr.push(temp);
}
return arr;
}
fib(10);
>>>
(10) [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
調(diào)用Generator函數(shù)硬爆,返回一個(gè)遍歷器對象,代表Generator函數(shù)的內(nèi)部指針锦募。以后摆屯,每次調(diào)用遍歷器對象的next方法,都會(huì)返回一個(gè)帶有value和done兩個(gè)屬性的對象。value屬性表示當(dāng)前的內(nèi)部狀態(tài)的值虐骑,是yield或者return后面那個(gè)表達(dá)式的值准验;done屬性是一個(gè)布爾值,表示是否遍歷結(jié)束廷没。
return & yield
1.相似處:都返回緊跟在語句后面的那個(gè)表達(dá)式的值糊饱。
2.區(qū)別:在一個(gè)函數(shù)中,只能執(zhí)行一個(gè)return語句颠黎,執(zhí)行后另锋,就結(jié)束該函數(shù)了。而每個(gè)yield表達(dá)式都能通過next()方法在該函數(shù)中執(zhí)行狭归。在一個(gè)函數(shù)中夭坪,每次遇到y(tǒng)ield語句,函數(shù)暫停執(zhí)行过椎,下一次再從該位置繼續(xù)往后執(zhí)行室梅,因此,它具有位置記憶的能力疚宇。
3.next()方法會(huì)執(zhí)行Generator函數(shù)中的yield表達(dá)式和return語句亡鼠;但當(dāng)使用for...of時(shí),僅會(huì)執(zhí)行yield表達(dá)式敷待。
4.開發(fā)者角度:通過next方法间涵,Generator函數(shù)依次遍歷yield表達(dá)式。
5.Generator函數(shù)角度:依次生成了一系列的值榜揖,也就是Generator(生成器)名字的來源勾哩。
next() & for...of
///next()
function* fib(max) {
var
t,
a = 0,
b = 1,
n = 1;
while (n < max) {
yield a;
t = a + b;
a = b;
b = t;
n ++;
}
return a;
}
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: true}
//for...of
function* fib(max) {
var
t,
a = 0,
b = 1,
n = 1;
while (n < max) {
yield a;
t = a + b;
a = b;
b = t;
n ++;
}
return a;
}
for(var i of fib(5)){
console.log(i);
}
>>>
0
1
1
2
- 如果在普通函數(shù)中使用yield表達(dá)式,會(huì)產(chǎn)生語句錯(cuò)誤根盒。
var arr = [1, [[2, 3], 4], [5, 6]];
var flat = function* (a) {
//普通函數(shù)
a.forEach(function (item) {
if (typeof item !== 'number') {
yield* flat(item);
} else {
yield item;
}
});
};
for (var f of flat(arr)){
console.log(f);
}
//Uncaught SyntaxError: Unexpected identifier
//解決:使用for循環(huán)替代內(nèi)部的普通函數(shù)
var arr = [1,[[2,3],4],[5,6]];
var flat = function* (a){
var length = a.length;
for(var i = 0;i < length;i++){
var item = a[i];
//將數(shù)組中的嵌套數(shù)組中的每個(gè)元素依次輸出
if(typeof item !== 'number'){
yield* flat(item);
}else{
yield item;
}
}
};
for(var f of flat(arr)){
console.log(f);
}
>>>
1
2
3
4
5
6
- yield表達(dá)式如果用在另一個(gè)表達(dá)式中钳幅,必須用圓括號括起來:
function* demo() {
console.log('Hello' + yield); // SyntaxError
console.log('Hello' + yield 123); // SyntaxError
}
//Uncaught SyntaxError: Unexpected identifier
function* demo() {
console.log('Hello ' + (yield)); // OK
console.log('Hello ' + (yield 123)); // OK
}
var f = demo();
f.next();
//{value: undefined, done: false}
f.next();
>>>
Hello undefined
{value: 123, done: false}
f.next();
>>>
Hello undefined
{value: undefined, done: true}
- yield表達(dá)式用作函數(shù)參數(shù)或放在賦值表達(dá)式的右邊,可以不加括號
function* demo(){
foo(yield 'a',yield 'b');
let input = yield;
}