zoukankan      html  css  js  c++  java
  • ES6 学习笔记之三 函数参数默认值

    定义函数时为参数指定默认值的能力,是现代动态编程语言的标配。在ES6出现之前,JavaScript是没有这种能力的,框架为了实现参数默认值,用了很多技巧。

    ES6 的默认参数值功能,与其他语言的语法类似,但功能更强大。

    首先,是可以用标量值为函数参数指定默认值,这个标量可以是基本类型、数组、对象。

    例1:

    function foo(name = {first:"张",last:"三"},age = 20, phones = ['18888888888','18666666666']) {
        console.log("姓名:" + name.first + name.last);
        console.log("年龄:" + age);
        console.log("电话:" + phones.join());
    }
    foo();
    foo({first: "李",last: "向阳"});
    foo({first: "张",last: "三"}, age = 40);
    foo({first: "张",last: "三"}, age = 20, ['18666666666', '18888888888', '13333333333']);

    输出结果为:

    姓名:张三
    年龄:20
    电话:18888888888,18666666666
    
    姓名:李向阳
    年龄:20
    电话:18888888888,18666666666
    
    姓名:张三
    年龄:40
    电话:18888888888,18666666666
    
    姓名:张三
    年龄:20
    电话:18666666666,18888888888,13333333333

    在其它语言中,对于有默认值的参数,通常只能从末端省略,不能省略中间或前面的参数,只传递后面的参数。如果排在前面的参数要使用与默认值相同的值,就只能采用上面例子中的第三和第四种方式,传递一个与默认值相同的值了。

    但 JavsScript 有所不同:不传递参数与传递 undefined 是等同的,所以上例可以改写为(例2):

    function foo(name = {first:"张",last:"三"},age = 20, phones = ['18888888888','18666666666']) {
        console.log("姓名:" + name.first + name.last);
        console.log("年龄:" + age);
        console.log("电话:" + phones.join());
    }
    foo();
    foo({first: "李",last: "向阳"});
    foo(undefined, age = 40);
    foo(undefined, undefined, ['18666666666', '18888888888', '13333333333']);

     另一个特点是可以传递表达式,这个表达式是广义的表达式,可以是变量、计算式、函数定义、函数调用...

    下面举一个综合了上面各种表达式的函数定义(例3):

    let fn = function fn(x = 1, y = x + 1, f = function () { console.log(x); }, fs = (function (i) { return i * 10;})(x)) {
        console.log(x);
        console.log(y);
        f();
        console.log(fs);
    }
    fn();

    输出结果为:

    1
    2
    1
    10

    作用域!绕不开的作用域!

    在没有默认参数值的时候,JavaScript 函数的作用域问题并不突出,但在有默认参数值时,情况就很难描述的清楚了。

    总体来说,参数括号部分会形成一个作用域,但这个作用域很奇特,兹举例说明:

    首先,这个作用域与函数体作用域不同,见下例(例5):

    let fn = function (x = y) {
        var y = 4;
        console.log(x);
    }
    fn();

    这段代码会报变量 y 未定义的错误,而不会使用函数体作用域中定义的 y 。由于 var 定义的变量,会在整个作用域中存在(在定义语句前也存在),因此如果参数定义的作用域与函数体作用域是同一个作用域,它就应该使用函数体内的定义,虽然它不会拿到 4 这个值,但至少不会摄错。可参照的示例如下(例6):

    let fn = function () {
        let x = y;
        var y = 4;
        console.log(x);
    }
    fn();

    这个例子中,x = y 时 y 是已经声明的变量,但是没有赋值,所以最后的结果不会报错,只会打印出 undefined。

    其次,这个作用域也与外部作用域不同,见下例(例7)

    let y = 4;
    let fn = function (x = y, y = 1) { console.log(x); } fn();

     这段程序会报错,原因是参数字义中的 y = 1 相当于 let y = 1,而参数字义区自成作用域,因此 x = y 不会使用全局定义的 y,而是尝试使用本作用域定义的 y,但是 let 定义在 x = y 之后,形成了暂时性死区。

    再次,这个作用域也不是函数体作用域的父作用域,见下例(例8)

    let fn = function (x = 3, y = x) {
        let x = 2;
    }
    fn();

    这段代码会报变量 x 已定义的错误,如果参数定义区域是函数体的父作用域,那么子作用域是可以重定义父作用域的变量的。例8的反应说明 x 是定义到函数体内的作用域里的变量。

    但是函数定义区却又是有自己的作用域的,见下例(例9)

    let fn = function fn(x, y = () => {console.log(x)}, z = () => { x = 2; console.log(x);}) {
         console.log(x); // 8
         y(); // 8
         var x = 6;
         x++; 
    console.log(x); // 7 y(); // 8 z(); // 2
    console.log(x); // 7 y(); // 2 console.log(x); // 7 } fn(
    8);

    为清晰对照,我把函数调用的结果直接以注释的形式写在了对应的行末。

    第一次调用 console.log(x); 显示为 8,此时调用 y(),结果也是8,似乎没什么疑问。

    但紧接着二行代码,已经将 x 改变为了 7,第二个console.log(x)的结果也证实了这一结果;但第二次调用 y(),却仍然输出 8,说明定义在函数参数区的闭包函数,仍然在使用参数定义区自己的作用域,这个作用域的 x 并没有发生变化。

    调用z(),显示为 2,这也没什么疑问,此时再调用 console.log(x),仍然是 7 ,说明这个 x 是函数体作用域的 x,不受闭包函数 z() 的影响,但此时参数定义区作用域的 x 应该被改变了。再调用一次 y(),输出的是 2,证实了刚刚的猜想,即 z() 和 y() 都还在使用参数定义区的作用域。

    最后一次调用 console.log(x),输出 7,这个就还是函数体作用域的 x。

    给个笔者的结论吧:在定义函数时,参数定义区自成作用域,同时在参数定义区定义的变量,将进入函数体作用域,成为函数体作用域内的局部变量;这两个作用域互不干涉。 

  • 相关阅读:
    20145228 《信息安全系统设计基础》第九周学习总结 (1)
    20145228《信息安全系统设计基础》期中总结
    20145228《信息安全系统设计基础》第一次实验实验报告
    20145228 《信息安全系统设计基础》第八周学习总结 (1)
    20145228 《信息安全系统设计基础》第七周学习总结 (2)
    20145228 《信息安全系统设计基础》第七周学习总结 (1)
    20145228 《信息安全系统设计基础》第六周学习总结 (2)
    20145228 《信息安全系统设计基础》第六周学习总结 (1)
    20145203《信息安全系统设计》 实验二 固件开发
    20145203 《信息安全系统设计基础》第九周学习总结
  • 原文地址:https://www.cnblogs.com/matchless/p/8462713.html
Copyright © 2011-2022 走看看