ES6语法的新特性

来源:互联网 发布:微信mp网络推广 编辑:程序博客网 时间:2024/05/01 15:09

之前面试被问到ES6新特性,箭头函数,generator、Module等等,表示刚开始上手用ES6,目前还没有很深入,所以这次想对ES6一些常用的特性进行整理。

let和const

主要是实现块级作用域的。因为在原生JS中,没有块级作用域。只有在函数中,才构成一个作用域,但是利用函数是可以实现一个类似于块级作用域的。详见这里。

不过,为了更方便的解决类似于下面这种问题:

setTimeout(function(){    for( var i = 0; i < 10; i++)    {        console.log(i);    }})

ES6引入了两个新的特性,letconst

letvar有什么区别呢?

1. `let`声明的变量有块级作用域,不能作为全局对象的全局属性被访问,即不能通过window来访问;2. `let` 声明的变量不能被重复声明,而`var`没有关系;3. 像 `for(let i ......)`这种形式,会在每次迭代对`i`进行绑定。

const与let类似,唯一的不同就在于const声明变量时必须初始化,并且初始化之后就不能再对值进行修改了,否则会报错!

箭头函数

箭头函数出现的目的是为了让JS代码显得更简洁一些。

// 六种语言中的简单函数示例    function (a) { return a > 0; } // JS    [](int a) { return a > 0; }  // C++    (lambda (a) (> a 0))  ;; Lisp    lambda a: a > 0  # Python    a => a > 0  // C#    a -> a > 0  // Java

我们都知道函数式编程很普遍,而且原生JS来实现比较冗长,所以ES6新引入了一种箭头函数的写法。

那么箭头函数和普通函数有什么区别呢?主要区别就是this的指向。在箭头函数里面是没有自己的this的,里面的this继承自外围作用域。而普通函数是有自己的作用域的,所以才会在引入闭包的时候,this一般都指向全局window对象。

var obj = {    name: 'heihei',    sayName: function(){        return function(){            console.log(this);        }    }}var obj1 = {    name: 'Hellen',    sayName: function(){        return ()=>{ console.log(this) };    }}

测试结果

另一点不同,就是箭头函数里面是访问不到arguments参数列表的,所以只能通过不定参数和默认参数这两个机制来实现。可参考这篇文章。

class类

在原生ES5中,我们通常利用构造函数来创建对象,而ES6引入一种与Java,C++等更接近的方法来创建对象-class。

我们对比下构造函数和class有什么不同。

 function Circle( radius ) {     this.radius = radius;     this.area = function(){        return Math.pow(this.radius, 2) * Math.PI;    } }var c = new Circle(4);var area = c.area();console.log(area);
class Circle {    constructor( radius ) {        this.radius = radius;    };    area() {        return Math.pow(this.radius, 2) * Math.PI;    }}var c = new Circle(4);var area = c.area();console.log(area);

在写法上,除了类的定义与构造函数不同,在用法上是相同的语法。不同的地方我们看下下面两张图就明白了。
这是利用构造函数构造的对象:
这里写图片描述

利用Class创建的对象:
这里写图片描述

Iterator(遍历器)

在原生JS中,遍历对象/数组有这么几种方式:

  • for循环
//最简单也最直观的循环遍历var arr = [2,6,5];for(var i = 0; i < arr; i++) {    console.log(arr[i]);}
  • forEach
//写法比上面的简单很多;//但是对于对象不使用,并且不能跳出循环,即用break,continue,return等var arr = [2,6,5];arr.forEach(function(data) {    console.log(data);})
  • for … in
//对于数组而言,是按照arr['0'],arr['1']来访问的;//不一定按顺序访问的//专门适用于对象的遍历var arr = [2,6,5];for(var index in arr) {    console.log(arr[index]);}

Iterator的出现就是为解决上面的一些缺点出现的,为的是给不同的数据结构产生统一的接口。只要部署一个Iterator接口,就可以为for ... of 服务,从而实现遍历。

Iterator的过程是这样的:

  1. 创建一个指针对象,指向数据结构的起始位置;
  2. 调用指针对象的next方法,指针指向数据结构的第一个成员;
  3. 一次类推,直到返回数据结构的最后一个成员。

    Iteratornext方法返回的是一个对象:{ value: 成员对象的值, done:false/true }

其实在数组、字符串,以及ES6的Map和Set中,都有默认的Iterator接口,因为有遍历器接口,所以才能调for ... of来实现遍历。那我们看看默认的Iterator接口是什么样的?
这里写图片描述
上图是一个数组对象的原型链上的方法。其中有一个Symbol.iterator函数,这个函数其实就是一个遍历器接口。我们来使用一下:

这里写图片描述

这个函数返回的是一个对象表示数组Iterator。并且在这个对象里有next方法,这跟我们前面说的是相吻合的。
这里写图片描述

每一次调用next方法之后,就会返回一个对象,value表示数据结构当前位置的数值,done表示是否到最后一个成员。

所以只要一个数据结构,有这个接口,都可以调用for…of方法来实现。
这里写图片描述
这里写图片描述

因为Object里面没有Iterator接口,所以不能直接用for…of实现遍历,那怎么办呢?
其实可以先调Object.keys将对象转成数组。
这里写图片描述

后期还会续上generator生成器对象(迭代器对象)以及modules等新特性。