了解ES6
内容:
1.ES6介绍及基础
2.模块、类和继承
3.ES6高级特性
4.Generator和Iterator
5.异步编程
6.函数相关
内容参考:《ES6 标准入门》
ES6标准阅读链接:http://es6.ruanyifeng.com/
一、ES6介绍及基础
1.什么是ES6
ECMAScript 6.0(以下简称 ES6)是 JavaScript 语言的下一代标准,已经在 2015 年 6 月正式发布了。它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言
2.JavaScript版本
JavaScript有很多版本,具体版本如下:
3.let和const
(1)let
ES6 新增了let
命令,用来声明变量。它的用法类似于var
,let所声明的变量,只在let
命令所在的代码块内有效,也就是说let创建块级作用域
let和var的区别:
{
let a = 10;
var b = 1;
} console.log(a) // ReferenceError: a is not defined.
console.log(b) //
// 结果表明,let声明的变量只在它所在的代码块有效 // var和let的区别:
// 下面的代码如果使用var,最后输出的是10:
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6]() // // 如果使用let,声明的变量仅在块级作用域内有效,最后输出的是 6。
var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6]() //
for循环的特别之处:
// 设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域
// 例如下面这段代码:
for (let i = 0; i < 3; i++) {
let i = 'abc';
console.log(i);
}
// abc
// abc
// abc
另外,var
命令会发生”变量提升“现象,即变量可以在声明之前使用,值为undefined
。这种现象多多少少是有些奇怪的,按照一般的逻辑,变量应该在声明语句之后才可以使用。
为了纠正这种现象,let
命令改变了语法行为,它所声明的变量一定要在声明后使用,否则报错
// var 的情况
console.log(foo); // 输出undefined
var foo = 2; // let 的情况
console.log(bar); // 报错ReferenceError
let bar = 2;
(2)const
const
声明一个只读常量;const
一旦声明就必须立即初始化,不能留到以后赋值;const
作用域与let
相同:只在所在的块级作用域内有效
const PI = 3.1415;
PI // 3.1415 PI = 3;
// TypeError: Assignment to constant variable.
// 改变常量的值会报错 const foo;
// SyntaxError: Missing initializer in const declaration
// const 用来声明一个不可赋值的变量 变量的值只能在声明的时候赋予
const a = 1
a = 2 // 错误 // 下面的不是赋值 是操作 所以是可以的
const arr = [1, 2]
arr.push(3)
// [1, 2, 3]
二、模块、类和继承
1.模块module
历史上,JavaScript 一直没有模块(module)体系,无法将一个大程序拆分成互相依赖的小文件,再用简单的方法拼装起来。其他语言都有这项功能,比如 Ruby 的require
、Python 的import
,甚至就连 CSS 都有@import
,但是 JavaScript 任何这方面的支持都没有,这对开发大型的、复杂的项目形成了巨大障碍
在 ES6 之前,社区制定了一些模块加载方案,最主要的有 CommonJS 和 AMD 两种。前者用于服务器,后者用于浏览器。ES6 在语言标准的层面上,实现了模块功能,而且实现得相当简单,完全可以取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案;ES6 模块的设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。CommonJS 和 AMD 模块,都只能在运行时确定这些东西。比如,CommonJS 模块就是对象,输入时必须查找对象属性
ES6 模块不是对象,而是通过export
命令显式指定输出的代码,再通过import
命令输入:
// export
export function stat() {}
export function exists() {}
export function readFile () {}
// import
import { stat, exists, readFile } from 'fs';
上面代码的实质是从fs
模块加载 3 个方法,其他方法不加载。这种加载称为“编译时加载”或者静态加载,即 ES6 可以在编译时就完成模块加载,效率要比 CommonJS 模块的加载方式高
模块详细内容:http://es6.ruanyifeng.com/#docs/module
2.类class
下面是ES5和ES6定义类的写法:
// ES5:
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); //ES6:
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
} toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
类详细介绍:http://es6.ruanyifeng.com/#docs/class
3.继承inherit
ES6中Class 可以通过extends
关键字实现继承,这比 ES5 的通过修改原型链实现继承,要清晰和方便很多
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
} class ColorPoint extends Point {
constructor(x, y, color) {
super(x, y); // 调用父类的constructor(x, y)
this.color = color;
} toString() {
return this.color + ' ' + super.toString(); // 调用父类的toString()
}
}
继承详细内容:http://es6.ruanyifeng.com/#docs/class-extends
三、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运算符用于数组的构造,析构,以及在函数调用时使用数组填充参数列表
let arrs1 = ['aa', 'bb']
let arrs2 = ['cc', 'dd'] // 合并数组
let arrs = [...arrs1, ...arrs2]
console.log(arrs) // ['aa', 'bb', 'cc', 'dd'] // 析构数组
let param1, param2
[param1, ...param2] = arrs1 console.log(param1) // aa
console.log(param2) // ['bb']
(2)剩余运算符rest
rest运算符用于获取函数调用时传入的参数
function testFunc(...args) {
console.log(args); // ['aa', 'bb', 'cc']
console.log(args.length); //
}
// 调用函数
testFunc('aa', 'bb', 'cc');
剩余运算符rest实现多参数:
function callFriends(via, ...friends) {
console.log('使用' + via + '通知: ' + friends.join(',') + '等' + friends.length + '个好友')
}
callFriends('QQ', '张三')
callFriends('电话', '张三', '李四', '王五') // 输出结果:
// 使用QQ通知: 张三等1个好友
// 使用电话通知: 张三,李四,王五等3个好友
3.template
模板字符串(template string)是增强版的字符串,用反引号(`)标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量
// 传统的 JavaScript 语言,输出模板通常是这样写的(下面使用了 jQuery 的方法)。 $('#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!
`);
4.set和map
JavaScript中set和map这两种数据结构详细介绍:http://es6.ruanyifeng.com/#docs/set-map
(1)set
Set 在其他语言里面称为集合,是一种和 Array 相似的数据结构,不同之处在于, Set 中的元素都是不重复的,set 类型的主要作用是去重
用法如下:
var s = new Set() // add 方法添加元素, 和 push 一样
s.add(1)
s.add(2) // has 方法检查元素是否在 set 中
s.has(1) // true
s.has(3) // false // size 属性相当于 length
s.size // // delete 方法删除一个元素
s.delete(1)
s.has(1) s.size //
注:JavaScript中的set不像python中的set那样提供了一系列的运算方法,这些运算方法需要自己去实现
(2)map
Map 和 Object 很相似,在其他语言中 通常会有 dict 和 object 两种数据结构
现在 js 也有独立的 dict 那就是 Map(其实没多好用),其用法如下:
var m = new Map() // set 方法增加一个值
m.set('name', 'gua') // get 属性得到一个值
m.get('name')
四、Generator和Iterator和Decorator
1.generator
(1)generator -> 类似python的生成器
Generator函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同
Generator函数有多种理解角度:
- 语法上,Generator 函数可以理解为是一个状态机,封装了多个内部状态
- 执行 Generator 函数会返回一个遍历器对象即Generator 函数还是一个遍历器对象生成函数。返回的遍历器对象可遍历Generator函数内部的每个状态
- 形式上Generator函数是一个普通函数,但是有两个特征。一是,
function
关键字与函数名之间有一个星号;二是,函数体内部使用yield
表达式,定义不同的内部状态(yield
在英语里的意思就是“产出”)
(2)generator函数语法
generator函数如下:
function* helloWorldGenerator() {
yield 'hello'
yield 'world'
return 'ending'
} var hw = helloWorldGenerator()
Generator 函数的调用方法与普通函数一样,也是在函数名后面加上一对圆括号。不同的是,调用 Generator 函数后,该函数并不执行,返回的也不是函数运行结果,而是一个指向内部状态的指针对象,也就是上一章介绍的遍历器对象(Iterator Object)
下一步,必须调用遍历器对象的next
方法,使得指针移向下一个状态。也就是说,每次调用next
方法,内部指针就从函数头部或上一次停下来的地方开始执行,直到遇到下一个yield
表达式(或return
语句)为止。换言之,Generator 函数是分段执行的,yield
表达式是暂停执行的标记,而next
方法可以恢复执行
hw.next()
// { value: 'hello', done: false } hw.next()
// { value: 'world', done: false } hw.next()
// { value: 'ending', done: true } hw.next()
// { value: undefined, done: true }
关于generator详细内容:http://es6.ruanyifeng.com/#docs/generator
2.iterator
(1)iterator -> 类似python中的迭代器
JavaScript 原有的表示集合的数据结构,主要是数组和对象,ES6 又添加了Map
和Set
。这样就有了四种数据集合,需要一种统一的接口机制,来处理所有不同的数据结构。
遍历器(Iterator)就是这样一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作
Iterator 的作用有三个:
- 为各种数据结构,提供一个统一的、简便的访问接口
- 使得数据结构的成员能够按某种次序排列
- ES6 创造了一种新的遍历命令
for...of
循环,Iterator 接口主要供for...of
消费
(2)Iterator 的遍历过程
- 创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象。
- 第一次调用指针对象的
next
方法,可以将指针指向数据结构的第一个成员。 - 第二次调用指针对象的
next
方法,指针就指向数据结构的第二个成员。 - 不断调用指针对象的
next
方法,直到它指向数据结构的结束位置。
每一次调用next
方法,都会返回数据结构的当前成员的信息。具体来说,就是返回一个包含value
和done
两个属性的对象。其中,value
属性是当前成员的值,done
属性是一个布尔值,表示遍历是否结束
下面是一个模拟next
方法返回值的例子:
var it = makeIterator(['a', 'b']); it.next() // { value: "a", done: false }
it.next() // { value: "b", done: false }
it.next() // { value: undefined, done: true } function makeIterator(array) {
var nextIndex = 0;
return {
next: function() {
return nextIndex < array.length ?
{value: array[nextIndex++], done: false} :
{value: undefined, done: true};
}
};
}
关于iterator详细内容:http://es6.ruanyifeng.com/#docs/iterator
3.Decorator
(1)decorator -> 类似python中的装饰器
许多面向对象的语言都有修饰器(Decorator)函数,用来修改类的行为;装饰器是一个对类进行处理的函数。装饰器函数的第一个参数,就是所要修饰的目标类,当然也可以不写成函数调用的方式(见下面的代码)
@testable // 等同于testable = testable(MyTestableClass)
class MyTestableClass {
// ...
} function testable(target) {
target.isTestable = true;
} MyTestableClass.isTestable // true // 上面代码中,@testable就是一个修饰器
// 它修改了MyTestableClass类的行为,为它加上静态属性isTestable。testable函数的参数target是MyTestableClass类本身
(2)decorator修饰类的属性
class Person {
@readonly
name() { return `${this.first} ${this.last}` }
} function readonly(target, name, descriptor){
// descriptor对象原来的值如下
// {
// value: specifiedFunction,
// enumerable: false,
// configurable: true,
// writable: true
// };
descriptor.writable = false;
return descriptor;
} readonly(Person.prototype, 'name', descriptor);
// 类似于
Object.defineProperty(Person.prototype, 'name', descriptor);
关于decorator的详细内容:http://es6.ruanyifeng.com/#docs/decorator
五、异步编程
1.JavaScript中的异步编程
至少在语言级别上,Javascript是单线程的,因此异步编程对其尤为重要。
拿nodejs来说,外壳是一层js语言,这是用户操作的层面,在这个层次上它是单线程运行的,也就是说我们不能像Java、Python这类语言在语言级别使用多线程能力。取而代之的是,nodejs编程中大量使用了异步编程技术,这是为了高效使用硬件,同时也可以不造成同步阻塞。不过nodejs在底层实现其实还是用了多线程技术,只是这一层用户对用户来说是透明的,nodejs帮我们做了几乎全部的管理工作,我们不用担心锁或者其他多线程编程会遇到的问题,只管写我们的异步代码就好
ES 6以前:
- 回调函数
- 事件监听(事件发布/订阅)
- Promise对象
ES 6之后:
- Generator函数(协程coroutine)
- async和await
2.callback(回调函数)
假定有两个函数f1和f2,后者等待前者的执行结果:
f1();
f2();
如果f1是一个很耗时的任务,可以考虑改写f1,把f2写成f1的回调函数:
function f1(callback){
setTimeout(function () {
// f1的任务代码
callback();
}, 1000);
}
执行代码就变成这样:f1(f2);
采用这种方式,我们把同步操作变成了异步操作,f1不会堵塞程序运行,相当于先执行程序的主要逻辑,将耗时的操作推迟执行。
回调函数的优点是简单、容易理解和部署,缺点是不利于代码的阅读和维护,各个部分之间高度耦合,流程会很混乱,而且每个任务只能指定一个回调函数
3.promise
ES 6中原生提供了Promise对象,Promise对象代表了某个未来才会知道结果的事件(一般是一个异步操作),并且这个事件对外提供了统一的API,可供进一步处理。
使用Promise对象可以用同步操作的流程写法来表达异步操作,避免了层层嵌套的异步回调,代码也更加清晰易懂,方便维护。
4.async函数
ES2017 标准引入了 async 函数,使得异步操作变得更加方便。async 函数是什么?一句话,它就是 Generator 函数的语法糖
详细内容直接看这里:http://es6.ruanyifeng.com/#docs/async
六、函数相关
1.函数参数默认值(函数默认参数)
// ES6 允许为函数的参数设置默认值,即直接写在参数定义的后面:
function log(x, y = 'World') {
console.log(x, y);
} log('Hello') // Hello World
log('Hello', 'China') // Hello China
log('Hello', '') // Hello
2.箭头函数
箭头函数就是匿名函数定义的简化版, 宣称能使得代码更简洁,实际上就是纯粹的垃圾
箭头函数的 this 值是绑定了的,箭头函数没有 arguments 对象,如果要多参数, 必须用 ...
语法如下:
// (参数1, 参数2) => { 语句 }
// (参数1, 参数2) => 语句
// 上面两行相当于下面这函数
function(参数1, 参数2) {
return 语句
} // 如果只有一个参数,圆括号可省略的
// (参数1) => { 语句 }
// 参数1 => { 语句 } // 但是如果没有参数, 必须需要使用圆括号
// () => { 语句 } // 例子
var a1 = [1, 2, 3]
// 下面两个等价
var a2 = a1.map(function(n){
return n * n
})
var a3 = a1.map( n => n * n ) n => n * n
// 上面 1 行等价于下面 3 行
function(n) {
return n * n
}
了解ES6的更多相关文章
- ES6模块import细节
写在前面,目前浏览器对ES6的import支持还不是很好,需要用bable转译. ES6引入外部模块分两种情况: 1.导入外部的变量或函数等: import {firstName, lastName, ...
- webpack+react+redux+es6开发模式
一.预备知识 node, npm, react, redux, es6, webpack 二.学习资源 ECMAScript 6入门 React和Redux的连接react-redux Redux 入 ...
- ES6的一些常用特性
由于公司的前端业务全部基于ES6开发,于是给自己开个小灶补补ES6的一些常用特性.原来打算花两天学习ES6的,结果花了3天才勉强过了一遍阮老师的ES6标准入门(水好深,ES6没学好ES7又来了...) ...
- ES6(块级作用域)
我们都知道在javascript里是没有块级作用域的,而ES6添加了块级作用域,块级作用域能带来什么好处呢?为什么会添加这个功能呢?那就得了解ES5没有块级作用域时出现了哪些问题. ES5在没有块级作 ...
- es6小白学习笔记(一)
1.let和const命令 1.es6新增了let和const命令,与var用法类似,但它声明的变量只在let所在的代码块内有效(块级作用域,es5只有全局和函数作用域) { let a = 1; v ...
- ES6之变量常量字符串数值
ECMAScript 6 是 JavaScript 语言的最新一代标准,当前标准已于 2015 年 6 月正式发布,故又称 ECMAScript 2015. ES6对数据类型进行了一些扩展 在js中使 ...
- ES6之let命令详解
let与块级作用域 { var foo='foo'; let bar='bar'; } console.log(foo,'var'); //foo varconsole.log(bar ,'bar') ...
- ES6 箭头函数中的 this?你可能想多了(翻译)
箭头函数=>无疑是ES6中最受关注的一个新特性了,通过它可以简写 function 函数表达式,你也可以在各种提及箭头函数的地方看到这样的观点——“=> 就是一个新的 function”. ...
- ES6+ 现在就用系列(二):let 命令
系列目录 ES6+ 现在就用系列(一):为什么使用ES6+ ES6+ 现在就用系列(二):let 命令 ES6+ 现在就用系列(三):const 命令 ES6+ 现在就用系列(四):箭头函数 => ...
- ES6+ 现在就用系列(一):为什么使用ES6+
系列目录 ES6+ 现在就用系列(一):为什么使用ES6+ ES6+ 现在就用系列(二):let 命令 ES6+ 现在就用系列(三):const 命令 ES6+ 现在就用系列(四):箭头函数 => ...
随机推荐
- bind() 函数兼容
为了搞清这个陌生又熟悉的bind,google一下,发现javascript1.8.5版本中原生实现了此方法,目前IE9+,ff4+,chrome7+支持此方法,opera和safari不支持(MDN ...
- 定时器setTimeout()的传参方法
更具体的代码:http://www.cnblogs.com/3body/p/5416830.html // 由于setTimeout()的延迟执行特性,所以在执行的函数中直接使用外部函数的变量是无法获 ...
- 【liunx】端口号的占用情况查看
Linux如何查看端口 1.lsof -i:端口号 用于查看某一端口的占用情况,比如查看8000端口使用情况,lsof -i:8000 # lsof -i:8000 COMMAND PID USER ...
- test20180922 世界第一的猛汉王
题意 分析 由于异色点必有连边,所以一个点的covered减去两个点共有的covered就是可存在的环数,十分巧妙. 代码 #include <bits/stdc++.h> using L ...
- 使用lua graphql 模块让openresty 支持graphql api
graphql 是一个很不错的api 查询标准语言,已经有一个lua 的版本支持graphql 项目使用docker&&docker-compose 运行 环境准备 模块安装 lu ...
- sql server CLR
1. 配置sql server 启用CLR 在SQL Server2005/2008里面,CLR默认是关闭的.可以使用如下SQL语句开启CLR. sp_configure 'show advanced ...
- 引用,引用形參,指针形參与指向指针的引用形參,内存泄露及free相关
(另:关于"引用"更具体的讨论.见此.) 由做UVa133引发的一系列问题及讨论 1.引用类型 C++ Primer P51 引用就是对象的还有一个名字,使用多个变量名指向同 ...
- bat删除系统默认共享
在我们的系统中,有很多默认的共享是开启的,可以设置一个bat文件在每次开机的时候把共享删除. net share c$ /del net share d$ /del net share e$ /del ...
- MySQL · 特性分析 · 优化器 MRR & BKA【转】
MySQL · 特性分析 · 优化器 MRR & BKA 上一篇文章咱们对 ICP 进行了一次全面的分析,本篇文章小编继续为大家分析优化器的另外两个选项: MRR & batched_ ...
- LINQ TO SQL 中的join(转帖)
http://www.cnblogs.com/ASPNET2008/archive/2008/12/21/1358152.html join对于喜欢写SQL的朋友来说还是比较实用,也比较容易接受的东西 ...