• ES6 学习(7) ---函数


    1、函数的默认值

      ES6 中函数的参数是可以设置默认值的,同时,参数可以是一个表达式。

      函数的参数,不能再函数内再次使用 let 和 const 再次声明

     1 // ES6 写法
     2 function log(x, y = "World") {
     3   console.log(x, y)
     4 }  
     5 
     6 // ES5 写法
     7 function log(x, y) {
     8   y = y || 'World';
     9   console.log(x, y);
    10 }
    11 
    12 //
    13 let x = 99;
    14 funtion foo(Y = x + 1) {
    15   console.log(Y)  
    16 }
    17 foo() // 100 每次调用都会重新计算 X + 1

      参数的默认值可以与解构赋值一起使用

     1 // 1, 参数必须是一个对象
     2 function foo({x, y = 5}) {
     3   console.log(x, y);
     4 }
     5 
     6 foo({}) // undefined 5
     7 foo({x: 1}) // 1 5
     8 foo({x: 1, y: 2}) // 1 2
     9 foo() // TypeError: Cannot read property 'x' of undefined
    10 
    11 // 2, 第二种方法可以解决,第一种方法不传参会报错的现象
    12 // 这种方法是解构后 参数使用默认值
    13 function foo({x, y = 5} = {}) {
    14   console.log(x, y);
    15 }
    16 
    17 foo() // undefined 5
    18 
    19 // 3, 默认值是一个有具体属性的参数,直接解构赋值参数
    20 function m2({x, y} = { x: 0, y: 0 }) {
    21   return [x, y];
    22 }

      参数默认值的位置。 函数传参,参数是一一对应的,除了定义了默认值的尾参数可以省略,如果非尾部设置默认值,则参数不可以省略

     1 function f(x, y = 5, z) {
     2   return [x, y, z];
     3 }
     4 
     5 f() // [undefined, 5, undefined]
     6 f(1) // [1, 5, undefined]
     7 f(1, ,2) // 报错
     8 f(1, undefined, 2) // [1, 5, 2]
     9 
    10 // 上面代码中,有默认值的参数不是尾参数。这时,无法只省略该参数,而不省略它后面的参数,除非显式输入undefined。
    11 
    12 // 只有传参是 undefined 的时候才能出发函数使用默认值

      函数的 length 属性 // 如果参数没有指定默认值是,返回函数的参数,如果指定了默认值,则返回默认值之前参数的个数

     1 // 返回函数参数的个数
     2 (function (a) {}).length // 1
     3 
     4 // 返回 默认值参数之前参数的个数
     5 (function (a = 1) {}).length // 0
     6 (function (a, b, c = 1) {}).length // 2
     7 (function (a = 0, b, c) {}).length // 0
     8 (function (a, b = 1, c) {}).length // 1
     9 
    10 // ...rest, ...args 不计入参数的个数
    11 (function(...args) {}).length // 0

      作用域 // 当函数参数设置了默认值时,函数的参数就会有着独特的作用域,当函数初始化后,此作用域就会消失。此作用域为暂时性死区相当于{ let x }

    var x = 1;
    
    function f(x, y = x) { // 此处的 x 为参数,实参赋值给形参 x, x 赋值给 y, 此时参数形参的作用域相当于 {let x;  y = x}
      console.log(y);
    }
    
    f(2) // 2
    1 let x = 1;
    2 
    3 function f(y = x) { // 参数形参的作用域中 x 未定义,因此 x 指向外层作用域的 x
    4   let x = 2;
    5   console.log(y);
    6 }
    7 
    8 f() // 1
    1 function f(y = x) { // 此时 参数形成的作用域及window下 x 均为定义会报错
    2   let x = 2;
    3   console.log(y);
    4 }
    5 
    6 f() // ReferenceError: x is not defined
    var x = 1;
    
    function foo(x = x) { // 参数形成的作用域相当于 {let x = x}
      // ...
    }
    
    foo() // ReferenceError: x is not defined
    1 let foo = 'outer';
    2 
    3 function bar(func = () => foo) { // 参数为函数,同上,参数形成的作用域 { func = () => foo} 此作用域内没有 foo 变量就要往上一层作用域中找
    4   let foo = 'inner';
    5   console.log(func());
    6 }
    7 
    8 bar(); // outer
    var x = 1;
    function foo(x, y = function() { x = 2; }) { // 参数形成的作用域相当于 { let x;function(){ x = 2}}; y 函数执行,x 的赋值,只是给作用域的x赋值,并不会影响 全局和函数内的变量x
      var x = 3;
      y();
      console.log(x);
    }
    
    foo() // 3
    x // 1
    1 var x = 1;
    2 function foo(x, y = function() { x = 2; }) { // 参数形成的作用域同上,但函数内的 x 指向参数x,因此 x = 3 赋值给参数 x, 当 y函数执行时,有给参数 x赋值为2,因此打印x为2
    3   x = 3;
    4   y();
    5   console.log(x);
    6 }
    7 
    8 foo() // 2
    9 x // 1

      总结:函数的作用域链 { global { 传参 { 函数体 } } }

    2、 rest 参数

      ES6 引入 rest参数(...rest) 这样就不用使用arguments了,rest 是一个数组,而arguments 是一个伪数组,因此rest可以调用数组的使用方法

      注意:rest 可以不是第一个参数,但是只能是最后一个参数

     3、 name 属性  // 函数的 name属性, 返回函数名

     1 // 当匿名函数赋值给变量的时候,返回的是 变量
     2 var f = function () {};
     3 
     4 // ES5
     5 f.name // ""
     6 
     7 // ES6
     8 f.name // "f"
     9 
    10 // 当具名函数赋值给变量的时候,返回的是具名函数的名
    11 const bar = function baz() {};
    12 
    13 // ES5
    14 bar.name // "baz"
    15 
    16 // ES6
    17 bar.name // "baz"
    18 
    19 // Function构造函数返回的函数实例,name属性的值为anonymous。
    20 (new Function).name // "anonymous"
    21 
    22 // bind返回的函数,name属性值会加上bound前缀。
    23 function foo() {};
    24 foo.bind({}).name // "bound foo"
    25 
    26 (function(){}).bind({}).name // "bound "

     4、箭头函数 // ES6 允许使用 箭头( => ) 来定义函数

      当一个函数不需要或者需要多个参数时, 就使用一个括号来代表参数部分,箭头后没有 {} 表示返回( return ) 箭头后的部分

    var f = () => 5;
    // 等同于
    var f = function () { return 5 };
    
    var sum = (num1, num2) => num1 + num2;
    // 等同于
    var sum = function(num1, num2) {
      return num1 + num2;
    };

      当箭头后只有一条语句,同时需要返回时,就可以省略函数的大括号。否则就需要用大括号把它们括起来。

      主要注意的是,返回对象的时候不能省略函数的大括号,因为浏览器会将对象的大括号解析成函数的大括号,会报错。当返回一个对象是,

    可以省略大括号,而是用小括号括起来表示返回一个对象。

    // 报错
    let getTempItem = id => { id: id, name: "Temp" };
    
    // 不报错
    let getTempItem = id => ({ id: id, name: "Temp" });

      当函数只有一条语句同时不需要返回值时,可以用 button.onclick = () => void doSomething();

      void 运算符在箭头函数中避免泄露,箭头函数标准中,允许在函数体不使用括号来直接返回值。 如果右侧调用了一个原本没有返回值的函数,其返回值改变后,则会导致非预期的副作用。 安全起见,当函数返回值是一个不会被使用到的时候,应该使用 void 运算符,来确保返回 undefined,这样,当 API 改变时,并不会影响箭头函数的行为。(这样doSomething 函数执行不管是否有返回,button的点击事件都不会有返回值)

      箭头函数很大程度上简化了代码

    1 // 正常函数写法
    2 [1,2,3].map(function (x) {
    3   return x * x;
    4 });
    5 
    6 // 箭头函数写法
    7 [1,2,3].map(x => x * x);

      使用箭头函数注意点

        1、箭头函数中是没有自己的this, 而是引用外层的 this,一般情况下,函数的this是可变的,但箭头函数的this的指向是固定的

        2、不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。

        3、不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。

        4、不可以使用yield命令

     1 function Timer() {
     2   this.s1 = 0;
     3   this.s2 = 0;
     4   // 箭头函数
     5   setInterval(() => this.s1++, 1000); // this 的指向是 Timer中的 this指向
     6   // 普通函数
     7   setInterval(function () { // this 的指向是 window
     8     this.s2++;
     9   }, 1000);
    10 }
    11 
    12 var timer = new Timer(); // new 操作符 改变了 Timer中 this的指向,使 this指向 Timer
    13 
    14 setTimeout(() => console.log('s1: ', timer.s1), 3100);
    15 setTimeout(() => console.log('s2: ', timer.s2), 3100);
    16 // s1: 3
    17 // s2: 0

      箭头函数不宜使用的地方:

        1、定义对象中的方法,一般函数,this是指向这个对象,但是使用箭头后,this就会指向window

        2、箭头函数的this是固定的,因此当需要动态的this时,不能用箭头函数

     1 const cat1 = {
     2   lives: 9,
     3   jumps: () => {
     4     this.lives--;
     5   }
     6 }
     7 const cat2 = {
     8   lives: 9,
     9   jumps: function() { // 动态this,谁调用指向谁
    10     this.lives--;
    11   }
    12 }
    13 cat1.jumps() // this 指向 window
    14 cat2.jumps() // this 指向 cat2

    5、尾调用优化 // https://es6.ruanyifeng.com/#docs/function#%E5%B0%BE%E8%B0%83%E7%94%A8%E4%BC%98%E5%8C%96

    6、尾逗号 // ES2017 允许函数的最后一个参数有尾逗号,这样的规定也使得,函数参数与数组和对象的尾逗号规则,保持一致了。

      此前,函数定义和调用时,都不允许最后一个参数后面出现逗号,否则会报错。

    7、Function.prototype.toString() // ES2019 对函数实例的toString()方法做出了修改。toString()方法返回函数代码本身,以前会省略注释和空格。修改后的toString()方法,明确要求返回一模一样的原始代码。

     1 // 修改前,会省略注释和函数名和()之间的空格
     2 function /* foo comment */ foo () {}
     3 
     4 foo.toString()
     5 // function foo() {}
     6 
     7 // 修改后,返回原代码
     8 function /* foo comment */ foo () {}
     9 
    10 foo.toString()
    11 // "function /* foo comment */ foo () {}"

    8、 try...catch 语句参数省略 

     1 // 以前明确要求catch命令后面必须跟参数,接受try代码块抛出的错误对象。
     2 try {
     3   // ...
     4 } catch (err) {
     5   // 处理错误
     6 }
     7 
     8 // ES2019 做出了改变,允许catch语句省略参数。
     9 try {
    10   // ...
    11 } catch {
    12   // ...
    13 }

    -----不生产代码,只是代码的搬运工

  • 相关阅读:
    Java Web学习总结(16)——JSP的九个内置对象
    Java Web学习总结(15)——JSP指令
    【我的物联网成长记11】8招带你玩转规则引擎
    云图说|高效管理华为云SAP的“秘密武器”
    Python 中更优雅的日志记录方案
    有了它,Python编码再也不为字符集问题而发愁了!
    【鲲鹏来了】手把手教你创造一个属于自己的鲲鹏开发者环境
    解密昇腾AI处理器--DaVinci架构(计算单元)
    使用Keil5构建GD32450i-EVAL工程
    云图说|SAP技术画册“一点通”
  • 原文地址:https://www.cnblogs.com/newttt/p/12492356.html
Copyright © 2020-2023  润新知