了解ES6

内容:node

1.ES6介绍及基础python

2.模块、类和继承es6

3.ES6高级特性编程

4.Generator和Iterator数组

5.异步编程promise

6.函数相关浏览器

 

内容参考:《ES6 标准入门》服务器

ES6标准阅读连接:http://es6.ruanyifeng.com/数据结构

 

 

 

1、ES6介绍及基础多线程

1.什么是ES6

ECMAScript 6.0(如下简称 ES6)是 JavaScript 语言的下一代标准,已经在 2015 年 6 月正式发布了。它的目标,是使得 JavaScript 语言能够用来编写复杂的大型应用程序,成为企业级开发语言

 

 

2.JavaScript版本

JavaScript有不少版本,具体版本以下: 

 

 

3.let和const

(1)let

ES6 新增了let命令,用来声明变量。它的用法相似于varlet所声明的变量,只在let命令所在的代码块内有效,也就是说let建立块级做用域

let和var的区别:

 1 {
 2   let a = 10;
 3   var b = 1;
 4 }
 5 
 6 console.log(a)  // ReferenceError: a is not defined.
 7 console.log(b)  // 1
 8 // 结果代表,let声明的变量只在它所在的代码块有效
 9 
10 
11 // var和let的区别:
12 // 下面的代码若是使用var,最后输出的是10:
13 var a = [];
14 for (var i = 0; i < 10; i++) {
15   a[i] = function () {
16     console.log(i);
17   };
18 }
19 a[6]()  //  10
20 
21 
22 // 若是使用let,声明的变量仅在块级做用域内有效,最后输出的是 6。
23 var a = [];
24 for (let i = 0; i < 10; i++) {
25   a[i] = function () {
26     console.log(i);
27   };
28 }
29 a[6]()  // 6

 

for循环的特别之处:

1 // 设置循环变量的那部分是一个父做用域,而循环体内部是一个单独的子做用域
2 // 例以下面这段代码:
3 for (let i = 0; i < 3; i++) {
4   let i = 'abc';
5   console.log(i);
6 }
7 // abc
8 // abc
9 // abc

 

另外,var命令会发生”变量提高“现象,即变量能够在声明以前使用,值为undefined。这种现象多多少少是有些奇怪的,按照通常的逻辑,变量应该在声明语句以后才可使用。

为了纠正这种现象,let命令改变了语法行为,它所声明的变量必定要在声明后使用,不然报错

1 // var 的状况
2 console.log(foo); // 输出undefined
3 var foo = 2;
4 
5 // let 的状况
6 console.log(bar); // 报错ReferenceError
7 let bar = 2;

 

(2)const

const声明一个只读常量;const一旦声明就必须当即初始化,不能留到之后赋值;const做用域与let相同:只在所在的块级做用域内有效

 1 const PI = 3.1415;
 2 PI  // 3.1415
 3 
 4 PI = 3;
 5 // TypeError: Assignment to constant variable.
 6 // 改变常量的值会报错
 7 
 8 
 9 const foo;
10 // SyntaxError: Missing initializer in const declaration
// const 用来声明一个不可赋值的变量  变量的值只能在声明的时候赋予
const a = 1
a = 2 // 错误

// 下面的不是赋值 是操做 因此是能够的
const arr = [1, 2]
arr.push(3)
// [1, 2, 3]

 

 

 

2、模块、类和继承

1.模块module

历史上,JavaScript 一直没有模块(module)体系,没法将一个大程序拆分红互相依赖的小文件,再用简单的方法拼装起来。其余语言都有这项功能,好比 Ruby 的require、Python 的import,甚至就连 CSS 都有@import,可是 JavaScript 任何这方面的支持都没有,这对开发大型的、复杂的项目造成了巨大障碍

