Hi ! ECMAScript 6

Posted 技术农夫

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Hi ! ECMAScript 6相关的知识,希望对你有一定的参考价值。

当前浏览器不支持播放音乐或语音,请在微信或其他浏览器中播放 Hi ! ECMAScript 6


时间点:

2015年6月,ECMAScript 6 发布正式版本,即ECMASscript 2015


今天:

掌握ES6非常有必要,可能尽管在读者的工作中还不能够具体实现,依然可以作为javascript日常学习的一种重要补充。真正的开始:


一、哪些新意

通过下方,列出ES6的一些常用的新特性,如:

1、声明变量用的 let  const

2、三大特性衍生出来的 classextendssuper

3、简单的属性表达 箭头函数 + 新的运算符扩展运算符(三个点点) 

4、增强字符串:模板字符串

5、Symbol

6、解构赋值:看! var {a, b}= Melon;

7、修饰器:像ts一样做的更好

8模块化的东西,如 importexport


1. let 和 const:

let 声明来自于块作用域,她的出现,是为了拯救一些会带来险恶情境的代码场合,什么是险恶环境?有时候,人为的,一些变量会被重复声明或者忘记声明及声明滞后(先引用再声明,往往不会带来实际问题,var是优先语句被检测到并执行的),而javascript的通常做法是,补足变量声明(前提是变量未曾声明)并且声明提前,这会导致错误和上下文作用域的混淆。有点不好理解是吗,喏:


看看图中使用var的声明吧(让你眼前一亮,如同请我喝一杯咖啡那么简单,打赏链接请至文章底部)

Hi ! ECMAScript 6

瞧!这就是代码提升带来的神奇之处。


对于变量,声明过的,未声明的以及重复声明的,最终的引用会带来不一样的结果,值得开发者注意。


而 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的用法或者对书写完美的类有十足的苛求,你也可以忽略此小节,她暂时还不适合你。


修饰器方法,简单列举用法:

  1. 修饰类

  2. 修饰属性


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( targetnamedescriptor ){   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更深入的案例代码,供大家参考,相信随着该技术的深入挖掘,更多通俗易懂的例子将会被呈现出来。


8import, 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的主要内容,如果未能解决你的问题,请参考以下文章

2ECMAScript基础变量

ECMAScript 6 学习笔记

JavaScript变量

ECMAScript 6

ECMAScript 6 中的快捷语法汇总及代码示例

ECMAScript 6学习——let命令