ES6学习心得

ECMAScript 6.0(简称ES6)是 JavaScript 一个制定于2015年的新标准,它于2015年6月正式发布。javascript

它的目的是想让JavaScript成为一个企业级的开发语言,能够去开发大型的复杂应用。html

个人ES6学习心得将分为如下三个部分来阐述:java

1.ECMAScript 6.0简介node

2.ECMAScript 6.0新特性程序员

3.ECMAScript 6.0性能总结与我的体会es6

4.参考文献编程

 

1.ECMAScript 6.0简介数组

想要弄清楚ECMAScript 6.0,那么咱们要先弄清楚它是什么,它怎么来的。浏览器

(1)ECMAScript闭包

ECMA是“European Computer Manufactures Association”的缩写,中文称欧洲计算机制造联合会。这个组织的目标是评估,开发和承认电信和计算机标准。

1996年的时候,Javascript的创造公司将Javascript提交给ECMA,但愿这种语言可以成为国际标准。

次年,ECMA 发布262号标准文件(ECMA-262)的初版,规定了浏览器脚本语言Javascript的标准,并将这种语言称为 ECMAScript,这个版本就是1.0版。

因此咱们这里总结一下ECMAscript与Javascript之间的关系:

ECMAscript是Javascript的标准/规格

Javascript是ECMAscript的实现(另外的 ECMAScript 语言还有 Jscript 和 ActionScript)

可是咱们通常平常说的ECMAScript就是Javascript的意思,这两个词是能够互换的,不过仍是要清楚它们的区别。

  

(2)ECMAScript 6.0(ES6) / ECMAScript 2015(ES2015)

2011年,ECMAScript 5.1版发布后,就开始制定6.0版了。所以,ES6 这个词的原意,就是指 ECMAScript 5.1版的下一个版本。

由于ECMA标准委员会会在每一年6月份更新并正式发布一次新的ECMAScript标准,做为当年的正式版本。

而后接下来的时间就是在这个版本的基础上面作改动,一直到下年的6月份。这样一来其实就不须要用版本号来区分了了,用年份标记便可。

ES6 的第一个版本,就这样在2015年6月发布了,正式名称就是《ECMAScript 2015标准》(简称 ES2015)。

2016年6月,小幅修订的《ECMAScript 2016标准》(简称 ES2016)如期发布,这个版本能够看做是 ES6.1 版,由于二者的差别很是小(只新增了数组实例的includes方法和指数运算符),基本上是同一个标准。根据计划,2017年6月发布 ES2017 标准。

所以,ECMAScript6.0既是一个版本名称,也是一个类别。版本名称是指5.1版之后的 ECMAScript 的下一代标准,类别是指它涵盖了ES201五、ES201六、ES2017等等。

而ES2015 则是正式名称,特指该年发布的正式版本的语言标准。

 

2.ECMAScript 6.0新特性

以前刚开始接触Javascript的时候ES6还没推出,用的仍是ES5的标准,那么新推出的ES6有哪些新特性呢?

下文我将总结一些在ES6的学习中接触到的一些比较经常使用的语法特性,具体有如下几项:

(1)let, const

(2)class, extends, super

(3)arrow function

(4)template string

(5)destructuring

(6)default, reat

 

--------------------华丽丽的分界线---------------------

 

(1)let, const

let, const的做用与var相似,都是用于声明变量的,可是它们减小了var在做用域以及赋值方面的缺陷,下面咱们来看一下。

①var在做用域方面的缺陷

var name = 'zach'

while (true) {
    var name = 'obama'
    console.log(name)  //obama
    break
}

console.log(name)  //obama

使用var两次输出都是obama,这是由于ES5只有全局做用域和函数做用域,没有块级做用域,这带来不少不合理的场景。第一种场景就是你如今看到的内层变量覆盖外层变量。而let则实际上为JavaScript新增了块级做用域。用它所声明的变量,只在let命令所在的代码块内有效。

let name = 'zach'

while (true) {
    let name = 'obama'
    console.log(name)  //obama
    break
}

console.log(name)  //zach

另一个var带来的不合理场景就是用来计数的循环变量泄露为全局变量,看下面的例子:

