浅谈ES6

1.var、let、const声明变量,有什么区别?

(1)作用域:
var 声明的变量不用多说,我们之前写js都是用这个来声明,但很少有人理解它的作用域,可以这样来说,var声明的变量属于function scope(方法作用域),可以简单的这样理解:如果一个变量用var定义且只在方法体中被声明过,那么这个变量就是局部变量,反之便是全局变量。可这样有时候并不是我们想要的,比如:

var a = 0;
if (a < 5){
  var b = 'Madman';
  console.log(a);  //0
  console.log(b); //Madman
}
console.log(a); //0
console.log(b); //Madman

我们发现,这四个都能打印出来对应的值。a 就不用多说了, b虽然被定义在 if 语句中,但是使用 var 定义,并没有在方法体内,所以 b 也是全局变量,然而我们只是想在这里被使用一次。ES6为了弥补这一不足,引入了 let 以及 const 。

let 和 const : 这两个在 ES6 中同样定义变量,但是它们属于 block scope(块级作用域),这个其实很好理解,如果上面例子中的 b 使用 let \ const 来定义,那么最后一个 console 会报 not defined 。因为 if 循环算是一个块级区域。

(2)重复声明:
var 可以重复声明同一个变量名,而 let 和 const 在同一个作用域下,只能被声明一次。

var a = 'Madman';
var a = '疯子';
let b = '李小呆';
let b = '哈哈哈';  //  错误
const c = 'php';
if(a == 'Madman'){
  const c = 'java';
}
console.log(c);  // php

上面例子中我们可以看到,在同一个作用域下不能用 let 和 const 声明相同名称的变量,所以在全局中使用 let 声明第二次 b 的时候,会报错;而我用 const 定义了两次变量 c ,但是它们不在同一个作用域下,故是两个变量。

(3)重新赋值
说一下 let 和 const 的区别,let 声明的变量是可以重新赋值的 ,而 const 声明的变量不可以重新赋值。
当然,如果只是单纯这样说的话表达的不是很明白,举个例子吧:

let a = 'Madman';
a = '李小呆'; 
const b = '哈哈哈';
b = '呵呵呵';  //错误!不可以被重复赋值

当然,const 声明的变量只是没办法重新赋值,但有一种情况却是可以:

const person = {
  name : 'Madman',
  age : 23
}
person = {
  name : '李小呆'
}   //错误
person.age = 18 ;
console.log(person);   //{name : 'Madman', age : 18} 
//可以看出,person对象的 age 属性被成功的修改。

person 是一个对象,对象是一种引用类型的值,当我给它赋值一个新的对象的时候,其实这个指针就指向了新的引用地址;而如果我们只是改变对象里的属性的话,这个对象本身的引用地址并没有发生变化。
如果连对象的属性都不想让它变化,那就使用const Madman = Object.freeze(person)

2.let 和 const 经常会被用在哪些地方?

(1)for 循环
在接触 ES6 之前呢,我们经常用到的 for 循环都是通过 var 来定义循环的次数的,比如:

for ( var v = 0; v<10 ; v++){
  console.log(v);
}

很明显,上面代码输出的结果是0到9;那么我们如果使用setTimeout(function(){})模拟一下ajax请求;

for ( var v = 0; v<10 ; v++){
  console.log(v);
  setTimeout(function(){
    console.log(`v:${v}`);
  })
}
浅谈ES6_第1张图片

此时,我们看到被 var 定义的变量 v 在 for 循环之后被打印了十次;可我们想让它输出像上面一样的结果,而并非 for 执行完之后再去执行setTimeout里面的语句;
那么,我们把 var 改成 let 试试:


浅谈ES6_第2张图片

可以看到,结果如我们所愿,为什么呢?
其实非要讲真正的原理我也不是很理解,但你可以这样理解,被let 定义的变量 v ,此时属于块级作用域,它只在一个 for 循环块中有效,所以每次结束这个块时,它都会等setTimeout执行完并输出v。

(2)变量提升
我们先来看一段代码:


这里为什么是undefined? 熟悉的人会知道在 js 中会有变量提升这以说法,那么什么是变量提升?

  • JavaScript 中,函数及变量的声明都将被提升到函数的最顶部。
  • JavaScript 中,变量可以在使用后声明,也就是变量可以先使用再声明。
  • JavaScript 只有声明的变量会提升,初始化的不会。

