概念:ECMAScript 6 也称为 ES6
一、let和const
特点:
- 块级作用域
- 不存在默认提升
- 不能重复定义
- var会挂载到window上,let和const不会
- 暂时性死区(TDZ)
1.块级作用域
概念:每一个{}就是一个独特的块级作用域
//利用函数模拟块级作用域
(function(){
var x=20
})();
console.log(x)//报错:x未定义
通过let和const定义的变量只能在其内部生效
if(true){
let x=2;
const y=3
}
console.log(x)//报错:x未定义
console.log(y)//报错:y未定义
2.不存在默认提升
在之前用var的时候会有默认提升到函数顶部的特点
console.log(x)//undefined
var x=20;
console.log(x)//20
这是因为使用var的时候会默认拆分程var x和x=20,var x会被默认提升到函数顶部先执行但是赋值得等到原来的地方才会执行,所以在上方输出x是undefined,在后面输出是为20,这样很容易出现问题。
console.log(x);
let x=20//报错:不能再定义之前使用
3.不能重复定义
在使用var的时候可以重复定义一个变量的时候会使用后定义的那个变量的值
var x=20;
var x=30;
console.log(x)//30
这个问题在别的语言中不是很严谨,在合作开发的时候会出问题
let x=0;
let x=2;//报错:x已经被定义
4.var会挂载到window上,let和const不会
使用var定义的全局变量会被挂载到window上,但是let和const不会
var x=20;
console.log(window.x)//20
let y=10;
console.log(window.y)//undefined
5.暂时性死区(TDZ)
let和const命令会形成块级作用域,如果在声明之前使用变量,就会报错,但是var不会
var a=10;
if(true){
console.log(a)//10
var a=20
}
let b=10;
if(true){
console.log(a)//报错
let a=20
}
let和const的区别:
let通常被用来定义变量,const用来定义常量
如果修改const的值会报错
const a=1;
a=2//报错
但是如果是赋值给复杂数据类型,只要不修改内存地址就不会报错
const obj={
name:"小明",
age:19
}
obj.name="小红",
obj.age=30
console.log(obj)//小红,30
const arr=[1,2,3,4,5,6]
arr[3]=10;
console.log(arr)//[1,2,3,10,5,6]
二、模板字符串
在之前我们使用+来拼接字符串,如果需要的东西特别长,也无法换行,看起来特别麻烦,所以有了模板字符串(``)
let name="小明";
console.log(name+"你好啊")
console.log(`${name}你好啊`);
console.log(`${name}
你好啊`);
三、解构赋值
在es6模块化开发 node模块化开发中将每一个特殊的功能封装起来;
将复杂的结构简化成简单的结构,解构必须是对象或者数组,前方解构的变量必须和复杂结构属性同名
let obj={
name:"小明",
age:19,
weigth:180
}
let {name,age,weight}=obj;
console.log(name,age,weight)//小明,19,180
const arr=[1,2,3];
let {a,b,c}=arr
console.log(a,b,c)//1,2,3
用该方法可以很简单的交换两个数字值
let a=1;
let b=2;
[a,b]=[b,a];
console.log(a,b)//2,1
三、对象的简写形式
let name="小明",
let age=19;
const obj={
name:name,
age:age,
eat:function(){
console.log("我能吃")
}
}
这是在上方有对应的变量的时候创建对象的方式,发现这样写name和name变量重名,就可以使用对象的简写形式,函数也可以使用简写形式
let name="小明",
let age=19;
const obj={
name,
age,
eat(){
console.log("我能吃")
}
}
简写完以后代码更加的简单,看起来更加的舒服
四、箭头函数
特点:
- 箭头函数的简写
- 没有argument参数只有rest参数
- this的指向永远都是被定义的环境
- 箭头函数没有默认提升
- 箭头函数不能用来创建构造函数
箭头函数的基本写法
let fn=(x)=>{
return x*x
}
fn(2)//4
1.箭头函数的简写
因为上面的函数只有一个参数所以能能吧参数旁边的括号省略
因为上面的那个函数只有一条语句并且是return语句,所以大括号和return都能省略
省略后的代码
let fn=x=>x*x
fn(2)//4
这样省略后代码可以变得更加的简洁
2.没有argument参数只有rest参数
在function创建的函数中有一个默认的arguments参数,是用来收集所有的参数
function sum(){
let sum=0
for(let i=0;i<arguments.length;i++){
sum+=arguments[i]
}
return sum
}
console.log(sum(1,2,3,4,5))//15
这样在处理不确定有多少个参数的时候会很好用,箭头函数没有这个但是有个用来代替的rest参数
let sum=(...rest)=>{
let sum=0
for(let i=0;i<rest.length;i++){
sum+=rest[i]
}
return sum
}
console.log(sum(1,2,3,4,5))//15
这两个还是有一点小区别的,就是如果有设置几个参数的时候
function sum1(a,b){
console.log(arguments)
}
sum1(1,2,3,4,5)
let sum2=(a,b,...rest)=>{
console.log(rest)
}
sum2(1,2,3,4,5)
可以发现,使用arguments的时候还是会拿到所有的参数,但是rest只能拿到剩下的参数
3.this的指向永远都是被定义的环境
在函数中this的指向不是特别的确定,在不同的环境中,this的指向会不同,很麻烦,
在箭头函数中this的指向指向创建的地方
比如在创建一个div然后点击过了一秒之后变色的案例
let btn1=document.getElementsByTagName("div")[0]
btn1.addEventListener("click",function(){
let _this=this
setTimeout(function(){
console.log(this)
_this.style.backgroundColor="blue"
},1000)
})
为了达到效果需要使用一个中间变量(_this)去保存this才能达到效果,如果在外面之间,可以发现输出的this是指向window,如果直接使用this无法达到效果
let btn1=document.getElementsByTagName("div")[0]
btn1.addEventListener("click",function(){
setTimeout(()=>{
console.log(this)
this.style.backgroundColor="blue"
},1000)
})
在使用了箭头函数之后,因为this的指向永远指向创建的地方也就是绑定事件的地方所以指向的是button,能直接达到效果,比较的方便
4.箭头函数没有默认提升
用function定义函数的时候,function的函数会被提升顶部优先执行
fn()//1
function fn(){
console.log(1)
}
可以发现这样是会执行函数的
但是如果使用箭头函数的写法,就不会执行
fn();//报错:fn不是一个函数
var fn=()=>{
console.log(1)
}
5.箭头函数不能用来创建构造函数
由于构造函数的创建方式是通过new来创建的,
new的时候做了以下几个步骤
- 在内存中创建一个新的空对象
- 让this指向这个新的对象
- 执行构造函数里面的代码,给这个新的对象添加属性和方法
- 返回这个新的对象(所以构造函数里面不需要return)
由于箭头函数的this始终指向创建的时候的位置,不会指向那个新的对象,所以无法用来创建新的对象
五、函数的默认参数
创建函数的时候,形参可以设置一些默认的参数
function sum(a,b=10){
d=a+b
console.log(d)
}
sum(1);//11
sum(1,2);//3
当调用函数的时候,传入参数,如果没有传入的时候就用这个默认值,如果传入参数就用那个传入的默认值
这个也可以配合上方的解构赋值一起使用
const obj={
name:"小明",
age:18,
address:"上海"
}
function hello({name,age,address}){
console.log(`${age}岁的${name},家在${address}`)
}
hello(obj)
六.扩展运算符
用途:
1.用于复杂运算符的展开
let arr=[1,2,3,4]
console.log(...arr)//1 2 3 4
这里输出的不是数组
2.用于合并数组
let arr1=[1,2,3,4];
let arr2=[5,6,7,8];
arr2=[...arr2,...arr1];
console.log(arr2)
3.用于复制数组
由于直接复制数值,复制的是内存地址而不是数组,所以一旦改变,原数组也会跟着改变(浅拷贝)
const arr1=[1,2,3,4];
let a=arr1;
a.push(5);
console.log(arr1)//[1,2,3,4,5]
如果使用扩展运算符复制数组,会发现改变复制的数组,原数组不会跟着变(深拷贝)
const arr1=[1,2,3,4];
let a=[...arr1];
a.push(5);
console.log(arr1)//[1,2,3,4]
console.log(a)//[1,2,3,4,5]
也可以用来复制对象
const obj={
name:"张三",
age:21,
weight:190
}
const obj2={
...obj
}
console.log(obj2)
5.可以用来计算数组中的最大值
原本没有的时候需要使用apply改变指向才能达到效果
const arr=[1,2,3,4.12,127,1,1423];
let max=Math.max.apply(null,arr);
let max2=Math.max(...arr);
console.log(max2)//1423
console.log(max)//1423