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 }

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

原文地址:https://www.cnblogs.com/newttt/p/12492356.html