JS基础:ES6关于基本语法的一些扩展
目录
一. 解构赋值
1. 数组的解构赋值
2. JS对象的解构赋值
3. 解构赋值的应用场景
二. 字符串的扩展
1. 模板字符串
三. 数组的扩展
1. 扩展运算符
...
四. JS对象的扩展
1. 扩展运算符
...
五. 函数的扩展
1. 箭头函数
一. 解构赋值
所谓解构赋值,是指当我们需要批量地从一个数组或字典中读取数据赋值给一堆指定的变量时采用的赋值方法,这种方法是ES6提供的,要比我们平常使用的赋值方法简便一些。
它的使用方式也很简单,我们只需要保证等号左边被赋值的一堆变量和等号右边的数组或字典的格式一样就行了。
1. 数组的解构赋值
比如说我们现在有一个数组arr
,里面存放好了要用的数据,现在要从数组中读取数据赋值给指定的变量。
在ES5中,我们通常的做法会像下面这样。
let arr = [1, 2, 3, 4, 5];
let a = arr[0];
let b = arr[1];
let c = arr[2];
let d = arr[3];
let e = arr[4];
// a = 1
// b = 2
// c = 3
// d = 4
// e = 5
我们发现,如果只是从数组中读取少量的数据赋值给指定的变量还好,可以一个一个地写,但是如果数据量很大,一个一个写就很头疼了,遍历倒是可以省劲,但是无法达到把数据赋值给指定的变量的效果,这时候ES6的解构赋值就派上用场了。
let arr = [1, 2, 3, 4, 5];
let [a, b, c, d, e] = arr;
// a = 1
// b = 2
// c = 3
// d = 4
// e = 5
下面是一些别的例子。
let arr = [1, 2, 3, 4, 5];
let [a, , c, , e] = arr;
// a = 1
// c = 3
// e = 5
let arr = [1, 2, 3, 4, 5];
let [a, b, c] = arr;
// a = 1
// b = 2
// c = 3
let arr = [1, 2, 3, 4, 5];
let [a, b, c, d, e, f] = arr;
// a = 1
// b = 2
// c = 3
// d = 4
// e = 5
// f = undefined
let arr = [1, [2, 3, 4], 5];
let [a, [b, c, d], e] = arr;
// a = 1
// b = 2
// c = 3
// d = 4
// e = 5
2. JS对象的解构赋值
JS对象的解构赋值和数组的解构赋值在本质上当然是一样的,不同的就是数组的元素是有序的,给变量赋值的时候按着顺序赋值就行了,而JS对象的元素是无序的,所以要赋值的变量名必须和JS对象里的属性名一样才能赋值成功。
比如说现在有一个person
对象,我们要从中读取数据赋值给指定的变量,那我们就知道变量名一定要取的和person
对象的属性名一样。
在ES5里,我们会这样做。
let person = {
'name': '张三',
'sex': '男',
'age': 11
};
let personName = person.name;
let personSex = person.sex;
let personAge = person.age;
// personName = "张三"
// personSex = "男"
// personAge = 11
这种单个读取单个赋值的方式,变量的名字可以随便取,但如果使用ES6里的解构赋值,那变量名就必须于JS对象的属性名一样,变量的顺序倒是无关紧要。
let person = {
'name': '张三',
'sex': '男',
'age': 11
};
let {sex, age, name} = person;
// name = "张三"
// sex = "男"
// age = 11
简单好些吧,不过注意变量名就不需要加''
了哦,你见过谁家变量名加引号的。
下面是一些别的例子。
let person = {
'name': '张三',
'sex': '男',
'age': 11
};
let {sex, name} = person;
// name = "张三"
// sex = "男"
let person = {
'name': '张三',
'sex': '男',
'age': 11
};
let {sex, age, name, height} = person;
// name = "张三"
// sex = "男"
// age = 11
// height = undefined
// 嵌套对象的解构赋值
let obj = {
p: [
'Hello',
{y: 'World'}
]
};
let {p, p: [x, {y}]} = obj;
// p = ["Hello", {y: "World"}]
// x = "Hello"
// y = "World"
3. 解构赋值的应用场景
- 交换两个变量的值
let a = 1;
let b = 2;
[a, b] = [b, a];
// a = 2
// b = 1
很爽吧。
- 提取JSON数据
这是解构赋值最常用的一个场景,比如我们从网络上请求到了JSON数据,用解构赋值很方便。
let jsonData = {
id: 42,
status: "OK",
data: [867, 5309]
};
let {id, status, data} = jsonData;
// id = 42
// status = "OK"
// data = [867, 5309]
二. 字符串的扩展
1. 模板字符串
模板字符串是增强版的字符串,用反引号``
来标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串里插入变量。
ES6之前,我们定义一个字符串用的是单引号''
。
let str = 'if i see her standing there alone';
str;// "if i see her standing there alone"
ES6之后,我们也可以用模板字符串来定义一个字符串。
let str = `if i see her standing there alone`;
str;// "if i see her standing there alone"
ES6之前,如果我们想定义一个多行字符串,那就需要在每个换行的地方手动插入\n
。
let str = 'if i see her standing there alone \n at the train station three stops from her home \n i have half a mind to say what i’m thinking anyway \n i don’t know \n i don’t know';
str;//
"if i see her standing there alone
at the train station three stops from her home
i have half a mind to say what i’m thinking anyway
i don’t know
i don’t know"
ES6之后,我们用模板字符串可以直接在需要换行的地方,敲击换行就可以了。(我们搞多行字符串有可能是为了开发人员看起来清晰舒服,毕竟如果一个字符串很长,一眼都看不到尾,我们可能会采用分段字符串,然后用+
连接,这样看起来舒服点。也有可能是我们要把这个带换行的字符串传给后台,那就得用\n
。但是有了模板字符串,这一切开发操作都变得更舒服更爽了。)
let str = `if i see her standing there alone
at the train station three stops from her home
i have half a mind to say what i’m thinking anyway
i don’t know
i don’t know`;
str;//
"if i see her standing there alone
at the train station three stops from her home
i have half a mind to say what i’m thinking anyway
i don’t know
i don’t know"
ES6之前,如果一个字符串里有很多变量,那我们就得用很多个加号+
(字符串连接符)把常量和变量连接起来,同时还需要注意字符串里的逗号啊、空格啊等格式不能给人家少掉,有一点麻烦呢。
let name = 'Mary';
let sex = 'female';
let age = 25;
let str = 'hi, my name is ' + name + ', ' + sex + ', ' + age + ' years old';
str;// "hi, my name is Mary, female, 25 years old"
ES6之后,用模板字符串可以很方便地在字符串中插入变量,我们只需要用${}
把变量包起来,然后直接把变量插入到相应的位置就可以了。
注意:
模板字符串里插入的这个变量最终肯定是个字符串,但写代码时你可以传进去任意JS数据类型,不要担心,运行时都会给你转化为字符串的,你甚至可以在
${}
调用一个函数,但这个函数最好有一个字符串作为返回值,否则这么做没什么意义。
let name = 'Mary';
let sex = 'female';
let age = 25;
let str = `hi, my name is ${name}, ${sex}, ${age} years old`;
str;// "hi, my name is Mary, female, 25 years old"
function fun() {
1 + 1;
}
let str = `hi, my name is ${fun()}`;
str;// "hi, my name is undefined"
function fun(name) {
return name;
}
let str = `hi, my name is ${fun('Mary')}`;
str;// "hi, my name is Mary"
三. 数组的扩展
1. 扩展运算符...
数组的扩展运算符...
用来将数组打散为一个用逗号分隔的参数序列,这是一个非常有用的扩展,比如我们给一个数组从另一个数组批量添加数据时会用到,给函数传多个参数时也会用到。
console.log(1, [2, 3, 4], 5);// 1 [2, 3, 4] 5
console.log(1, ...[2, 3, 4], 5);// 1 2 3 4 5
扩展运算符可以用来实现数组的深拷贝(值拷贝,指向不同的对象)。
JS里,数组的直接赋值是一个浅拷贝(指针拷贝,指向同一个对象)。
let arr1 = [1, 2];
let arr2 = arr1;
arr2[1] = 1;
arr1;// [1, 1]
arr2;// [1, 1]
而如果我们想要实现数组的深拷贝就可以通过扩展运算符来实现。
let arr1 = [1, 2];
let arr2 = [...arr1];
arr2[1] = 1;
arr1;// [1, 2]
arr2;// [1, 1]
四. JS对象的扩展
1. 扩展运算符...
JS对象的扩展运算符...
用来将JS对象打散为一对一对key-value的参数序列。
let obj = {
'name': '张三',
'sex': '男',
'age': 11
};
let newObj = {
...obj,
'height': 177,
'weight': 67
};
newObj;// {name: "张三", sex: "男", age: 11, height: 177, weight: 67}
以上newObj
除了height
、weight
属性之外,其它的属性均来自被打散了的obj
对象。
扩展运算符可以用来实现JS对象(字典)的深拷贝(值拷贝,指向不同的对象)。
JS里,JS对象的直接赋值是一个浅拷贝(指针拷贝,指向同一个对象)。
let obj = {
'name': '张三',
'sex': '男',
'age': 11
};
let newObj = obj;
newObj.name = '李四';
obj;// {name: "李四", sex: "男", age: 11}
newObj;// {name: "李四", sex: "男", age: 11}
而如果我们想要实现数组的深拷贝就可以通过扩展运算符来实现。
let obj = {
'name': '张三',
'sex': '男',
'age': 11
};
let newObj = {...obj};
newObj.name = '李四';
obj;// {name: "张三", sex: "男", age: 11}
newObj;// {name: "李四", sex: "男", age: 11}
五. 函数的扩展
1. 箭头函数
1.1 基本用法
ES6给我们提供了一种定义匿名函数的新方法——箭头函数(注意是匿名函数哦,普通函数还是用老方法定义),它有好几个优点,如果想了解可以自己去查,总之你用就行了,箭头函数的格式为(参数) => {执行体}
,就这么简洁,不过注意要把分号;
捋清楚。
let func = function () {
console.log('Hello World');
};
let func = () => {console.log('Hello World');};
传统定义法如下,一个函数无非就四个部分:函数名、函数的具体实现、参数和返回值(返回值语句包含在函数体内)。
var 函数名 = function(参数1, 参数2, ...) {
// 函数的具体实现
}
那么用箭头函数=>
来定义函数的话,无非也包含这四个部分就可以了嘛,箭头函数的标准写法就是:(函数参数) => {函数体};,要是给一个变量赋值的话就是:var 函数名 = (函数参数) => {函数体};,但是也有变种,例如:当我们参数只有一个时,我们可以省略掉函数参数部分的()
,同时如果我们省略了函数体部分的{}
,那么箭头函数是会默认把=>
后面表达式的值作为函数的返回值。
var f = function(param) {
return param;
}
标准写法
var f = (param) => {return param};
等价于
var f = param => param;
需要特别注意的是:
箭头函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。即this对象的指向是可变的,但是在箭头函数中,它是固定的。
当然也正是因为箭头函数里的this由动态变为静态的了,所以需要动态this的场合我们就不能使用箭头函数。
因此:
写箭头函数或分析别人写的箭头函数是什么意思,首先要把箭头函数分为三部分:参数、=>
、=>
后面的返回值或执行体特别要注意的是,如果
=>
后面没有写{}
,就代表该箭头函数的真正执行体为执行这段代码,并把代码执行的结果作为该箭头函数的返回值返回,如果=>
后面写了{}
,那该箭头函数的执行体自然就是我们自己写的这段代码了。
注意,箭头函数只是一个匿名函数,别看它的样子像立即执行就觉得它会立即执行,它和匿名函数一样,除非你定义了立马调用它,它才会立即执行,否则就是定义了一个函数而已。因此
var f = (param) => {return param};
我们是给f赋值了一个匿名函数嘛,因此它永远是个函数,我们不通过f()调动这个函数,右面的箭头函数就不可能执行,所以千万不要以为f会等于return回来的param,除非直接让箭头函数执行才是这样。
var f = (() => {return 123})();