1、let关键字
ES6中 新增的用于声明变量的关键字。
使用let关键字声明的变量的特点:
(1)let声明的变量只在所处于的块级有效(使用let关键字声明的变量具有块级作用域)
if(true) {
let a = 10;
console.log(a);//输出10
}
console.log(a);//报错
注意:使用let关键字声明的变量才具有块级作用域,使用var声明的变量不具备块级作用域特性。
拥有块级作用域的变量的好处:防止循环变量变成全局变量。
//使用var关键字
for(var i = 0;i < 2;i++) {
}
console.log(i);//输出2
//使用let关键字
for(let i = 0;i < 2;i++) {
}
console.log(i);//报错
(2)使用let关键字声明的变量不存在变量提升
var关键字可以先使用再声明,但是let关键字必须先声明才能使用。
console.log(a);//报错
let a = 10;
(3)使用let关键字声明的变量具有暂时性死区
var num = 20;
if(true) {
console.log(num);//报错
let num = 10;
}
var关键字的经典面试题:
var arr = [];
for(var i = 0;i < 2;i++) {
arr[i] = function() {
console.log(i);//输出两次2
};
}
arr[0]();
arr[1]();
//此题的关键点在于变量i是全局的,函数执行时输出的都是全局作用域下的值。
let关键字经典面试题:
let arr = [];
for(let i = 0;i < 2;i++) {
arr[i] = function() {
console.log(i);//第一次输出0,第二次输出1
};
}
arr[0]();
arr[1]();
//此题的关键点在于let关键字会生成两个块级作用域,一个是let i = 0,另一个是let i = 1,它们会分别输出结果
2、const关键字
作用:声明常量,常量就是值(内存地址)不能变化的量。
使用const关键字声明的常量的特点:
(1)具有块级作用域
if(true) {
const a = 10;
console.log(a);//输出10
}
console.log(a);//报错
(2)声明常量时必须赋值
const PI;//报错
const PI = 3.14;//正确
(3)常量赋值后,值不能修改
//基本数据类型
const PI = 3.14;
PI = 100;//报错
注意:对于基本数据类型来讲,常量在声明之后值不可更改
//复杂数据类型
const ary = [100,200];
ary[0] = 'a';//没有更改ary常量在内存中的存储地址
ary[1] = 'b';
console.log(ary);//输出['a','b']
ary = ['a','b'];//报错,改变了ary常量在内存中的存储地址
注意:对于复杂数据类型来讲,它内部的值可以更改,但是对它重新赋值是不可以的,重新赋值等于改变了它的内存地址
3、let、const、var的区别
(1)使用var声明的变量,其作用域为该语句所在的函数内,且存在变量提升现象,值可更改;
(2)使用let声明的变量,其作用域为该语句所在的代码块内,不存在变量提升,值可更改;
(3)使用const声明的是常量,在后面出现的代码中不能再修改该常量的值,不存在变量提升。
4、解构赋值
ES6允许从数组中提取值,按照对应位置对变量赋值。对象也可以实现解构。
(1)数组解构
let [a,b,c] = [1,2,3];//等号左边的中括号不是数组,它代表解构,a、b、c为变量,不用加引号
console.log(a);//输出1
console.log(b);//输出2
console.log(c);//输出3
//如果解构不成功,变量的值为undefined
let [a] = [];
console.log(a);//输出undefined
let [a,b] = [1];
console.log(a);//输出1
console.log(b);//输出undefined
(2)对象解构
对象解构允许我们使用变量的名字匹配对象的属性,匹配成功将对象属性的值赋给变量。
//写法一
let person = {
name:"zhangsan",
age:18
};
let {name,age} = person;
console.log(name);//输出zhangsan
console.log(age);//输出18
//写法二
let person = {
name:"zhangsan",
age:18
};
let {name:myName,age:myAge} = person;
console.log(myName);//输出zhangsan
console.log(myAge);//输出18
5、箭头函数
ES6中新增的定义函数的方式。
语法:() => {}
const fn = () => { //赋值给常量fn
console.log(123);//输出123
}
fn();
箭头函数的特点:
(1)函数体中只有一句代码,且代码的执行结果就是返回值,可以省略大括号
const sum = (a,b) => a + b;
const result = sum(10,10);
console.log(result);//输出20
(2)如果形参只有一个,可以省略小括号
const fn = a => a;
const result = fn(10);
console.log(result);//输出10
6、箭头函数中this的指向
箭头函数不绑定关键字(也就是说没有自己的this关键字),箭头函数中的this,指向的是函数定义位置的上下文this。
const obj = {
name:"zhangsan"
}
function fn (){
console.log(this);//this一开始指向window,由fn.call(obj)改变了this的指向,此时指向obj
return () => {
console.log(this);//此时箭头函数被定义在fn函数中,fn函数中的this指向obj,所以箭头函数中的this也指向obj
}
}
const resFn = fn.call(obj);//调用fn,返回了一个箭头函数并赋给常量resFn
resFn();
箭头函数面试题:
var age = 25;
var obj = {
age:20,
say:() => {
alert(this.age);//警告框中弹出25
}
}
obj.say();
此题的关键点在于对象是不能产生作用域的,say方法被定义在了全局作用域下,say方法中的this指向的是window,所以弹出的是window对象下的age,也就是25
7、剩余参数
(1)剩余参数语法允许我们将一个不定数量的参数表示为一个数组(即实参个数大于形参个数时,可以将剩余的实参放在一个数组中)。
//传统写法
function sum(first,...args) {
console.log(first);//输出10
console.log(args);//输出[20,30]
}
sum(10,20,30);
//箭头函数写法
const sum = (...args) => { //...args表示一次性取到所有实参
console.log(...args);
};
sum(10,20);//输出[10,20]
sum(10,20,30);//输出[10,20,30]
注意:在ES6之前我们通常会使用函数内部的args一次性的取到所有实参,但在箭头函数中使用不了args。
const sum = (...args) => {
let total = 0;
args.forEach(item => total = total + item);
return total;
};
console.log(sum(10,20));//输出30
console.log(sum(10,20,30));//输出60
(2)剩余参数和解构配合使用
let students = ["张三","李四","王五"];
let [s1,...s2] = students;
console.log(s1);//输出张三
console.log(s2);//输出["李四","王五"]