Node.js笔记七:es6
es6是javascript的新一代语法规范,现在很多新的库都是基于新的es6语法规范编写。得益于类结构,方便了大型项目的编写。在webpack,babel等工具的帮助下,es6离我们并不遥远。说到es6不得不说es5,也想说说es7。
网上es6的教程很多,这里推荐的是阮一峰老师的ECMAScript 6 入门。
es5
我相信很多的前端工程师嘴上说的Javascript都是es5,因为es5可以直接在大部分浏览器当中运行,兼容性问题较少。由于es5当中所有数据类型都是对象,并不存在类的概念,只有原型。所有的原型链都指向Object。
这时,面试官问你,用原始es5写一个class类名为person,它具有公有属性name,和私有属性age,公有函数setAge()设置私有变量age,公有函数getAge()获取变量age。
function Person(props){
if(props){
this.name = props.name||"brandon";
var age = props.age||26;
}else{
this.name = "brandon";
var age = 26;
}
this.setAge = function(_age){
age = _age;
}
this.getAge = function(){
return age;
}
}
其中,this指向的是自己的prototype。在进行new操作以后,该对象的属性可以被外部读取,便像是公有变量。而var定义的变量不能被外部读取,可以看作私有变量。
这里补充一点,new的过程其实并不是类的实例化。而是构造函数执行的过程,将this的属性赋予新的对象。
面试官再问你,写一个class类名为teacher继承于person,具有私有属性studentCount公有方法setStudentCount()设置私有变量studentCount,公有函数getStudentCount()获取变量studentCount。没有类怎么办?
function Teacher(props){
Person.call(this, props);
if(props){
var studentCount = props.studentCount||55;
}else{
var studentCount = 55;
}
this.setStudentCount = function(_count){
studentCount = _count;
}
this.getStudentCount = function(){
return studentCount;
}
}
这不过是个构造函数。原型链并没有建立。步骤如下:需要创建一个新的函数,原型指向父类。子类原型是它的实例。详细参考:原型继承-廖雪峰Javascript官网。源码参考。其实,es5面向对象的方法还有很多,想了解各自优劣,参看Javascript面向对象编程(二):构造函数的继承。
function inherits(Child,Parent){
var F = function(){};
F.prototype =Parent.prototype;
Child.prototype = new F();
Child.prototype.constructor = Child;
}
inherits(Teacher, Person);
这时候,面试官再问你,es5怎么实现多继承。
function Man(){
var sex = 'male'
this.setSex = function(_sex){
sex = _sex
}
this.getSex = function(){
return sex
}
}
function Student(){
Person.call(this)
Man.call(this)
}
for(var i in Person.prototype){
Student.prototype[i] = Person.prototype[i]
}
for(var i in Man.prototype){
Student.prototype[i] = Man.prototype[i]
}
由于空方法继承法在多继承的情况下会出现被覆盖的情况。最终只能使用复制法。该方法将父类的prototype复制给子类,出现名字重复的话,直接被覆盖。
es6
如果你困扰于es5的面向对象,变量提升,函数提升和作用域的问题,那么es6则是你的救星。es6也就是es2015。它给你一个完整的编程语言。
数据类型
var
是es5变量声明的一个标志。它出现的时候你要小心,因为变量提升。它没出现的时候,你更加需要小心,它有可能改变了上一层作用域的值。
es5只有全局作用域和函数作用域,没有块级作用域。
--30分钟掌握ES6/ES2015核心内容
es6的let
和const
则没有这个问题,他俩给你的是类似其他语言般正常的体验,使用的是块级作用域。
let
是变量声明,并不会出现变量提升,而且可以在for循环中放心使用。const
则为常量声明,已经定义不能可以被改变,很好地避免了变量的重复声明。
面向对象
es6提供完整的class和继承,但是很可惜的是并不具备私有变量。如下的定义_age
并非正在的私有变量。_age
还是可以被外界访问。上方的面向对象代码可以被重构。
class Person {
constructor(){
this.name = 'brandon'
this._age = 26;
}
setAge(_a){
this._age = _a;
}
getAge(){
return this._age;
}
}
继承用extends,super则是执行父类的构造函数。
class Teacher extends Person {
constructor(){
super()
this._studentCount = 55
}
setStudentCount(_b){
this._studentCount = _b
}
getStudentCount(){
return this._studentCount
}
}
如果真的需要私有变量,可以考虑用weakMap
。详情参考如何在 ES6 中管理类的私有数据。这里不做详细说明。
箭头函数
箭头函数内部没有constructor方法,也没有prototype,所以不支持new操作。但是它对this的处理与一般的普通函数不一样。箭头函数的 this 始终指向函数定义时的 this,而非执行时。使用前要搞清楚this的指向。
其他特征
解构,默认参数和字符串格式化都非常实用,参考ECMAScript 6 入门。
es7
正因为es6还是有缺点,所以才要有进步。
展望es7,es7在es6的基础上,它增加了一些新的语言特性。可以说,es7是es2016发展的过程中,有好几个stage。
语法特性包括:
- 指数运算符
- SIMD.JS – SIMD APIs + polyfill
- 异步函数
- Object.values/Object.entries
- 字符串填充
- 函数参数列表与调用中的尾逗号
由于es7还在发展的过程中,很多“语法糖”特性并未稳定。暂时不推荐用于生产当中。题外话,著名的koa是基于es6开发的,而koa2结合es7的await和async的属性实现异步函数。
扩展阅读
【译】ECMAScript 2016 (ES7) 新特性一览
欢迎关注我的微信公众号:brandonxiang