es6基础知识点1

在项目中已经不知不觉开始使用es6语法,比如箭头函数、let关键字等等。现在来梳理一下ES6知识点。

关于ES6

ECMAScript 6(ES6)是JavaScript的最新标准化版本。es6标准化已经很长一段时间了,浏览器也广泛支持。但并非所有浏览器都已经支持es6,此时则需要使用转换器将代码转换成es5版本,如Babel。

例如:

一段es6代码:

let nums = [1,2,3];
let doubleNums = nums.map((e) => e*2);

Babel会将其转换为一下es5代码:

"use strict";

var nums = [1,2,3];
var doubleNums = nums.map(function (e){
    return e * 2
});

下面开始梳理一些es6的知识点。

1. let

1.1 let基本用法

let的用法类似var,但是声明的变量,只在let所在的代码块内有效。

例如:

let x = 1;
if (x == 1) {
    let x = 2;
    console.log(x); // 2;
}
console.log(x); // 1

首先,声明了变量x,并赋值1

然后,x在if块中声明一个具有相同名称的新变量,赋值2

最后,输出if内x为2,外部不受影响为1(块内有效,相当于if快内的x是一个新变量)

注意:如果使用var,则外部也会变成2

1.2 let与全局变量

当使用var声明全局变量时,会将变量添加到全局对象中,在web浏览器情况下,全局对象为window。

例如:

var a = 1;
console.log(window.1);//1

但是使用let关键字声明变量,不会将变量添加到全局对象中。

例如:

var b = 2;
console.log(window.b);//undefined

1.3 let在for循环中

使用var时,有一个问题:

for(var i = 0;i < 5;i++) {
    setTimeout(function(){
        console.log(i);//结果为:5次5
    },1000);
}

原因是经过5次迭代,i的变量为5,并且传递给了setTimeout的回调函数。

在es5中,需要通过创建另一个作用域来解决上述问题,以便每个回调函数实例引用一个新变量。而要创建一个新的范围,需要创建一个函数。通常,使用IIFE模式如下:

for(var i = 0;i < 5;i++) {
	(function(j){
        setTimeout(function(){
            console.log(j);//0 1 2 3 4
        },1000);
	})(i); 
}

在es6中,let关键字在每个循环迭代中声明一个新变量,因此只需要将var改成let即可:

for (let i = 0; i < 5; i++) {
    setTimeout(() => console.log(i), 1000);
}

1.4 let 变量提升

首先,看一个例子:

(function(){
    console.log(name);//ReferenceError: name is not defined  (使用var输出undefined)
    let name = 'Summer';
})();

在函数中,name在声明之前访问会导致ReferenceError: name is not defined。以此可知,JavaScript引擎会将let声明的变量提升到块的顶部,但是如果在声明之前引用,则会ReferenceError。如果使用var则会发生变量提升,name在声明之前已经存在了,只是没有值,所以输出undefined。

1.5 TDZ

使用let声明变量存在暂时死区(时滞盲区)TDZ。是指从块开始到处理变量声明的时间。

(function(){
    // 进入新的块范围, TDZ start
    let log = function () {
        console.log(name); // ReferenceError: name is not defined
    };
 
    // 这是TDZ并访问name变量 
    // 如果在此调用log(),将得到 ReferenceError
 
    let name = 1; // TDZ 结束
    log(); // 在TDZ之外调用
})();

首先进入块范围,TDZ开始。

然后,日志函数表达式访问name变量。但是该log()函数未执行,因此是没问题的。

再然后,声明name变量,并赋值1。从块范围开始到name变量被访问的时间成为时间死亡区(TDZ)。JavaScript引擎处理声明,TDZ结束。

最后,调用log()访问name变量

在let变量声明之前,是一个不存在的变量,类型是未定义的。

(() => {
	//TDZ 开始
	console.log(typeof a) //undefined
    var a = 1;
    
    console.log(typeof b) //ReferenceError
    let b = 2; //TDZ 结束
})();

注意:let在同一个块范围中,不能重复声明

2. const