var a = [];
for (var i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[6](); // 10

上面代码中,变量i是var声明的,在全局范围内都有效,因此全局只有一个变量i。每一次循环,变量i的值都会发生改变,而循环内被赋给数组a的function在运行时,会经过闭包读到这同一个变量i,致使最后输出的是最后一轮的i的值,也就是10。而使用let则不会出现这个问题。

var a = [];
for (let i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[6](); // 6

 上面代码中,变量i是let声明的,当前的i只在本轮循环有效,因此每一次循环的i其实都是一个新的变量,因此最后输出的是6。你可能会问,若是每一轮循环的变量i都是从新声明的,那它怎么知道上一轮循环的值,从而计算出本轮循环的值?这是由于 JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算。

另外,for循环还有一个特别之处,就是循环语句部分是一个父做用域,而循环体内部是一个单独的子做用域。

for (let i = 0; i < 3; i++) {
  let i = 'abc';
  console.log(i);
}
// abc
// abc
// abc

上面代码输出了3次abc,这代表函数内部的变量i和外部的变量i是分离的。

 

 

②var在赋值方面的缺陷

从上面的例子咱们能够看出,var的赋值是能够很轻易地被改变的

var name = 'zach'

while (true) {
    var name = 'obama'
    console.log(name)  //obama
    break
}

console.log(name)  //obama

这就带来了一个问题,一些程序中比较重要的变量很容易就会被他人,特别是你绝不知情的队友改变了,这就给咱们大型程序的开发带来了麻烦。

固然上文仅仅是我设想的一个场景,咱们的程序中更多的时候是须要一些约定俗成,值不变的常量,好比说pi。

在ES6中,咱们添加了const特性来声明常量。一旦声明,常量的值就不能改变。

const PI = Math.PI

PI = 23 //Module build failed: SyntaxError: /es6/app.js: "PI" is read-only

当咱们尝试去改变用const声明的常量时,浏览器就会报错。
const有一个很好的应用场景,就是当咱们引用第三方库的时声明的变量,用const来声明能够避免将来不当心重命名而致使出现bug:

const monent = require('moment')

 

(2)class, extends, super

 ES6还有一大特色就是它跟咱们所熟知的入门级语言C、C++更像了,由于它引入了class(类)这个概念。

在ES5的年代,js是没有特定的class这个概念的,因此咱们以前通常经过构造函数定义并生成新对象,以下图:

function Point(x, y) {
  this.x = x;
  this.y = y;
}

Point.prototype.toString = function () {
  return '(' + this.x + ', ' + this.y + ')';
};

var p = new Point(1, 2);

可是上面这种写法跟传统的面向对象语言(好比C++和Java)差别很大,很容易让刚接触的程序员感到困惑。

ES6提供了更接近传统的面向对象语言的写法,引入了Class(类)这个概念。

在ES6中,经过class关键字,咱们能够定义类。

但其实ES6的class仅仅是个名字/写法而已,由于它的绝大部分功能,ES5均可以作到。

不过新的class写法让对象原型的写法更加清晰、更像面向对象编程的语法,这样就能够更接近企业级的开发语言。

上面的代码用ES6的“类”改写,就是下面这样。

//定义类
class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }

  toString() {
    return '(' + this.x + ', ' + this.y + ')';
  }
}

上面代码首先用class定义了一个“类”,能够看到里面有一个constructor方法,这就是构造方法,而this关键字则表明实例对象。简单地说,constructor内定义的方法和属性是实例对象本身的,而constructor外定义的方法和属性则是全部实例对象能够共享的。

Point类除了构造方法,还定义了一个toString方法。注意,定义“类”的方法的时候,前面不须要加上function这个关键字,直接把函数定义放进去了就能够了。另外,方法之间不须要逗号分隔,加了会报错。

ES6的类,彻底能够看做构造函数的另外一种写法。

class Point {
  // ...
}

typeof Point // "function"
Point === Point.prototype.constructor // true

 

Class之间能够经过extends关键字实现继承,这比ES5的经过修改原型链实现继承,要清晰和方便不少。下面定义了一个Cat类,该类经过extends关键字,继承了Animal类的全部属性和方法。

class Animal {
    constructor(){
        this.type = 'animal'
    }
    says(say){
        console.log(this.type + ' says ' + say)
    }
}

let animal = new Animal()
animal.says('hello') //animal says hello

class Cat extends Animal {
    constructor(){
        super()
        this.type = 'cat'
    }
}

let cat = new Cat()
cat.says('hello') //cat says hello

super关键字,它指代父类的实例(即父类的this对象)。子类必须在constructor方法中调用super方法,不然新建实例时会报错。这是由于子类没有本身的this对象,而是继承父类的this对象,而后对其进行加工。若是不调用super方法,子类就得不到this对象。

ES6的继承机制,实质是先创造父类的实例对象this(因此必须先调用super方法),而后再用子类的构造函数修改this。

 

 

(3)arrow function

 ES6带来的还有一个新特性,就是简洁。

arrow function应该是ES6最最经常使用的一个新特性了,用它来写function比原来的写法要简洁清晰不少:

function(i){ return i + 1; } //ES5
(i) => i + 1 //ES6

若是function有多行内容,则须要用{}将其括起来:

function(x, y) { 
    x++;
    y--;
    return x + y;
}//ES5
(x, y) => {x++; y--; return x+y}//ES6

 

另外ES5在使用this的时候也须要当心混淆:

class Animal {
    constructor(){
        this.type = 'animal'
    }
    says(say){
        setTimeout(function(){
            console.log(this.type + ' says ' + say)
        }, 1000)
    }
}

 var animal = new Animal()
 animal.says('hi')  //undefined says hi

运行上面的代码会报错,这是由于setTimeout中的this指向的是全局对象。