在 ES6 以前,社区制定了一些模块加载方案,最主要的有 CommonJS 和 AMD 两种。前者用于服务器,后者用于浏览器。ES6 在语言标准的层面上,实现了模块功能,并且实现得至关简单,彻底能够取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案;ES6 模块的设计思想是尽可能的静态化,使得编译时就能肯定模块的依赖关系,以及输入和输出的变量。CommonJS 和 AMD 模块,都只能在运行时肯定这些东西。好比,CommonJS 模块就是对象,输入时必须查找对象属性

 

ES6 模块不是对象,而是经过export命令显式指定输出的代码,再经过import命令输入:

1 // export
2 export function stat() {}
3 export function exists() {}
4 export function readFile () {}
5 // import
6 import { stat, exists, readFile } from 'fs';

上面代码的实质是从fs模块加载 3 个方法,其余方法不加载。这种加载称为“编译时加载”或者静态加载,即 ES6 能够在编译时就完成模块加载,效率要比 CommonJS 模块的加载方式高

 

模块详细内容:http://es6.ruanyifeng.com/#docs/module

 

 

2.类class

下面是ES5和ES6定义类的写法:

 1 // ES5:
 2 function Point(x, y) {
 3   this.x = x;
 4   this.y = y;
 5 }
 6 
 7 Point.prototype.toString = function () {
 8   return '(' + this.x + ', ' + this.y + ')';
 9 };
10 
11 var p = new Point(1, 2);
12 
13 
14 //ES6:
15 class Point {
16   constructor(x, y) {
17     this.x = x;
18     this.y = y;
19   }
20 
21   toString() {
22     return '(' + this.x + ', ' + this.y + ')';
23   }
24 }

 

类详细介绍:http://es6.ruanyifeng.com/#docs/class

 

 

3.继承inherit

ES6中Class 能够经过extends关键字实现继承,这比 ES5 的经过修改原型链实现继承,要清晰和方便不少

 1 class Point {
 2     constructor(x, y) {
 3         this.x = x;
 4         this.y = y;
 5     }
 6 }
 7 
 8 
 9 class ColorPoint extends Point {
10   constructor(x, y, color) {
11     super(x, y); // 调用父类的constructor(x, y)
12     this.color = color;
13   }
14 
15   toString() {
16     return this.color + ' ' + super.toString(); // 调用父类的toString()
17   }
18 }

 

继承详细内容:http://es6.ruanyifeng.com/#docs/class-extends

 

 

 

3、ES6高级特性

1.变量的解构赋值

ES6中容许这样的赋值方式:

 1 let [a, b, c] = [1, 2, 3]
 2 
 3 let [foo, [[bar], baz]] = [1, [[2], 3]]; 4 foo // 1 5 bar // 2 6 baz // 3 7 8 let [ , , third] = ["foo", "bar", "baz"]; 9 third // "baz" 10 11 let [x, , y] = [1, 2, 3]; 12 x // 1 13 y // 3 14 15 let [head, ...tail] = [1, 2, 3, 4]; 16 head // 1 17 tail // [2, 3, 4] 18 19 let [x, y, ...z] = ['a']; 20 x // "a" 21 y // undefined 22 z // []

另外若是解析不成功,值就为undefined,以下所示:

1 let [foo] = [];
2 let [bar, foo] = [1]; 3 // 以上两种状况都属于解构不成功,foo的值都会等于undefined

更多细节:http://es6.ruanyifeng.com/#docs/destructuring

 

 

2.spread 和 rest

(1)拓展运算符spread

spread运算符用于数组的构造,析构,以及在函数调用时使用数组填充参数列表

 1 let arrs1 = ['aa', 'bb']
 2 let arrs2 = ['cc', 'dd']
 3 
 4 // 合并数组
 5 let arrs = [...arrs1, ...arrs2]
 6 console.log(arrs)  // ['aa', 'bb', 'cc', 'dd']
 7 
 8 // 析构数组
 9 let param1, param2
10 [param1, ...param2] = arrs1
11 
12 console.log(param1)  // aa
13 console.log(param2)  // ['bb']

 

(2)剩余运算符rest