在es6中,const关键字用于声明常量。声明的变量只读,不能修改,且声明变量时必须初始化一个值。(通常,JavaScript的常量变量名大写)

除了以上,const与let声明变量基本一样。

2.1 常量 and 对象

使用const创建的变量是只读的,但是不以为着const变量引用是不可变的实际值。(what???蒙圈!!!)

举例说明:

const person = {name:'Summer'};
person.name = 'Minya';//正确的,不会报错
console.log(person.name);//Minya

可以修改对象里属性的值,但是不能给整个对象重新赋值,比如:

person.name = {name:'who'};//TypeError

如何确保对象的属性值也是不可变的?可以使用Object.freeze冻结:

const person = Object.freeze({name:'Summer'});
person.name = 'Minya';
console.log(person.name);//Summer

Object.freeze是浅冻结,如:

const person2 = Object.freeze({
    name:'Summer',
    friends:{
        first:'Minya',
        second:'who'
    }
});
//修改
person2.friends.first = 'handsome';//此时值已修改成功

2.2 for循环

使用for…of,使用let时:

var nums = [1,2,3];
for(let num of nums){
    console.log(num) //1 2 3
}

使用const:

var nums = [1,2,3];
for(const num of nums){
    console.log(num) //1 2 3
}
//以上代码是有效的,在每次迭代中for...of为const创建一个新的绑定。即const常量是每次迭代中创建的

错误用法:

for (const i = 0; i < nums.length; i++) { // TypeError: Assignment to constant variable.
    console.log(nums[i]);
}
//错误原因,声明只在循环体开始之前被创建(一次),不能修改

3. 箭头函数

首先,es5函数表达式写法如下:

var add = function(x,y) {
    return x+y;
}
add(1,2);//3

将上述函数表达式换成箭头函数表达式写法,如下:

var add = (x,y) => x+y;
add(1,2);//3

console.log(typeof add) //function
console.log(add instanceof Function) //true  箭头函数也是Function的一个实例

3.1 参数

对于参数在两个或两个以上的箭头函数,可以使用以下写法:

(x1,x2,...,xn) => expression;

//其中 =>expression 等价于 =>{return expression;}

举例说明:

var nums = [2,3,1];
nums.sort((a,b) => b-a);//排序
console.log(nums);//[3,2,1]

单个参数:

x => {语句}
或者:
(x) => {语句}

如:
var names = ['John', 'Mac', 'Peter'];
var lengths = names.map(name => name.length);
 
console.log(lengths);

没有参数:

() => {语句}
如:
var names = ['John', 'Mac', 'Peter'];
var lengths = () => names.length

lengths();//3

参数与括号之间不能换行:

//以下写法错误,SyntaxError
var add = (x,y)
=> x+y;

//正确写法
var add = (x,y) =>
x+y;

//正确写法
var add = (
        x,
        y) =>
        x+y;

3.2 箭头函数与es5的function函数比较

区别:

1.在箭头函数中,本身不存在this对象;

2.不可以使用new命令(不可以当做构造函数);

3.不可以使用arguments对象,不存在。可以使用rest参数代替;

4.不能使用super

关于this的区别,举例说明:

在es5的函数中:

var add = function(x){
    this.x = x
    setTimeout(function(){
        console.log(this.x)//undefined,此时this是指向setTImeout的回调函数function里的
    },0);
}

add(1);

在箭头函数中:

var add = function(x){
    this.x = x
    setTimeout(() => {
        console.log(this.x) //1 箭头函数没有this,所以这里的this指向add这个function的this
    },0);
}

add(1);

4. 参数

4.1 默认参数

举例说明:

function add(x=10){
	console.log(x)
}

add();//10
add(undefined);//10
add(20);//20

4.2 rest参数(…)

不定数量的参数:

function add(x1,x2,...xn){
    //...
}
//最后一个参数xn前面加上三个点(...)称为rest参数(...xn)

比如add(1,2,3,100,200,300),此时,x1=1,x2=2,xn=[3,100,200,300]

本篇主要总结let、const、箭头函数、参数,下篇继续总结es6知识点。

下一篇:spread运算符、解构、模板文字等