美文网首页 移动 前端 Python Android Java
sort() | 闭包 | 箭头函数 | Genera

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

作者: 姚屹晨 | 来源:发表于2017-09-01 09:55 被阅读58次
    概述.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;
    }
    

    相关文章

      网友评论

        本文标题:sort() | 闭包 | 箭头函数 | Genera

        本文链接:https://www.haomeiwen.com/subject/uljhjxtx.html