sort() | 闭包 | 箭头函数 | Generator函数

概述.png

廖雪峰老师----JavaScript教程

一.sort()

  • 排序的核心?比较两个元素的大小

  • 问题:

[1,10,5,45].sort();
//(4) [1, 10, 45, 5]

因为:Array的sort()方法默认把所有元素先转换为String再排序,同时4的ASCll码比5小。

  • 解决
//常规方式
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]
//优雅的方式
var arr = [1,10,45,5];
arr.sort(function(a,b){
    return a-b;
});
//(4) [1, 5, 10, 45]
sort()
sort()数值排序
  • sort()方法会直接修改原数组Array,同时没有"另起炉灶"---copy,返回的结果仍然是当前Array。
var a1 = ['b','a','c'];
var a2 = a1.sort();
console.log(a1);//["a", "b", "c"]
console.log(a2);//["a", "b", "c"]


二. 闭包

1. 函数作为返回值

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:该子函数可以引用父函数中的参数和局部变量;当从父函数中返回子函数时,相关的参数和变量仍保存在返回的子函数内。

  • 注意:当我们调用父函数时,每次调用都会返回一个新的函数,即使传入相同的参数:

var f1 = parent([1,2,3,4,5]);
var f2 = parent([1,2,3,4,5]);
f1 === f2;//false

2. 返回的函数并没有立刻执行

  • 什么意思?
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是一个指向函数count执行结果arr的引用,该数组中包含了三个函数:
ƒ (){
   return i*i;
}
  • 这三个函数都引用了父函数count中的局部变量 i,但这三个返回的子函数并没有立即执行。当这三个函数都返回时,它们所引用的变量i已经变成了4,所以三次结果均为16。

  • 返回闭包时要牢记一点:返回的函数不要引用任何循环变量,或者后续会发生变化的变量。

  • 这里你想要的结果是:1 4 9,可以用以下方法实现:

var arr = [1,2,3];
function square(arr){
    return arr.map(function(a){
        return a*a;
    });
}
square(arr);//[1, 4, 9]
  • 如果你非要用嵌套函数的方式
//创建一个匿名函数并立即执行
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
//优雅点的---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. 闭包的真正威力

  • 模拟私有变量:

  • 设计一个计数器,执行一下,加1,而不是人工加1:

function counter(i){
    return i++;
}
counter(0);
//0
counter(1);
//1
counter(2);
//2
counter(3);
//3
//自动化
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

闭包就是携带状态的函数,并且它的状态可以对外完全隐藏。

4. 使用闭包将多参数的函数变成单参数的函数。

  • 比如:x^y 可以使用Math.pow(x,y)函数,但对于x^2 或x^3有点大材小用了,使用闭包弄个简洁版的。
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


三. 箭头函数(Arrow Function)

1.箭头函数 & 匿名函数 区别?

箭头函数内部的this是词法作用域,由上下文决定。

//匿名函数
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
//箭头函数
var obj = {
    birth : 1996,
    getAge : function(){
        var fn = () => new Date().getFullYear() - this.birth;
        return fn();
    }
}
obj.getAge();//21
//由于箭头函数中的this已绑定了词法作用域,
//因此call()或者apply()调用箭头函数时,传入的第一个参数无效。
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.调用函数:传入参数,返回结果

//常规方法
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]

阮一峰老师---Generator 函数的语法

  • 调用Generator函数,返回一个遍历器对象,代表Generator函数的内部指针。以后,每次调用遍历器对象的next方法,都会返回一个带有value和done两个属性的对象。value属性表示当前的内部状态的值,是yield或者return后面那个表达式的值;done属性是一个布尔值,表示是否遍历结束。

  • return & yield
    1.相似处:都返回紧跟在语句后面的那个表达式的值。
    2.区别:在一个函数中,只能执行一个return语句,执行后,就结束该函数了。而每个yield表达式都能通过next()方法在该函数中执行。在一个函数中,每次遇到yield语句,函数暂停执行,下一次再从该位置继续往后执行,因此,它具有位置记忆的能力。
    3.next()方法会执行Generator函数中的yield表达式和return语句;但当使用for...of时,仅会执行yield表达式。
    4.开发者角度:通过next方法,Generator函数依次遍历yield表达式。
    5.Generator函数角度:依次生成了一系列的值,也就是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
  • 如果在普通函数中使用yield表达式,会产生语句错误。
var arr = [1, [[2, 3], 4], [5, 6]];
var flat = function* (a) {
  //普通函数
  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循环替代内部的普通函数
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];
        //将数组中的嵌套数组中的每个元素依次输出
        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表达式如果用在另一个表达式中,必须用圆括号括起来:
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表达式用作函数参数或放在赋值表达式的右边,可以不加括号
function* demo(){
    foo(yield 'a',yield 'b');
    let input = yield;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容