rest运算符用于获取函数调用时传入的参数

1 function testFunc(...args) {
2    console.log(args);  // ['aa', 'bb', 'cc']
3    console.log(args.length); // 3
4 }
5 // 调用函数
6 testFunc('aa', 'bb', 'cc'); 

剩余运算符rest实现多参数:

1 function callFriends(via, ...friends) {
2   console.log('使用' + via + '通知: ' + friends.join(',') + '等' + friends.length + '个好友')
3 }
4 callFriends('QQ', '张三')
5 callFriends('电话', '张三', '李四', '王五')
6 
7 // 输出结果:
8 // 使用QQ通知: 张三等1个好友
9 // 使用电话通知: 张三,李四,王五等3个好友

 

 

3.template

模板字符串(template string)是加强版的字符串,用反引号(`)标识。它能够看成普通字符串使用,也能够用来定义多行字符串,或者在字符串中嵌入变量

 1 // 传统的 JavaScript 语言,输出模板一般是这样写的(下面使用了 jQuery 的方法)。
 2 
 3 $('#result').append(
 4   'There are <b>' + basket.count + '</b> ' +
 5   'items in your basket, ' +
 6   '<em>' + basket.onSale +
 7   '</em> are on sale!'
 8 );
 9 
10 // 上面这种写法至关繁琐不方便,ES6 引入了模板字符串解决这个问题。
11 $('#result').append(`
12   There are <b>${basket.count}</b> items
13    in your basket, <em>${basket.onSale}</em>
14   are on sale!
15 `);

 

 

4.set和map

JavaScript中set和map这两种数据结构详细介绍:http://es6.ruanyifeng.com/#docs/set-map

(1)set

Set 在其余语言里面称为集合,是一种和 Array 类似的数据结构,不一样之处在于, Set 中的元素都是不重复的,set 类型的主要做用是去重
用法以下:

 1 var s = new Set()
 2 
 3 // add 方法添加元素, 和 push 同样
 4 s.add(1)
 5 s.add(2)
 6 
 7 // has 方法检查元素是否在 set 中
 8 s.has(1) // true
 9 s.has(3) // false
10 
11 // size 属性至关于 length
12 s.size  // 2
13 
14 // delete 方法删除一个元素
15 s.delete(1)
16 s.has(1)
17 
18 s.size  // 1

注:JavaScript中的set不像python中的set那样提供了一系列的运算方法,这些运算方法须要本身去实现

 

(2)map

Map 和 Object 很类似,在其余语言中 一般会有 dict 和 object 两种数据结构
如今 js 也有独立的 dict 那就是 Map(其实没多好用),其用法以下:

1 var m = new Map()
2 
3 // set 方法增长一个值
4 m.set('name', 'gua')
5 
6 // get 属性获得一个值
7 m.get('name')

 

 

 

4、Generator和Iterator和Decorator

1.generator 

(1)generator -> 相似python的生成器

Generator函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数彻底不一样

Generator函数有多种理解角度:

  • 语法上,Generator 函数能够理解为是一个状态机,封装了多个内部状态
  • 执行 Generator 函数会返回一个遍历器对象即Generator 函数仍是一个遍历器对象生成函数。返回的遍历器对象可遍历Generator函数内部的每一个状态
  • 形式上Generator函数是一个普通函数,可是有两个特征。一是,function关键字与函数名之间有一个星号;二是,函数体内部使用yield表达式,定义不一样的内部状态(yield在英语里的意思就是“产出”)

 

(2)generator函数语法

generator函数以下:

1 function* helloWorldGenerator() {
2   yield 'hello'
3   yield 'world'
4   return 'ending'
5 }
6 
7 var hw = helloWorldGenerator()

Generator 函数的调用方法与普通函数同样,也是在函数名后面加上一对圆括号。不一样的是,调用 Generator 函数后,该函数并不执行,返回的也不是函数运行结果,而是一个指向内部状态的指针对象,也就是上一章介绍的遍历器对象(Iterator Object)

下一步,必须调用遍历器对象的next方法,使得指针移向下一个状态。也就是说,每次调用next方法,内部指针就从函数头部或上一次停下来的地方开始执行,直到遇到下一个yield表达式(或return语句)为止。换言之,Generator 函数是分段执行的,yield表达式是暂停执行的标记,而next方法能够恢复执行

 1 hw.next()
 2 // { value: 'hello', done: false }
 3 
 4 hw.next()
 5 // { value: 'world', done: false }
 6 
 7 hw.next()
 8 // { value: 'ending', done: true }
 9 
10 hw.next()
11 // { value: undefined, done: true }

 

关于generator详细内容:http://es6.ruanyifeng.com/#docs/generator

 

 

2.iterator

(1)iterator -> 相似python中的迭代器

JavaScript 原有的表示集合的数据结构,主要是数组和对象,ES6 又添加了MapSet。这样就有了四种数据集合,须要一种统一的接口机制,来处理全部不一样的数据结构。

遍历器(Iterator)就是这样一种机制。它是一种接口,为各类不一样的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就能够完成遍历操做

Iterator 的做用有三个:

  • 为各类数据结构,提供一个统一的、简便的访问接口
  • 使得数据结构的成员可以按某种次序排列
  • ES6 创造了一种新的遍历命令for...of循环,Iterator 接口主要供for...of消费

 

(2)Iterator 的遍历过程

  • 建立一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象。
  • 第一次调用指针对象的next方法,能够将指针指向数据结构的第一个成员。
  • 第二次调用指针对象的next方法,指针就指向数据结构的第二个成员。
  • 不断调用指针对象的next方法,直到它指向数据结构的结束位置。

每一次调用next方法,都会返回数据结构的当前成员的信息。具体来讲,就是返回一个包含valuedone两个属性的对象。其中,value属性是当前成员的值,done属性是一个布尔值,表示遍历是否结束

下面是一个模拟next方法返回值的例子:

 1 var it = makeIterator(['a', 'b']);
 2 
 3 it.next() // { value: "a", done: false }
 4 it.next() // { value: "b", done: false }
 5 it.next() // { value: undefined, done: true }
 6 
 7 function makeIterator(array) {
 8   var nextIndex = 0;
 9   return {
10     next: function() {
11       return nextIndex < array.length ?
12         {value: array[nextIndex++], done: false} :
13         {value: undefined, done: true};
14     }
15   };
16 }

 

关于iterator详细内容:http://es6.ruanyifeng.com/#docs/iterator

 

 

3.Decorator

(1)decorator -> 相似python中的装饰器

许多面向对象的语言都有修饰器(Decorator)函数,用来修改类的行为;装饰器是一个对类进行处理的函数。装饰器函数的第一个参数,就是所要修饰的目标类,固然也能够不写成函数调用的方式(见下面的代码)

 1 @testable  // 等同于testable = testable(MyTestableClass)
 2 class MyTestableClass {
 3   // ...
 4 }
 5 
 6 function testable(target) {
 7   target.isTestable = true;
 8 }
 9 
10 MyTestableClass.isTestable // true
11 
12 // 上面代码中,@testable就是一个修饰器
13 // 它修改了MyTestableClass类的行为,为它加上静态属性isTestable。testable函数的参数target是MyTestableClass类自己

 

(2)decorator修饰类的属性

 1 class Person {
 2   @readonly
 3   name() { return `${this.first} ${this.last}` }
 4 }
 5 
 6 function readonly(target, name, descriptor){
 7   // descriptor对象原来的值以下
 8   // {
 9   //   value: specifiedFunction,
10   //   enumerable: false,
11   //   configurable: true,
12   //   writable: true
13   // };
14   descriptor.writable = false;
15   return descriptor;
16 }
17 
18 readonly(Person.prototype, 'name', descriptor);
19 // 相似于
20 Object.defineProperty(Person.prototype, 'name', descriptor);

 

关于decorator的详细内容:http://es6.ruanyifeng.com/#docs/decorator

 

 

 

5、异步编程

1.JavaScript中的异步编程

至少在语言级别上,Javascript是单线程的,所以异步编程对其尤其重要。

拿nodejs来讲,外壳是一层js语言,这是用户操做的层面,在这个层次上它是单线程运行的,也就是说咱们不能像Java、Python这类语言在语言级别使用多线程能力。取而代之的是,nodejs编程中大量使用了异步编程技术,这是为了高效使用硬件,同时也能够不形成同步阻塞。不过nodejs在底层实现其实仍是用了多线程技术,只是这一层用户对用户来讲是透明的,nodejs帮咱们作了几乎所有的管理工做,咱们不用担忧锁或者其余多线程编程会遇到的问题,只管写咱们的异步代码就好

ES 6之前:

  • 回调函数
  • 事件监听(事件发布/订阅)
  • Promise对象

ES 6以后:

  • Generator函数(协程coroutine)
  • async和await

 

 

2.callback(回调函数)

假定有两个函数f1和f2,后者等待前者的执行结果:

1 f1();
2 f2();

若是f1是一个很耗时的任务,能够考虑改写f1,把f2写成f1的回调函数:

1 function f1(callback){
2     setTimeout(function () {
3         // f1的任务代码
4         callback();
5     }, 1000);
6 }

执行代码就变成这样:f1(f2);

采用这种方式,咱们把同步操做变成了异步操做,f1不会堵塞程序运行,至关于先执行程序的主要逻辑,将耗时的操做推迟执行。

回调函数的优势是简单、容易理解和部署,缺点是不利于代码的阅读和维护,各个部分之间高度耦合,流程会很混乱,并且每一个任务只能指定一个回调函数

 

 

3.promise

ES 6中原生提供了Promise对象,Promise对象表明了某个将来才会知道结果的事件(通常是一个异步操做),而且这个事件对外提供了统一的API,可供进一步处理。
使用Promise对象能够用同步操做的流程写法来表达异步操做,避免了层层嵌套的异步回调,代码也更加清晰易懂,方便维护。

 

 

4.async函数

ES2017 标准引入了 async 函数,使得异步操做变得更加方便。async 函数是什么?一句话,它就是 Generator 函数的语法糖

详细内容直接看这里:http://es6.ruanyifeng.com/#docs/async

 

 

 

6、函数相关

1.函数参数默认值(函数默认参数)

1 // ES6 容许为函数的参数设置默认值,即直接写在参数定义的后面:
2 function log(x, y = 'World') {
3   console.log(x, y);
4 }
5 
6 log('Hello') // Hello World
7 log('Hello', 'China') // Hello China
8 log('Hello', '') // Hello

 

 

2.箭头函数

箭头函数就是匿名函数定义的简化版, 宣称能使得代码更简洁,实际上就是纯粹的垃圾
箭头函数的 this 值是绑定了的,箭头函数没有 arguments 对象,若是要多参数, 必须用 ...

语法以下:

 1 // (参数1, 参数2) => { 语句 }
 2 // (参数1, 参数2) => 语句
 3 // 上面两行至关于下面这函数
 4 function(参数1, 参数2) {
 5     return 语句
 6 }
 7 
 8 // 若是只有一个参数,圆括号可省略的
 9 // (参数1) => { 语句 }
10 // 参数1 => { 语句 }
11 
12 // 可是若是没有参数, 必须须要使用圆括号
13 // () => { 语句 }
14 
15 // 例子
16 var a1 = [1, 2, 3]
17 // 下面两个等价
18 var a2 = a1.map(function(n){
19     return n * n
20 })
21 var a3 = a1.map( n => n * n )
22 
23 n => n * n
24 // 上面 1 行等价于下面 3 行
25 function(n) {
26     return n * n
27 }
相关文章
相关标签/搜索