说了这么多,什么意思呢?其实上面的代码就相当于:

var color;  //定义的变量被提升到代码的最顶部
console.log(color);  //这个时候输出,js 能找到color 这个变量,但是这个变量没被初始化值,所以是undefined
color = 'blue';  //声明被提升到了代码的顶部,但是初始化仍在console 后面。

那么,如果换成 let 或者 const 呢?

console.log(userName);
let userName = 'Madman';
浅谈ES6_第3张图片

为什么?我们来看看gitHub上的解释:



通俗来说,这种现象叫做hoist,在 var 中有,同样在 let/const 中也有。

就和上面所提及到的一样,在声明代码之前使用后面用 var 声明的变量会返回一个 undefined,这个值是默认的在初始化的时候赋进去的。

但是如果是在声明之前使用后面会用 let/const 声明的变量会抛出一个错误。这个因为变量在声明代码之前是不可用的(没有被初始化)。进入作用域和使用作用域的值得这段时期就叫做时间死区(Temporal Dead Zone)。

注解:
时间死区(Temporal Dead Zone): 在进入一个scope之后,let/const也会有一个hoist,这个过程和var 一样,区别是 var 在hoist之后,被初始化为了 undefined,但是let/const没有初始化,直到真正声明它的地方。

3.箭头函数

ES6 推出的箭头函数有四个特点:

  • 简明的语法;
const arr1 = [5,8,10,12,15];
const arr2 = arr1.map(function (arr) {
    return arr*2;
});
console.log(arr2);
const arr3 = arr1.map((arr) => { //箭头函数
    return arr*2;
});
console.log(arr3);
const arr4 = arr1.map(arr => { //箭头函数,单个参数可以不要那一对括号
    return arr*2;
});
console.log(arr4)
const arr5 = arr1.map((arr,i) => { //箭头函数,多个参数用逗号分割
    return `${i} : ${arr *2}`;
});
console.log(arr5);
  • 可以隐士返回;
const arr1 = [5,8,10,12,15];
const arr2 = arr1.map((arr) => {
  return arr*2;  //  像这种带有return 的被称为显示返回
})
const arr3 = arr1.map((arr) => arr*2);
//这中把代码写在一行,不写return 以及去掉 '{}' 的被称为隐式返回;
  • 箭头函数都是匿名函数
function sayName(name){
  alert(`hi,${name}`);
}
sayName('Madman'); //很显然,这是一个命名函数

//那如何用箭头函数来实现呢?一般我们把箭头函数赋给一个变量
const sayHi = name => alert(`hi,${name}`);
sayHi('Madman');

const a = 0;
const hh = a => {
                if(a<5) {
                    alert(a);
                }
            }
 hh(a);
//其实这样看起来怪怪的 -O-
  • this 的理解;
const madman = {
            name : 'Madman',
            hobbies :['睡觉','吃饭','打豆豆'],
            printHobbies :function () {
                this.hobbies.map(function(hobby){ //这里的this会指向madman
                   console.log(`${this.name} love ${hobby}`); //这里的this会指向windows对象
                });
            }
        };
madman.printHobbies()

来看一下控制台的结果:


可以发现, this.name 并没有被打印出来。那么我们来试试箭头函数:

const madman = {
            name : 'Madman',
            hobbies :['睡觉','吃饭','打豆豆'],
            printHobbies :function () {
                this.hobbies.map((hobby) =>{
                   console.log(`${this.name} love ${hobby}`);
                });
            }
        };
madman.printHobbies();

来看一下控制台的结果:


浅谈ES6_第4张图片

为什么呢?
因为箭头函数没有自己的 this 值,它的 this 值是继承它的父作用域。

4.参数默认值

之前,我们一般调用方法的时候会给参数一个默认值,比如:

function multiply(a,b){
  a = a || 3;
  b = b || 5;
  return a * b;
}

那么,我们来看一下ES6是如何给参数赋默认值的;

function multiply(a = 3, b = 5){ //是不是很简单明了且具有可读性
  return a * b;
}
multiply();  //15
multiply(1,1);  //1
multiply(2);  //10
multiply(undefined,2);  //6 ,这里底层是通过判断typeof === 'undefined' ? 默认值 || 其他

你可能感兴趣的:(浅谈ES6)