- 箭头函数
- 类
- 模块
- Promises 对象
- 异步生成器 Generators
- let以及const语法
let 跟 var 之间的差异1:
使用var声明变量,如重复声明,使后面的变量值会覆盖前面的变量值,而不会报错,这样会让我们调试变得非常困难,这在小型的项目也许不会发生,但是在大规模项目或代码规模量大的时候有可能会发生:
var myName = "Bob";
var myName = "Alice";
// 最终myName的值被更改为“Alice”
使用let,无法重复声明相同的变量名:
let myName = "Bob";
let myName = "Alice"; //报错!!!重复声明myName这个变量会报错
let 跟 var 之间的差异2:
let 跟 var 关键字作用相似,但是它们之间的某些特性不同:
- var声明的变量作用域是全局的,或是在函数块内的。
- let声明的变量作用域是在当前代码块,表达式或语句中。
for(var i =0;i < 3;i++) {
}
console.log(i); //控制台打印3,i 等于 3
这里的for循环块内的 i 是全局变量,类似于👇:
var i ;
for(i =0;i < 3;i++) {
}
console.log(i); //控制台打印3,i 等于 3
有种情况,当我们在for循环里的函数,使用了i变量,就会出现上面的情况:
var printNum;
for(var i =0;i < 3;i++) {
if(i ==2){
printNum = function(){
console.log(i)
}
}
}
printNum(i); //控制台打印3,因为i等于 3
可以看到,控制台打印的是3,并不是2,因为,i是全局的,它随着for循环里的值变化而变化,当调用printNum函数时,打印的是循环内最终的值。
接下来,我们可以使用let,解决这个问题,得到想要的结果:
let printNum;
for(let i =0;i < 3;i++) {
if(i ==2){
printNum = function(){
console.log(i)
}
}
}
printNum(i); //控制台打印2
上面这个例子,使用了let关键字,这样for循环里面的变量i的作用域就只在它里面而已,这样外部printNum函数保持了i为2的值,调用它就能打印出我们想要的结果。
我们再来看一个综合例子,加深对let的理解:
function checkCar() {
"use strict"; //严格模式,用于检测代码错误或不安全的行为,如 pi = 3.14,少了声明的关键字,会报错!
let car = "smallCar";
if (true) {
let car= "bigCar";
console.log("car 是: ", car);
}
console.log("car 是: ", car);
}
checkScope();
//控制台先后打印:
// car 是:bigCar
// car 是:smallCar
可以看到 if语块内的car,跟外部的car是没有任何关系的,都有各自的作用域,虽然使用let可以避免这样的错误,但是在实际编码中,尽量避免使用相同的变量名。
const与let的差异:
const 拥有let的所有优点,但const声明的变量是只读的,也就是说,声明后,不能再次进行修改:
const MY_KEY = "my Keys";
MY_KEY = "not my keys"; //报错,不能修改!
const的使用场景一般用于不会再次修改的变量,通常称为常量,常量名为全部字母大写,不同字母用下划线分割,如我们在做数据持久化,通常需要指定它们的key,一般这样的值定义一次,不需要改动:
const USERNAME = "username";
localStorage.setItem(USERNAME,"Bob");
const声明的数组,元素值可以被更改:
const array = [8,9,10];
array = [1,2]; //报错
array[0] = 1; //array的8被修改为1
//array的值为:[1,9,10]
由此可见,const对于数组来说,只能保证常量名的指向不被更改,简单点来说就是不能直接用常量名赋予其它的值,但可以通过数组的索引对值更改。
Object.freeze保证对象的属性不被更改:
上面这个例子可以发现const并不能保证对象不被修改,这里ES6新增了一个Object.freeze()函数,能保证对象不被他人增、删、改,任何试图修改的操作都会被忽略:
let men = {
name:"周杰伦",
age:34
};
Object.freeze(men);
men.mother = "叶惠美"; // men 对象被冻结了,这个操作会被忽略
men.name = "张惠妹"; // 也会被忽略,不允许数据改变
console.log(obj);
// { name: "周杰伦", age:34}
箭头函数:
优点: 简洁、优雅
使用场景:1、不考虑给函数命名 2、只需要传递参数 3、不考虑复用
当遇到这些场景,你都应该优先考虑使用它。
const today = () =>{
return new Date();
}
当只需要返回一个值时,箭头函数允许你省略函数体和return:
const today = () => new Date();
你可以给箭头函数传递参数
const add = (x,y) =>{
return x + y;
}
add(1,1) //return 2
给函数设置默认参数
通过给函数设置的参数设置默认值,能让我们的函数更加强大。
const greeting = function (name = "World"){
console.log("Hello " + name);
}
greeting("Jim"); //打印 Hello Jim
greeting(); //打印Hello World
当没有给函数传入指定值的时候(也就是undefined),函数会使用默认提供的参数。
函数:剩余参数
通过使用剩余(rest)参数,可以更灵活的创建函数。通过它可以传递任意多个参数,而无需繁琐的定义它们。
function fruit(...args){
console.log("I bought " + args.length + " fruit");
}
fruit("apple","banner","orange");
//打印 I bought 3 fruit
利用这特性我们还可以使用filter、map、reduce函数,操作这些参数。
//返回大于0的数
function greaterThanZero(...num){
return num.filter((item) => item > 0);
}
console.log(greaterThanZero(-8,-1,-3,1,2,3));
//打印:[1, 2, 3]
展开操作符(spread),展开数组
通过展开操作符能够铺开数组和拷贝数组,请看栗子更容易理解:
let arr1 = [3,45,21];
console.log(Math.min(...arr1));
//打印:3
通过...arr1,把数组里面的参数一一列出,变为Math.min(3,45,21),所以得到我们想要的值。
下面通过展开操作符复制一个数组:
let arr1 = ["one","two","three","four","five"];
let arr2 = [...arr1];
//这样arr1里的值就被拷到arr2里边了,arr1里的值改变并不会影响到arr2
展开操作符只能用于数组中或者函数参数中,比如下面是错误的:
let arr = ["alert","error"];
let tip = ...arr; //报错
对象的解构赋值
对象的解构赋值非常强大,能够简单快速的取得变量和值。
例1:
let obj = {a:1,b:2,c:3};
const {a,b,c} = obj;
console.log(a,b,c);
//打印:123
例2:
let obj = {a:"one ",b:"two ",c:"three"};
const {a:x,b:y,c:z} = obj;
console.log(x,y,z);
//打印:one two three
例2的解构赋值,你可以理解为把a的值拷贝并交到x的手上
数组的解构
同样解构数组跟对象解构一样简单:
let myArr = [1,2,3,4,5];
const [a,b] = myArr;
//a = 1 , b=2
我们也可以利用剩余参数,获取剩余的值成为新的数组:
let myArr = [1,2,3,4,5];
const [a,b,...newArr] = myArr;
//a = 1 , b=2, newArr=[3,4,5]
把解构对象当做参数传入函数中
const shoppingList = {
apple:5,
jam:2,
soy:4
}
function goShopping(list){
let {apple,jam,soy} = list
}
//or 直接在写为函数参数
function goShopping({apple,jam,soy}){
return "apple: "+ apple + ",jam: "+ jam + ",soy: "+soy;
}
看到了吗?它让程序变得更简洁,真的极其方便。
简洁的函数声明
在过去函数的声明是这样的:
let person = {
name:"小明",
hobby: function() {
console.log(this.name + " 喜欢打篮球")
}
}
在ES6中,定义函数不必书写function关键字和冒号:
let person = {
name:"小明",
hobby() {
console.log(this.name + " 喜欢打篮球")
}
}
ES6中 import 和 require 的差异
编写程序时常我们需要从外部引入代码或者函数,使用require,会让文件内的所有函数或变量全部导入,但往往我们只需要部分引入。
在es6中提高了非常便利的工具,import 可以只导入某个部分,这样就提高了程序的加载速度和内存空间。
//应用语法
import { 函数名 } from "文件路径"
export 导出可复用的代码块
export能导出文件里的函数或变量,从而使用import来导入到目标文件里使用。实现代码的重用。
const capitalizeString = (string) => {
return string.charAt(0).toUpperCase() + string.slice(1);
}
export { capitalizeString } //导出函数。
export const place = "Beijing"; //导出变量。
or
const capitalizeString = (string) => {
return string.charAt(0).toUpperCase() + string.slice(1);
}
const place = "Beijing"; //导出变量。
export { capitalizeString,place } //导出函数。
使用 * 导入所有内容
咱们还可以使用 import 导入文件里的所有内容。
//语法
import * as 名字(这是一个对象) from "文件地址"
//例子
import * as myMathModule from "math_functions";
myMathModule.add(2,3);
myMathModule.subtract(5,3);
你在import * as 后面定义的名字,它是一个对象,保存了导入文件里的所有内容,你可以使用这个对象的.
语法来访问里面具体的内容。
用 export default 创建一个默认导出
刚刚我们学习了命名导出,但还有一个比较方便的默认导出,当只需要导出一个函数或值的时候,可以使用它,它常常用来给文件或模块创建返回值。
export default function subtract(x,y) {return x - y;}
导入一个默认导出
刚刚我们学习了一个默认导出,导入一个默认导出,跟之前的写法有些不同。
下面是从"math_functions"里导入一个默认导出的语法:
//减法
import subtract from "math_functions";
subtract(10,2);//返回8
在这里需要注意,导入一个默认导出,import 后面的名称不需要加花括号{}包围,你只需要在import之后写变量名即可。