解构赋值
(1)、什么是解构赋值
ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构赋值(Destructuring)。
关于给变量赋值,传统的变量赋值是这样的:
将数组的元素值1,2,3分别赋值给变量a,b,c,结果也是如我们所愿,赋值成功,这是一种传统的赋值方式。
变量的解构赋值:
注意到了吗?赋值的代码大大减少了,不需要分别把变量a,b,c分别声明定义和赋值,只需要将变量a,b,c作为一个数组的元素,然后将数组[1,2,3]赋值给数组[a,b,c]即可,变量a,b,c即可分别得到对应的值。
(2)、数组的解构赋值
解构赋值可以嵌套
如我们的预料,数组中即使再嵌套另一个数组,解构赋值也能为我们的变量准确的赋值,c1和c2的值分别为3.1 , 3.2,也就是赋值成功。
不完全解构
当左边的模式(你可以理解为格式)与右边不完全一样的时候,那么赋值过程中,只会给模式匹配成功的部分的变量赋值,例如:变量c没有在右边找到匹配的模式,所以无法进行赋值,但这并不影响变量a和变量b的赋值,因为它们在右边找到与之匹配的模式,这种叫做不完全解构。
赋值不成功,变量的值为undefined
还是接着上面的不完全解构例子讲解,变量a和变量b为不完全解构,那么变量c解构不成功会怎么样呢?记住,解构不成功,变量的值就等于undefined。相当于只声明了变量c,但是没赋值。
允许设定默认值
例子中变量c已经指定默认值为3,即使右侧没有与之对应的值赋给它也没关系,它都可以成功赋值为3,如果你想覆盖默认值3,只需赋一个有效的值即可。如下:
这个时候默认值3会被新的值4覆盖,c的值为4;注意:当新的值为undefined的时候,是不会覆盖默认值的。
演示示例: 数组的结构赋值
(3)、对象的解构赋值
对象的解构赋值跟数组的解构赋值很类似,我们来看一段小代码:
这段例子的代码是不是跟数组的解构赋值很相似,只不过是数组换成了对象。但是两者有一个不同的地方,我们对上面的代码稍做修改:
我把右侧的对象属性b和属性c的位置进行了调换,但这并不会影响赋值的结果,变量b和变量c的值不会改变,依然是b为2,c为3。这就告诉我们对象的解构赋值不会受到属性的排列次序影响(数组则会受影响),它是跟属性名关联起来的,变量名要和属性名一致,才会成功赋值。
如果变量找不到与其名字相同的属性,就会赋值不成功,如下面的例子:
变量a在右侧找不到与之名字匹配的属性a,所以变量a赋值不成功,a的值为undefined。
但也不是完全没有办法补救的,如果你想给一个变量名与属性名不一样的变量解构赋值,可以这样写:
变量a在右侧找不到与之名字匹配的属性a,所以变量a赋值不成功,a的值为undefined。
但也不是完全没有办法补救的,如果你想给一个变量名与属性名不一样的变量解构赋值,可以这样写:
这样变量a同样可以赋值成功,a的值最终为2。
对象的解构赋值的用法与数组的解构赋值也很类似:
对象解构赋值也可以嵌套
可以指定默认值
(4)、字符串的解构赋值
除了对象和数组可以解构赋值外,字符串也可以这么玩,看看下面的例子:
这是因为在解构赋值的过程中,字符串被转换成了一个类似数组的对象。变量a,b,c,d,e,f都分别赋上了对应的值。
演示示例:字符串的结构赋值
(5)、解构赋值的用途
1. 交换变量的值
传统做法最常用的是引入第三个变量来临时存放,如下:
但是有了解构赋值,想交换两个变量的值就简单多了。看下面的代码:
简单的一句代码即可成功交换x,y的值。
2. 提取函数返回的多个值
函数只能返回一个值,我们可以将多个值装在一个数组或者对象中,再用解构赋值快速提取其中的值。
将demo函数的运行结果通过结构赋值给变量name和age,实现快速的提取对应的值。
3. 定义函数参数
通过这种写法, 很方便就能提取JSON对象中想要的参数,例如案例中,我们只需要获取实参中的:a,b,c,而不需要关其他的参数,比如:d或者其他更多的参数。
4. 函数参数的默认值
传统的参数默认值的实现方式是,先判断该参数是否为undefined,如果是代表没传,需要手动给它赋一个值,如:
但是有了解构赋值,一切都变得简单很多!看下面的代码:
上面的代码给我们展示了通过解构赋值设定函数参数的默认值,简洁地代码即可实现。函数调用的时候没有传入对应的name参数,此时name就会使用默认值:“张三”,是不是很简洁很方便。
以上介绍了解构赋值的4个用途,你是不是也感觉到了它给我们带来的方便,它使我们的代码量大大的减少,并且语法十分清晰,增加了代码的可读性和表现力。
演示示例:结构赋值的用途
5、字符串的用法
(1)、模版字符串
ES6中引入了模板字符串(Template Literal),是创建字符串的一种新方法。模板字符串使用反引号 (` `) 来代替普通字符串中的用双引号和单引号。模板字符串可以包含特定语法(${expression})的占位符。有了这个新特性,我们就能更好地控制动态字符串。这将告别长串连接字符串的日子。
假如我们要拼接一段话:举个栗子:大家好,我是亚亚,我来自河南,我今年22岁了,我的爱好是狼人杀。
const Person = {
name: "亚亚",
age: 22,
hometown: "河南",
hobby: "狼人杀"
}
const intro = "大家好,我是" + Person.name + ",我来自" + Person.hometown +
",我今年" + Person.age + "岁了,我的爱好是" + Person.hobby + "。"
console.log(intro)
但是你会发现这样写很麻烦,一会中文一会英文,一会双引号一会加号+。当我们使用了es6中的模板字符串以后,你会发现新的大陆!
const intro2 =
`大家好,我是${Person.name},我来自${Person.hometown},我今年${Person.age}岁了,我的爱好是${Person.hobby}。 `
console.log(intro2)
另外{}内可以写一些表达式,比如:
const intro3 =
`大家好,我是${Person.name},我来自${Person.hometown},我今年${Person.age}岁了,我的爱好是${Person.hobby},我明年就${Person.age + 1}岁了,我已经是${Person.age > 18 ? '成年人' : '未成年'}了。`
console.log(intro3)
(2)、repeat函数
repeat( )函数:将目标字符串重复N次,返回一个新的字符串,不影响目标字符串。
重复3次后返回一个新字符串赋值给name2,name1不受影响,所以name1的值不变。
(3)、includes函数
includes( )函数:判断字符串中是否含有指定的子字符串,返回true表示含有和false表示未含有。第二个参数选填,表示开始搜索的位置。
传统的做法我们可以借助indexOf( )函数来实现,如果含有指定的字符串,indexOf( )函数就会子字符串首次出现的位置,不含有,则返回-1。我们通过返回值是否为-1来判断字符串中是否含有指定的子字符串,但是,我们现在可以用includes( )函数代替indexOf( )函数,因为它的返回值更直观(true或false),况且我们并不关心子字符串出现的位置。
注意,上面最后一句代码,第二个参数为1,表示从第2个字符“端“开始搜索,第一个字符”前“的位置是0。
(4)、startsWith函数
startsWith( )函数:判断指定的子字符串是否出现在目标字符串的开头位置,第二个参数选填,表示开始搜索的位置。
我们如果判断字符串是否以某个子字符串开头,就可以直接使用startsWith( )函数即可,同样,第二个参数为1表示从第2个字符开始搜索。若要从第一个字符开始搜索,参数应该为0或者为空(默认从第一个字符开始搜索)。
(5)、endsWith函数
endsWith( )函数:判断子字符串是否出现在目标字符串的尾部位置,第二个参数选填,表示针对前N个字符。
(6)、string.raw函数
最后讲解的一个函数是String.raw( );看函数名raw是未加工的的意思,正如这个函数的作用一样:返回字符串最原始的样貌,即使字符串中含有转义符,它都视而不见,直接输出。举个例子: 未经String.raw( )处理的字符串:
\n会被识别为换行符,实现换行效果,而经过String.raw( )的同一个字符串的结果是:
\n被识别为\和n两个字符,失去换行的效果,直接输出,这就是String.raw( )的功能。它常用来作为一个模板字符串的处理函数,也就是直接在后面加一个模板字符串。
演示示例:新增字符串的用法
6、数组的用法
(1)、Array.of函数
函数作用:将一组值,转换成数组。
是不是很好理解,传进去的数字是:1~5,最后经过Array.of函数处理,得到了一个数组,而数组的内容就是[1,2,3,4,5]。
(2)、Array.from函数
函数作用:可以将类似数组的对象或者可遍历的对象转换成真正的数组。
有哪些是类似数组的对象?最常见的就是调用getElementsByTagName方法得到的结果,它就是一个类似数组的结果,getElementsByTagName方法一定不陌生吧,我们来看一下:
看上面的代码,我们调用getElementsByTagName方法,得到结果存到变量ele中,然后对其进行类型判断,发现变量ele并不是一个数组,而是一个对象Array,一个类似数组的对象Object,接下来我们用Array.from( )对其进行处理,并再一次进行类型判断。
这个时候我们运行的结果是:true,也就是经过Array.from函数处理返回的结果,已经变成了一个真正的数组。
Array.from函数其中一个用处就是将字符串转换成数组。看下面的案例:
字符串“hello”被转换后的返回的结果已经变成了一个数组:["h", "e", "l", "l","o"]。
(3)、find函数
函数作用:找出数组中符合条件的第一个元素。
看上面的代码,find()函数的参数是一个匿名函数,数组的每个元素都会进入匿名函数执行,直到结果为true,find函数就会返回value的值:3。倘若所有元素都不符合匿名函数的条件,find( )函数就会返回undefind。看下面的代码案例:
上面的案例中,数组中没有存在大于7的元素,所以find函数就会返回:undefined。
(4)、findIndex函数
函数作用:返回符合条件的第一个数组成员的位置下标。
上面的代码结果是:2,因为数组元素中大于8的元素是9,而元素9的位置正是2,(数组元素是从0算起)。倘若所有元素都不符合匿名函数的条件,findIndex( )函数就会返回-1。
(5)、fill函数
函数作用:用指定的值,填充到数组。
经过fill( )函数处理后的数组arr已经变成了[4,4,4];正如函数名fill(填充)一样。所有元素都被填充为数字4了。如果我想只填充部分元素可不可以呢?可以的,fill( )函数提供了一些参数,用于指定填充的起始位置和结束位置。
还是上面的案例,我们稍做调整,再演示一下:
上面的代码中第2个参数和第3个参数的意思是:从位置1的元素开始填充数字4,截止到位置3之前,所以是位置1和位置2的元素被数字4填充了,得到的结果:[1,4,4]。
(6)、entries函数
函数作用:对数组的键值对进行遍历,返回一个遍历器,可以用for..of对其进行遍历。
遍历器和for..of也是ES6的新增特性,目前我们还没有介绍到,我们可以先进行一下简单地认知。
回到我们的entries( )函数,看个案例:
上面的代码中,我们将entries( )函数返回的一个遍历器,用for...of进行遍历,并打印出结果,能得到数组的键值:0和1,以及对应的数组元素:‘a‘和’b‘。
如果只想遍历数组的索引键的话,可以使用另一个实例方法。
(7)、keys函数
函数作用:对数组的索引键进行遍历,返回一个遍历器。
正如上面的运行结果一样,我们打印出了数组的索引键:0和1。
如果我们想只对数组的元素进行遍历,我们可以使用两一个实例方法。
(8)、values函数
作用:对数组的元素进行遍历,返回一个遍历器。
上面的代码运行结果也是我们预料之中的,最终打印出了数组的元素:a和b。
除了新增函数以外,ES6还为数组带来了一个新的概念:数组推导。