• JavaScript全面学习(函数)


    1.定义函数的两种方法:

    function abs(x) {
        if (x >= 0) {
            return x;
        } else {
            return -x;
        }
    }

    或者

    var abs = function (x) {
        if (x >= 0) {
            return x;
        } else {
            return -x;
        }
    };  //记得要加分号,因为这是赋值abs变量

    2.调用函数

    abs(10, 'blablabla'); // 返回10
    abs(-9, 10, 'hehe', null); // 返回9,不受多个参数的影响,因为第一个参数就return了
    abs(); // x为undefined,返回NaN

    3.关键字arguments,类似于array.

    function foo(x) {
        alert(x); // 10
        for (var i=0; i<arguments.length; i++) {
            alert(arguments[i]); // 10, 20, 30
        }
    }
    foo(10, 20, 30);

    arguments最常用于判断传入参数的个数:

    if (arguments.length === 0) //如果参数个数为0...

    4.用rest获取所有参数:

    function foo(a, b) {
        var i, rest = [];
        if (arguments.length > 2) {
            for (i = 2; i<arguments.length; i++) {
                rest.push(arguments[i]);   // 在rest数组后添加元素
            }
        }
        console.log('a = ' + a);
        console.log('b = ' + b);
        console.log(rest);
    }

    一般写成如下更加简洁明了,与上面等效:

    function foo(a, b, ...rest) {
        console.log('a = ' + a);
        console.log('b = ' + b);
        console.log(rest);
    }
    
    foo(1, 2, 3, 4, 5);
    // 结果:
    // a = 1
    // b = 2
    // Array [ 3, 4, 5 ]
    
    foo(1);
    // 结果:
    // a = 1
    // b = undefined
    // Array []

    注意rest前面有3个点,如果没有的话,相当于rest就是第三个参数:

    function foo(a, b,rest) {
        console.log('a = ' + a);
        console.log('b = ' + b);
        console.log(rest);
    }
    foo(1, 2, 3, 4, 5);
    // 结果:
    // a = 1
    // b = 2
    // 3
    
    foo(1);
    // 结果:
    // a = 1
    // b = undefined
    // undefined

    5.接受任意个参数并返回它们的和:

    function sum(...rest) {
      var sum = 0;
      for(var i of rest) {
        sum += i;      
      }
      return sum;
    }

    6.JavaScript在行末自动添加分号

    7.不同函数内部的同名变量互相独立,互不影响

    8.内部函数可以访问外部函数定义的变量,反过来则不行:

    function foo() {
        var x = 1;
        function bar() {
            var y = x + 1; // bar可以访问foo的变量x!
        }
        var z = y + 1; // ReferenceError! foo不可以访问bar的变量y!
    }

    9.JavaScript会先扫描整个函数体的语句,把所有申明的变量“提升”到函数顶部,但不会提升变量的赋值:

    'use strict';
    
    function foo() {
        var x = 'Hello, ' + y;
        alert(x);
        var y = 'Bob';
    }
    
    foo();  //结果显示Hello, undefined,说明y没有值,但是已经声明了

    10.JavaScript默认有一个全局对象window,全局作用域的变量实际上被绑定到window的一个属性:

    'use strict';
    
    var course = 'Learn JavaScript';
    alert(course); // 'Learn JavaScript'
    alert(window.course); // 'Learn JavaScript'  与上面等效

    11.let解决块级作用域

    'use strict';
    
    function foo() {
        for (var i=0; i<100; i++) {
            //
        }
        i += 100; // 仍然可以引用变量i
    }
    'use strict';
    
    function foo() {
        var sum = 0;
        for (let i=0; i<100; i++) {
            sum += i;
        }
        i += 1; // SyntaxError,无法引用i
    }

    12.关键字const来定义常量,constlet都具有块级作用域:

    'use strict';
    
    const PI = 3.14;
    PI = 3; // 某些浏览器不报错,但是无效果!
    PI; // 3.14

    13.this指的是被调用函数的当前对象  ,多层内嵌会使指示错误,可以在函数开头用var that = this;来捕捉固定this

        要指定函数的this指向哪个对象,可以用函数本身的apply方法,它接收两个参数,第一个参数就是需要绑定的this变量,第二个参数是Array,表示函数本身的参数。

    function getAge() {
        var y = new Date().getFullYear();
        return y - this.birth;
    }
    
    var xiaoming = {
        name: '小明',
        birth: 1990,
        age: getAge
    };
    
    xiaoming.age(); // 25
    getAge.apply(xiaoming, []); // 25, this指向xiaoming, 参数为空

    对普通函数调用,我们通常把this绑定为null

    另一个与apply()类似的方法是call(),唯一区别是:

    • apply()把参数打包成Array再传入;

    • call()把参数直接按顺序传入。 

    14.map函数用法,()里调用其他函数

    function pow(x) {
        return x * x;
    }
    
    var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
    arr.map(pow); // [1, 4, 9, 16, 25, 36, 49, 64, 81] 令数组的所有元素都执行()里的函数

    还能这样

    var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
    arr.map(String); // ['1', '2', '3', '4', '5', '6', '7', '8', '9']

     15.reduce函数用法:必须接收两个参数,reduce()把结果继续和序列的下一个元素做累积计算,例如求和:

    var arr = [1, 3, 5, 7, 9];
    arr.reduce(function (x, y) {
        return x + y;
    }); // 25

    其他例子

    var arr = [1, 3, 5, 7, 9];
    arr.reduce(function (x, y) {
        return x * 10 + y;   // 把return值当成下一个x,与下一个y循环函数
    }); // 13579

    16.箭头函数

    function (x) {
        return x * x;
    }                 //相当于箭头函数x => x * x

     如果包含多条语句,这时候就不能省略{ ... }return

    如果参数不是一个,就需要用括号()括起来:

    // 两个参数:
    (x, y) => x * x + y * y
    
    // 无参数:
    () => 3.14
    
    // 可变参数:
    (x, y, ...rest) => {
        var i, sum = x + y;
        for (i=0; i<rest.length; i++) {
            sum += rest[i];
        }
        return sum;
    }

    如果要返回一个对象(单表达式),要外加一个括号,写成:

    x => ({ foo: x })

    回顾前面的例子,

    var obj = {
        birth: 1990,
        getAge: function () {
            var b = this.birth; // 1990
            var fn = () => new Date().getFullYear() - this.birth; // this指向obj对象
            return fn();
        }
    };
    obj.getAge(); // 25

    箭头函数使this总是指向词法作用域,也就是外层调用者obj,如果是之前的直接创建函数,this就会指向window

    由于this在箭头函数中已经按照词法作用域绑定了,所以,用call()或者apply()调用箭头函数时,无法对this进行绑定,即传入的第一个参数被忽略

    var obj = {
        birth: 1990,
        getAge: function (year) {
            var b = this.birth; // 1990
            var fn = (y) => y - this.birth; // this.birth仍是1990
            return fn.call({birth:2000}, year);   //箭头函数里的this已经绑定原对象obj,
                                                              //  此时的this.birth仍然是1990,
                                                         //  而不会将this绑定到传入的 birth:2000
        }
    };
    obj.getAge(2015); // 25

    17.split() 方法用于把一个字符串分割成字符串数组,如果要把字符串数组变成“数”组,要乘以1,可以如下写

    var arr=string.split('').map(x => x * 1)

    18.parseInt()函数可解析一个字符串,并返回一个整数。

        语法:parseInt(string, radix);

        string 必需。要被解析的字符串。

        radix 可选。表示要解析的数字的基数。该值介于 2 ~ 36 之间。

        如果省略该参数或其值为 0,则数字将以 10 为基础来解析。

        如果它以 “0x” 或 “0X” 开头,将以 16 为基数。

        如果该参数小于 2 或者大于 36,则 parseInt() 将返回 NaN。

    parseInt("10");          //返回 10         10进制
    parseInt("19",10);       //返回 19 (10+9)  10进制
    parseInt("11",2);        //返回 3 (2+1)    2进制
    parseInt("17",8);        //返回 15 (8+7)   8进制
    parseInt("1f",16);        //返回 31 (16+15)    16进制
    parseInt("010");         //未定:返回 10 或 8

    19.filter方法

    var arr = [1, 2, 4, 5, 6, 9, 10, 15];
    var r = arr.filter(function (x) {   
        return x % 2 !== 0;    //把arr中的偶数过滤掉,留下x%2!==0的
    });
    r; // [1, 5, 9, 15]
    var arr = ['A', '', 'B', null, undefined, 'C', '  '];
    var r = arr.filter(function (x) {
        return x && x.trim(); // 把false的空字符串过滤掉
    });                            //注意:IE9以下的版本没有trim()方法
    arr; // ['A', 'B', 'C']
    var arr = ['A', 'B', 'C'];
    var r = arr.filter(function (element, index, self) {  // 可以输入3个参数
        console.log(element); // 依次打印'A', 'B', 'C'
        console.log(index); // 依次打印0, 1, 2
        console.log(self); // self就是变量arr   会输出3次Array [ "A", "B", "C" ]
        return true;
    });
    var r = arr.filter(function (element, index, self) {
        return self.indexOf(element) === index;
    });  //过滤掉arr中重复的元素   indexOf() 方法返回某个指定的字符串值在字符串中首次出现的位置,注意是首次

    选出数组里面的素数:

     function get_primes(arr) {
          var i;
          var res = arr.filter(function(x){
                if(x<2) return false;     //排除掉1
                for(i=2; i*i<=x; i++){     
                    if(x%i === 0){return false;}   //从2开始往上面的数一个个地除,直到确认是不是素数
                    }
                return true;   //是素数就return true。
            });
            return res;
    }

     20.对于两个元素xy,如果认为x < y,则返回-1,如果认为x == y,则返回0,如果认为x > y,则返回1

    21.闭包(不大懂意义):返回一个函数,不立即执行

    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()   
                           //调用lazy_sum()时,返回的并不是求和结果,而是返回求和函数
    f(); // 15       //调用函数f时,才是真正计算求和的结果

    当我们调用lazy_sum()时,每次调用都会返回一个新的函数,即使传入相同的参数(每次调用的结果互不影响):

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

    返回的函数并没有立刻执行,而是直到调用了f()才执行:

    function count() {
        var arr = [];
        for (var i=1; i<=3; i++) {     // 这里正常思维是最终i=4,但是没想到4最后居然进入循环里面运算了??最终return 4*4
            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   等到3个函数都返回时,它们所引用的变量i已经变成了4

    正确写法:

    function count() {
        var arr = [];
        for (var i=1; i<=3; i++) {
            arr.push((function (n) {     // 在里面再创建一个函数,用该函数的参数绑定循环变量当前的值
                return function () {
                    return n * n;
                }
            })(i));              // 这样是用i去立即执行函数 注意括号的括法,(function (x) { return x * x }) (i);
        }
        return arr;
    }
    
    var results = count();
    var f1 = results[0];
    var f2 = results[1];
    var f3 = results[2];
    
    f1(); // 1
    f2(); // 4
    f3(); // 9

    借助闭包,可以封装一个私有变量。例如用JavaScript创建一个计数器:

    'use strict';
    function create_counter(initial) {
        var x = initial || 0;   //在没有初始值initial的时候给一个初始值
        return {
            inc: function () {
                x += 1;
                return x;
            }
        }
    }
    var c1 = create_counter();
    c1.inc(); // 1
    c1.inc(); // 2
    c1.inc(); // 3
    var c2 = create_counter(10);
    c2.inc(); // 11
    c2.inc(); // 12
    c2.inc(); // 13

    换句话说,闭包就是携带状态的函数,并且它的状态可以完全对外隐藏起来:

    function make_pow(n) {
        return function (x) {
            return Math.pow(x, n);   // 计算x的n次方
        }
    }
    // 创建两个新函数:
    var pow2 = make_pow(2);
    var pow3 = make_pow(3);
    pow2(5); // 25             相当于Math.pow(5, 2)
    pow3(7); // 343            相当于Math.pow(7, 3)

    只需要用函数,就可以用计算机实现运算,而不需要0123这些数字和+-*/这些符号:

    'use strict';
    
    // 定义数字0:
    var zero = function (f) {
        return function (x) {
            return x;
        }
    };
    
    // 定义数字1:
    var one = function (f) {
        return function (x) {
            return f(x);
        }
    };
    
    // 定义加法:
    function add(n, m) {
        return function (f) {
            return function (x) {
                return m(f)(n(f)(x));
            }
        }
    }
    // 计算数字2 = 1 + 1:
    var two = add(one, one);
    
    // 计算数字3 = 1 + 2:
    var three = add(one, two);
    
    // 计算数字5 = 2 + 3:
    var five = add(two, three);
    
    // 给3传一个函数,会打印3次:
    (three(function () {
        console.log('print 3 times');
    }))();
    
    // 给5传一个函数,会打印5次:
    (five(function () {
        console.log('print 5 times');
    }))();

    22.(意义不明啊!)generator(生成器)是ES6标准引入的新的数据类型。一个generator看上去像一个函数,但可以返回多次。

        编写一个产生斐波那契数列的函数:

    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;
    }
    fib(5); // fib {[[GeneratorStatus]]: "suspended", [[GeneratorReceiver]]: Window}
            // fib(5)仅仅是创建了一个generator对象,还没有去执行它

    //可以这样调用:
    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}

    next()方法每次遇到yield x;就返回一个对象{value: x, done: true/false},然后“暂停”。返回的value就是yield的返回值,done表示这个generator是否已经执行结束了。

    一般这样调用:

    for (var x of fib(6)) {   // 注意要6,坑啊
        console.log(x); // 依次输出0, 1, 1, 2, 3
    }

    下面是天书:

    用generator的话,AJAX可以大大简化代码:

    try {
        r1 = yield ajax('http://url-1', data1);
        r2 = yield ajax('http://url-2', data2);
        r3 = yield ajax('http://url-3', data3);
        success(r3);
    }
    catch (err) {
        handle(err);
    }

    用一个对象来保存状态:

    var fib = {
        a: 0,
        b: 1,
        n: 0,
        max: 5,
        next: function () {
            var
                r = this.a,
                t = this.a + this.b;
            this.a = this.b;
            this.b = t;
            if (this.n < this.max) {
                this.n ++;
                return r;
            } else {
                return undefined;
            }
        }
    };

    自增,并保存数字:

    'use strict';
    function* next_id() {
    var i=1;
    while(true)
    {
      yield i++;
    }
    }
  • 相关阅读:
    MySQL总结
    16 MySQL--正确使用索引
    15 MySQL--索引
    14 MySQL--事务&函数与流程控制
    13 MySQL--存储过程
    12 MySQL--内置功能介绍
    Spring课程 Spring入门篇 4-6 Spring bean装配之基于java的容器注解说明--@ImportResource和@Value java与properties文件交互
    Spring课程 Spring入门篇 4-5 Spring bean装配之基于java的容器注解说明--@Bean
    Spring课程 Spring入门篇 4-4 Spring bean装配(下)之Autowired注解说明3 多选一 qualifier
    Spring课程 Spring入门篇 4-3 Spring bean装配(下)之Autowired注解说明2 集合运用
  • 原文地址:https://www.cnblogs.com/shen076/p/6160173.html
Copyright © 2020-2023  润新知