对于“以前的JavaScript” ,Node解决了很多问题:
创建类
const 和 let 代替了var 解决了作用域的问题
Node6 开始,可以使用:
https://node.green/ 上汇总了Node 支持的ES 2015特性
先说类。
在ES5 及以前的版本中,我们需要使用 prototype对象来创建类似于类的结构:
function User(){//构造器
}User.prototype.method = function(){//方法
};
有了Node 6 和 ES 2015,我们就可以写成下面这样了:
class User {constructor() {}method() {}
}
可以看到,代码量少了,也更容易理解了,Node也支持子类、超类和静态方法。
const 和 let 是从 Node4 开始支持的。
在ES5 中,所有变量都是用var 创建的,不管是在函数中还是全局作用域中,都是用var定义变量,所以我们没办法在if语句、for循环以及其他块中定义块级别的变量。
这里一个问题:【到底应该用const 还是 let】
在决定是用const 还是let 时,几乎都可以用const。因为你的大部分代码都是在用你自己的类实例、对象常量或不会变的值,所以大部分情况下都可以用const。即便是有可修改属性的对象,也是可以用const声明的,因为const的意思是引用是只读的,而不是值是不可变的。
Node还有原生的promise 和 生成器。
让开发者可以用流畅的接口风格编写异步代码,有很多库都支持promise。
流畅的接口风格:
[1,2,3].map(n => n * 2).filter(n => n > 3)
生成器可以把异步I/O 变成同步编程风格。
Koa Web 应用库中用到了Generator,如果结合Koa 使用 promise和其他生成器,你就可以抛开层层嵌套的回调(“回调地狱”),在值上yield。
ES2015中的模板字符串在Node 中也很好用。
在ES5中,字符串常量不支持插值,也不能跨行。
现在我们可以使用反引号(`) 定义模板字符串,这样不仅可以插值,还可以跨行。
this.body = `Hello from Node
Welcome, ${user.name}!
>
`
以前只能使用普通字符串进行拼接,不仅代码多,还容易出错。
箭头函数。
比起普通函数写法,箭头函数的语法非常精炼。
有一个参数和一个返回值的回调函数:
[1,2,3].map(v => v * 2)
在Node中,我们一般会需要两个参数,回调的第一个参数通常是错误对象
const fs = require('fs');
fs.readFile('package.json',(err, text) => {console.log('Length:',text.length)
});
如果函数体的代码不止一行,则要用到大括号,箭头函数的价值不仅体现在其精炼的语法,还和JavaScript 的作用域有关。
在ES5以及之前的版本的语言中,在函数中定义函数会把this的应用变成全局对象,像下面这样就很容易出错:
function User(id){//构造器this.id = id;
}User.prototype.load = function (){var self = this;var query = 'select * from user where id = ?';sql.query(query,this.id,function (err,users){self.name = users[0].name;})
}
给self.name 赋值那行代码不能写成 this.name,因为这个函数的this 是个全局变量。
常用的解决办法是在函数的入口处将this 赋值给一个变量。
但是。
箭头函数的绑定就没有这个问题,在ES2015中,上面的例子可以改写成更直观的形式:
// function User(id){
// //构造器
// this.id = id;
// }
//
// User.prototype.load = function (){
// var self = this;
// var query = 'select * from user where id = ?';
// sql.query(query,this.id,function (err,users){
// self.name = users[0].name;
// })
// }class User {constructor(id) {this.id = id;}load() {const query = 'select * from users where id = ?';sql.query(query, this.id, (err, users) => {this.name = users[0].name;});}
}
开发者不仅可以用const 更好地定义建模数据库查询,而且还去掉了麻烦的self 变量。
Node 的动力源自V8 JavaScript 引擎,它是由服务于Google Chrome 的 Chromium项目组开发的。
V8的一个很棒的特性是它会把JavaScript 直接编译为机器码,另外它还有一些代码优化的特性,所以Node 才能这么快。
之前我们说到Node 的另一个本地部件libuv,它负责处理I/O,而V8 负责JavaScript 代码的解释和执行,Node 用C++ 绑定层将libuv 和 V8结合。
下图是Node.js 的软件栈:
因此,Node 中能用的JavaScript特性都可以追溯到V8对该特性的支持。
这一支持是通过特性组来管理的。
Node包含了V8提供的ES2015特性。
这些特性分为shipping.staged和 in progress三组。
shipping组的特性是默认开启的,staged和 in progress组的特性则需要用命令行参数开启。
如果你想用staged特性,可以在运行 Node时加上参数–harmony,V8团队将所有接近完成的特性都放在了这一组。
然而,in progress特性稳定性较差,需要具体的特性参数来开启。
Node的文档建议通过grep "in progress"来查询当前可用的 in progress特性:
node --v8-options | grep "in progress"
在不同的 Node版本中执行这条命令后得到的结果也是不同的。Node自己也有个版本计划,定义了它要提供哪些API。
Node的发行版分为长期支持版(LTS)、当前版和每日构建版三组。
LTS版有18个月的支持服务﹐期满后还有12个月的维护性支持服务。版本号是按照语义版本(SemVer )编制的。SemVer给每个版本定义了一个主要、次要和补丁版本号。比如6.9.1的主要版本号是6,次要版本号是9,补丁版本号是1。
只要看到主版本号发生变化,那就意味着有些API可能不兼容了,也就是说如果要用这个版本的Node,那么你的项目需要重新测试一下。
另外,按Node的发布规则,主版本号增长意味着新的当前版也已经切下来了。每日构建版的构建是自动进行的,每隔.24小时一次,包含这24小时内的最新修改,但一般只用来测试Node的最新特性。
用哪个版本取决于你的项目和组织。有些人可能喜欢更新不那么频繁的LTS,对于那些难以管理频繁更新的大公司来说,这个版本可能更好。但如果你想跟上性能和功能的改进,当前版更合适。