通常用ES5的解决方法有传递this或者bind(this)这些, 但如今咱们有了箭头函数,就不须要这么麻烦了:

class Animal {
    constructor(){
        this.type = 'animal'
    }
    says(say){
        setTimeout( () => {
            console.log(this.type + ' says ' + say)
        }, 1000)
    }
}
 var animal = new Animal()
 animal.says('hi')  //animal says hi

当咱们使用箭头函数时,函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
并非由于箭头函数内部有绑定this的机制,实际缘由是箭头函数根本没有本身的this,它的this是继承外面的,所以内部的this就是外层代码块的this。

 

 

可是在这里咱们要说的是,arrow function也并非一劳永逸的,特别是在你并不知道this指向哪的时候,你须要慎用arrow function。

由于arrow function是 Lexical scoping(词法做用域),this指向定义Arrow Function时外围, 而不是运行时的对象。

词法做用域: 变量的做用域是在定义时决定而不是执行时决定,也就是说词法做用域取决于源码,经过静态分析就能肯定,所以词法做用域也叫作静态做用域。

下面咱们将根据文章:Do ES6 Arrow Functions Really Solve “this” In JavaScript? 来分析。

以下代码:

// run this in node v4 to see the "expected" behavior

this.test = "attached to the module";

var foo = {
  test: "attached to an object"
};

// a method to create methods
foo.method = function(name, cb){
  this[name] = cb;
};

// use an arrow function and get
// lexical analysis of "this"
foo.method("bar", () => {
  // not what you expected, maybe?
  console.log(this.test); 
});

foo.bar();

输出为:“attached to the module”而不是“attached to an object”

由于

就像咱们所说的,arrow function是 Lexical scoping,由于在foo.method("bar", () => {的外围并无包含着它的代码,因此,foo.bar()中的this.test值将永远是“attached to the module”。

 

 

(4)template string

 这个新特性能够帮助咱们插入大段的html内容到文档中去。传统的写法通常比较麻烦,因此以前咱们一般会引用一些模板工具库,好比mustache等等。代码以下:

$("#result").append(
  "There are <b>" + basket.count + "</b> " +
  "items in your basket, " +
  "<em>" + basket.onSale +
  "</em> are on sale!"
);

咱们要用一堆的'+'号来链接文本与变量,而使用ES6的新特性模板字符串``后,咱们能够直接这么来写:

$("#result").append(`
  There are <b>${basket.count}</b> items
   in your basket, <em>${basket.onSale}</em>
  are on sale!
`);

在ES6中,咱们用`来标识开始和结尾,用${}来引用变量,并且全部的空格和缩进都会被保留在输出之中。

 

 

(5)destructuring

 ES6容许按照必定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。

当使用ES5的时候,咱们通常是这么写的:

let cat = 'ken'
let dog = 'lili'
let zoo = {cat: cat, dog: dog}
console.log(zoo)  //Object {cat: "ken", dog: "lili"}

用ES6彻底能够像下面这么写:

let cat = 'ken'
let dog = 'lili'
let zoo = {cat, dog}
console.log(zoo)  //Object {cat: "ken", dog: "lili"}

反过来能够这么写:

let dog = {type: 'animal', many: 2}
let { type, many} = dog
console.log(type, many)   //animal 2

 

 

(6)default, reat

 default很简单,意思就是默认值。你们能够看下面的例子,调用animal()方法时忘了传参数,传统的作法就是加上这一句type = type || 'cat'来指定默认值。

function animal(type){
    type = type || 'cat'  
    console.log(type)
}
animal()

若是用ES6咱们能够直接这么写:

function animal(type = 'cat'){
    console.log(type)
}
animal()

 

最后一个rest语法也很简单,直接看例子:

function animals(...types){
    console.log(types)
}
animals('cat', 'dog', 'fish') //["cat", "dog", "fish"]

而若是不用ES6的话,咱们则得使用ES5的arguments

 

 

3.ECMAScript 6.0性能总结与我的体会

整体来看,ES6正在朝着更简洁、更友好、可读性更强、更模块化的方向发展,这些特性都能支持其成为一个企业级的开发语言,能够去开发大型的复杂应用。

本文章从ES6的来历,讲到ES6的一些新特性。但以上仅仅列出了ES6中一些比较经常使用的新特性,并且分析的并不够深刻,因此咱们仍是须要再去深一步学习和摸索的。“实践是检验真理的惟一方法”,之后在实战项目中遇到的问题我会再来写博客分析的。

 

 

4.参考文献

http://www.jianshu.com/p/ebfeb687eb70

http://es6.ruanyifeng.com/#docs/function

http://cnodejs.org/topic/57266e375a26c4a841ecbf40

https://derickbailey.com/2015/09/28/do-es6-arrow-functions-really-solve-this-in-javascript/

http://www.cnblogs.com/jiangyi666/p/5998914.html

http://blog.csdn.net/pengju_guo/article/details/7292080

相关文章
相关标签/搜索