Hi ! ECMAScript 6
Posted 技术农夫
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Hi ! ECMAScript 6相关的知识,希望对你有一定的参考价值。
时间点:
2015年6月,ECMAScript 6 发布正式版本,即ECMASscript 2015
今天:
掌握ES6非常有必要,可能尽管在读者的工作中还不能够具体实现,依然可以作为javascript日常学习的一种重要补充。真正的开始:
一、哪些新意
通过下方,列出ES6的一些常用的新特性,如:
1、声明变量用的 let 和 const
2、三大特性衍生出来的 class, extends, super
3、简单的属性表达 + 箭头函数 + 新的运算符:扩展运算符(三个点点)
4、增强字符串:模板字符串
5、Symbol
6、解构赋值:看! var {a, b}= Melon;
7、修饰器:像ts一样做的更好
8、模块化的东西,如 import, export
1. let 和 const:
let 声明来自于块作用域,她的出现,是为了拯救一些会带来险恶情境的代码场合,什么是险恶环境?有时候,人为的,一些变量会被重复声明或者忘记声明及声明滞后(先引用再声明,往往不会带来实际问题,var是优先语句被检测到并执行的),而javascript的通常做法是,补足变量声明(前提是变量未曾声明)并且声明提前,这会导致错误和上下文作用域的混淆。有点不好理解是吗,喏:
看看图中使用var的声明吧(让你眼前一亮,如同请我喝一杯咖啡那么简单,打赏链接请至文章底部)
和
瞧!这就是代码提升带来的神奇之处。
对于变量,声明过的,未声明的以及重复声明的,最终的引用会带来不一样的结果,值得开发者注意。
而 let 则简单直率很多,请记住:一旦在代码中启用了 let ,则只能在声明后使用,过早引用与 is not defined 所犯的错误无异,重复声明甚至还会引起语法错误!还有,let 声明的变量在浏览器javascript用法中不会成为window对象的属性,就是这样。
const 声明记住两点:一是声明时便要赋值,并且仅在当前代码有效;二是不可更改const声明的变量,这样操作同样会引起语法错误。
2. class,extends + super
引子:如果读者接触过node.js并且查看过他(node.js发展到8.8,已是如此的健壮!)的插件库,会知道,以往的JS面对对象的编程风格主要是用扩展构造函数原型的方式,发现这里。而跟C,Java等强类型语言的类 Class 来创建实例对象有很大的不同,这些语言的类里可以写成员变量,成员函数(这对于JS是最重要的!),然后设置为私有的,受保护的,都可以轻轻松松通过一个类做到。当JS也可以这么使用class的时候,就不用在单个文件中,上下文环境去随意地构造函数体的具体内容,明确构造对象的界限总是一件好事!
class:几乎所有的JS实例对象都有一个属性,这个属性叫 constructor。她是该实例对象所继承的类,又叫做构造函数。和 typeof 的作用是一样的。因此使用ES6类方法时,定义 constructor 十分必要,比如:
// 创建 Melon类
class Melon {
constructor() {
console.error( '我是Melon.prototype的constructor函数' )
}
}
// 引用 Melon类,和ES5标准没有区别,实例化
var a1 = new Melon();
这段代码做了一件很重要的事,类Melon 的构造函数(绿色部分)成为了实例a1的constructor属性,如:
a1.constructor === Melon.prototype.constructor
// true
像什么?是的,既然B构造自A,那么就把A的原型内容继承给B,这就是原型继承。因此,试试给 a1 增加一些新方法吧,改造一下 Melon 的 constructor函数如:
constructor() {
console.error( '我是Melon.prototype的constructor函数' );
this.melon1 = function() { xxx };
...
}
然后就可以轻松调用melon1的原型方法了,利用 a1.melon1();当然,直接创建并使用 类Melon 的普通成员函数也可以,像这样:
// 创建 Melon类
class Melon {
constructor() {
console.error( '我是Melon.prototype的constructor函数' );
this.melon1 = function() { xxx };
}
Melon_function() {
console.error( '我是Melon的成员方法' );
}
}
var a1 = new Melon();
// 引用 Melon类的方法,同原型继承的方法调用一样
a1. Melon_function();
继承extends :了解了最重要的方法后,extends 也不难理解,ES6的 extends 就是把Class进行扩展形成一个新Class用的,一个类继承另一个类的方法。需要注意的是:子类要想继承父类的成员方法,需要在父类的成员方法前添加静态关键字 static。
super 是一个子类中的父类对象,避免父类,子类成员名的相同引用麻烦,ES6把子类里的 super 认作是父类对象(其实更像是父类的原型prototype,en...值得思考一下或者打开浏览器试试?)。但使用起来,相当严格,必须遵循相应的规则,不然会出现语法错误。
3. 简写属性方式的运用 箭头函数 扩展运算符 及${ }
首先,属性方式可以这么玩:
let a = 'Aa',b = 'Ba';
var Melon_Obj = { a,b }
// as
// var Melon_Obj = { a: 'Aa', b: 'Ba' }
第二,箭头函数估计读者早已见过,是的,非常友好的操作,标识符=>表达式,可能用在回调函数或者匿名函数中会更加适合。有两个是需要知道的地方,看:
1. a => a
2. ( a, b ) => { 表达式 }
小编想表达的是,当标识符即argument的数目大于等于两个时,在标识符外头添加圆括号。另外,如果表达式变成了纯粹的对象内容,如 {a: 1, b: 2},请增加圆括号至大括号外,如此 ({a: 1, b: 2}),当然多数情况下,强烈建议用大括号加代码块的方式,因为箭头函数遇到 ‘=>’ 后的符号‘{’就是当作代码块解析的。需要返回的时候正常添加 return,避免混淆代码块与返回值操作。如果代码只有一行,并且不需要输出,可以追加 ‘void’ 如 {void **代码语句**;}。
提醒:箭头函数非常像逼近运算符-->,这是一个双目运算符。
n--> 0
// 如果使用在 while 语句中,可以直接省略n的递增或递减操作,因为-->
// 可以让操作符左边自加或自减
很有趣是吗,但的确是不常见的操作。
扩展运算符是如何使用呢?
很简单,扩展运算符用三个点号 '...' 表示,是把数组或类数组对象展开成一系列用逗号隔开的值。但不要直接在没有语句块包裹的情况下使用,会导致语法错误。
可能用在:
解析字符串
数组合并,类似于concat方法
函数入参的写法,很鸡肋的说
还可以展开对象,就是新兴的对象展开运算符
扩展运算符就说到这里,并没有什么用法难度,如果想更深入了解对象展开运算符,Vuex 项目下的 State 章节可能有更详尽的用法。小编指的是 Vuex官网。当然,如果继续往下阅读本文,一些结合扩展运算符知识的内容会被发现。
4. 模板字符串
引自百度:
反单引号也称重音符,是西文字符,主要用于计算机相关领域。位置在键盘中数字键“1”的左边,其上档符号是“~ ”,使用Shift键可以换挡输入。由于计算机显示的原因,反单引号非常容易和单引号 ‘ 混淆。
` 这是个叫反单引号的东西,请避免与字符串常用语法单引号混淆。
然后还有一个新的语法:${ },模板字符串用法举例,如下:
let a = ' Melon ', b = { name: ' Melon ' };
function c() { return ' Melon ' }
// ${ }新的语法用在此处,可以方便在字符串内插入表达式,没错,就是
// 新增的插值表达式方式,她的内容被当作javascript来执行。如:
`The coder is ${ a }`
// as
`The coder is ${ b.name }`
// as
`The coder is ${ c() }`
提醒:转义字符请读者使用反斜杠 ' \ ',又是一个反字,如:`\$`,`\${a}`,`\$${a}`,第一个输出 $ ,第二个输出有点特别 ${a},第三个输出 $ Melon 。
5. 如何优雅地理解并使用 Symbol
初中的历史书在评价中世纪时,是这样形容封建宗主制度的:
我的附属的附属不是我的附属
后来学到 Symbol,让我联想到了她的应用场景。因此,我加了一句话使她更方便于理解:
即使我的附属的称谓与我的附属的附属的称谓一致,也不能(改变 ‘ 我的附属的附属不是我的附属 ’ 的事实)
终于,ES6 引入了一种新的原始数据类型 Symbol,记住三个地方:
不要在构造 Symbol类型 数据的前面加上 new ,这是多余的,Symbol更像是一个唯一标识符,如:let a = Symbol(); 还嫌不够?
再加个标识符标签:let a = Symbol('only_a')。
不要用点运算符,当Symbol类型数据作为属性的时候。其实,该类型数据完全只有一种用法,那就是用方括号包裹 Symbol数据,如:
melon = {[a]: xxx}或 melon[a] 。
Symbol还有一些好玩的内置属性:试试吧。请进入附文章查看Symbol 内置属性。
6. 解构 Destructuring
使用方法,请看下例,melon是个健壮的数组或者对象!
数组的传统的做法:
// 数组 melon
var a = melon[0]; var b =melon
[1];
ES6:
var [a, b, ...c] = melon; // 有个小伎俩:变量c取到了数组melon除0,1剩下的所有数据
对象的传统的做法:
// 对象 melon = { one: 1, two: 2}
var a = melon .one; var b =melon .two
;
ES6:
var
{ one , two }
= melon; // 有个小伎俩:解析对象时,必须要用符合对象属性名的变量名才可以
最后,当你好奇心地尝试解构 null 或 undefined 时,会得到一个类型错误!
对了,解析函数(前提是返回值为数组或者对象)也是可以的,去浏览器上试试吧,这样,你会记得更牢。
7. 到了一个难点,她叫修饰器,就是像这样:@xxx
在组件中注册服务商,如: @Component
在 NgModule 中注册服务商,如: @NgModule
创建和注册日志服务,如: @Injectable
由此可知,没有装饰器做注入器,Angular 设置都无法建立功能完整的根模块和根组件,还谈什么应用,装饰器对构建 Angular 真的太重要了。
接下来,读者想想,如果我们希望建造一辆车(当作一个 Class:Car),我们会在Car类中创建哪些东西呢,比如轮胎(this.tire),引擎(this.engine),座椅等等。当我们建立好后,可能忘了一件事,尽管这个Car类非常健全,可以行驶(功能完整),但是如果需要给轮胎换一个新配件会引起麻烦,因为在Car类里已经给 this.tire 定义完善了,只有改动Class类,增加一个新的参数 this.tire(NewPatten) ,并且修补其他轮胎,除此以外别无它法。那如果是想给整个轮胎换成新品牌呢?
因此考虑到类的脆弱性和缺乏弹性,有时候要更加灵活地创建类,而修饰器就这样被发明了。相当于用修饰器来解耦复杂的类行为。让类的延伸性更好。不过,如果你还未完全掌握class的用法或者对书写完美的类有十足的苛求,你也可以忽略此小节,她暂时还不适合你。
修饰器方法,简单列举用法:
修饰类
修饰属性
a. 修饰类:看这个代码段落,
// 这里耍了个小聪明使用闭包,增加了修饰器函数的参数入口,不添加入参,
// 可以直接用target代替Owner,并取消闭包的用法
function marked( Owner ) {
return function( target ) {
target.prototype.owner = Owner;
}
}
// 创建一个car类,并修饰它,给他打上独一无二的标识
@marked( 'Melon' )
class car {
consoleOwner() {
console.log( `It is belong to ${ this.owner }` );
}
}
// 创建实例
const vw = new car();
vw.consoleOwner();
// 输出:It is belong to Melon
b. 修饰属性,类似于这样
function decorator( target, name, descriptor ){ xxx }
使用时,比如上文的 consoleOwner:
@decorator
consoleOwner() {
console.log( `It is belong to ${ this.owner }` );
}
其中,标注为绿色的是很重要的参数:
target:指向修饰的目标对象,就是实例化对象,如上文的vw,
name:修饰的属性名
descriptor :属性的描述符
而descriptor对象值如下(因为这实际就是数据类型属性的描述符)
value:包含这个属性的数据值
writable :表示能否修改属性的值。
enumerable:表示能否通过for-in循环枚举属性。(枚举的特性:可以尝试进入Hi文章系列的首篇进行复习回顾)
configurable:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。
Decorator目前在浏览器中还不能简单通过babel实现,另外的Decorator-babel是需要的,因此小编并没有特意贴出Decorator更深入的案例代码,供大家参考,相信随着该技术的深入挖掘,更多通俗易懂的例子将会被呈现出来。
8. import, export的用法
import 是为了引入模块,export 是为了导出模块,喏:
// 文件 ./a.js
export class A { xxx }
// 引入a.js 的A类
import A from './a.js'
xxx...
或者是这样用,请看:
// 文件 ./a.js
export default class A { xxx }
// 引入a.js 的A类
import Melon from './a.js'
xxx...
嗯,并没有什么特别,只是导出时增加了default后,就不用查看a.js代码库的类名了,引入模块起来更加舒畅!
其实,不仅引用类,变量,函数都可以用这个来传递,不再一一举例,甚至使用 " import * as Melon from xxx" 可以帮助将模块多条并入,并作为Melon对象的属性来调用。
使用 import, export 正是创建组件化的关键,有了这样的引入和导出命令,AMD及require方法可以功成身退了。当然,这也包括CommonJS(因为node.js也非常支持ES6,学习ES6果真是十分必要的)。
二、谈一谈 Asynic、Promise对象和Generator
光讲 ES6 的一些特性可能还不够痛快,毕竟是两年前的东西,因此小编加了一些佐料,做了一道菜,叫 " 比较异步操作 ",由于本文篇幅较长,因此将第二大节:Asynic、Promise对象和Generator 放在下一期解读。期望读者留意。下回预告:
1、Promise让回调使用更加有效简洁。
2、Asynic 是小编见过最反 javascript 编程思想的提案,没有之一!!!
3、相对于 Asynic,Generator 普遍看来更像是手动版的 Asynic。
原创内容,欢迎自由转发
扫二维码赞赏:
安卓土豪可以直接最下方点击 赞赏:
以上是关于Hi ! ECMAScript 6的主要内容,如果未能解决你的问题,请参考以下文章