Web/05-JavaScript之ES6语法/06-ES6:函数扩展.md
2020-06-04 14:49:45 +08:00

258 lines
7.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## 前言
ES6在**函数扩展**方面新增了很多特性例如
- 箭头函数
- 参数默认值
- 参数结构赋值
- 扩展运算符
- rest参数
- this绑定
- 尾调用
## 箭头函数
定义和调用函数传统写法
```javascript
function fn1(a, b) {
return a + b;
}
console.log(fn1(1, 2)); //输出结果3
```
定义和调用函数ES6中的写法
```javascript
var fn2 = (a, b) => a + b;
console.log(fn2(1, 2)); //输出结果3
```
二者的效果是一样的
在箭头函数中如果方法体内有两句话那就需要在方法体外边加上{}括号如下
```javascript
var fn2 = (a, b) => {
console.log('haha');
return a + b;
};
console.log(fn2(1, 2)); //输出结果3
```
从上面的箭头函数中我们可以很清晰地找到函数名参数名方法体
上方代码中
- 如果有且仅有1个参数`()`可以省略
- 如果方法体内有且仅有1条语句`{}`可以省略但前提是这条语句必须是 return
### this的指向
> 箭头函数只是为了让函数写起来更优雅吗当然不是还有一个很大的作用是与this的指向有关
ES5 this指向的是函数被调用的对象 ES6 的箭头函数中this指向的是函数被定义时
简单来说箭头函数中的this是不会变的是永远绑定在当前的环境下
## 参数默认值
**传统写法**
```javascript
function fn(param) {
let p = param || 'hello';
console.log(p);
}
```
上方代码中函数体内的写法是如果 param 不存在就用 `hello`字符串做兜底这样写比较啰嗦
**ES6 写法**参数默认值的写法很简洁
```javascript
function fn(param = 'hello') {
console.log(param);
}
```
ES6 中定义方法时我们可以给方法里的参数加一个**默认值**缺省值
- 方法被调用时如果没有给参数赋值那就是用默认值
- 方法被调用时如果给参数赋值了新的值那就用新的值
如下
```javascript
var fn2 = (a, b = 5) => {
console.log('haha');
return a + b;
};
console.log(fn2(1)); //第二个参数使用默认值 5。输出结果6
console.log(fn2(1, 8)); //输出结果9
```
**提醒1**默认值的后面不能再有**没有默认值的变量**比如`(a,b,c)`这三个参数如果我给b设置了默认值那么就一定要给c设置默认值
**提醒2**
我们来看下面这段代码
```javascript
let x = 'smyh';
function fn(x, y = x) {
console.log(x, y);
}
fn('vae');
```
注意第二行代码我们给y赋值为`x`这里的`x`是括号里的第一个参数并不是第一行代码里定义的`x`打印结果`vae vae`
如果我把第一个参数改一下改成
```javascript
let x = "smyh";
function fn(z, y = x) {
console.log(z, y);
}
fn("vae");
```
此时打印结果是`vae smyh`
## 扩展运算符
注意区分
- 扩展运算符的格式为`...`
- rest运算符的格式为`...变量名`
有了ES6当我们在定义一个方法但是不确定其参数的个数时我们就可以用**扩展运算符**作为参数
以前我们在定义方法时参数要确定个数如下程序会报错
```javascript
function fn(a, b, c) {
console.log(a);
console.log(b);
console.log(c);
console.log(d);
}
fn(1, 2, 3);
```
上方代码中因为方法的参数是三个但使用时是用到了四个参数所以会报错
![](http://img.smyhvae.com/20180304_1638.png)
现在我们有了扩展运算符就不用担心报错的问题了代码可以这样写
```javascript
function fn(...arg) { //当不确定方法的参数时,可以使用扩展运算符
console.log(arg[0]);
console.log(arg[1]);
console.log(arg[2]);
console.log(arg[3]);
}
fn(1, 2, 3); //方法中定义了四个参数但只引用了三个参数ES6 中并不会报错。
```
![](http://img.smyhvae.com/20180304_1650.png)
上方代码中注意arg参数之后不能再加别的参数否则编译报错
**举例**数组赋值的问题
我们来分析一段代码将数组 arr1 赋值给 arr2
```javascript
let arr1 = ['www', 'smyhvae', 'com'];
let arr2 = arr1; // 将 arr1 赋值给 arr2其实是让 arr2 指向 arr1 的内存地址
console.log('arr1:' + arr1);
console.log('arr2:' + arr2);
console.log('---------------------');
arr2.push('你懂得'); //往arr2 里添加一部分内容
console.log('arr1:' + arr1);
console.log('arr2:' + arr2);
```
运行结果
![](http://img.smyhvae.com/20180304_1950.png)
上方代码中我们往往 arr2 里添加了`你懂的`却发现arr1 里也有这个内容原因是`let arr2 = arr1;`其实是让 arr2 指向 arr1 的地址也就是说二者指向的是同一个内存地址
如果不想让 arr1 arr2 指向同一个内存地址我们可以借助扩展运算符来做
```javascript
let arr1 = ['www', 'smyhvae', 'com'];
let arr2 = [...arr1]; //arr2 会重新开辟内存地址
console.log('arr1:' + arr1);
console.log('arr2:' + arr2);
console.log('---------------------');
arr2.push('你懂得'); //往arr2 里添加一部分内容
console.log('arr1:' + arr1);
console.log('arr2:' + arr2);
```
运行结果
![](http://img.smyhvae.com/20180304_1951.png)
我们明白了这个例子就可以避免开发中的很多业务逻辑上的 bug
## `rest` 运算符
`rest` 在英文中指的是**剩余部分**不是指休息我们来举个例子理解剩余部分的含义
```javascript
function fn(first, second, ...arg) {
console.log(arg.length);
}
fn(0, 1, 2, 3, 4, 5, 6); //调用函数后,输出结果为 5
```
上方代码的输出结果为 5 调用`fn()`里面有七个参数`arg`指的是剩下的部分因为除去了`first``second`
从上方例子中可以看出`rest`运算符适用于知道前面的一部分参数的数量但对于后面剩余的参数数量未知的情况
## 模块化
**模块化的意义**
比如说当我需要用到jQuery库时我会把jQuery.js文件引入到我自己代码的最前面当我需要用到vue框架时我会把vue.js文件引入到我自己代码的最前面
可是如果有20个这样的文件就会产生20次http请求这种做法的性能肯定是不能接受的
如果把20个文件直接写在一个文件里肯定是不方便**维护**可如果写成20个文件这20个文件又不好排序这就是一个很矛盾的事情于是模块化就诞生了
**模块化历程**commonJSAMD规范RequireJSCMD规范SeaJSimport & export
**export**
静态化必须在顶部不能使用条件语句自动采用严格模式静态化有利于性能以及代码的稳定性