ECMAScript 6.0(以下简称 ES6)是 JavaScript 语言的下一代标准,已经在 2015 年 6 月正式发布了。它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。
ECMAScript 和 JavaScript 的关系是,前者是后者的规格,后者是前者的一种实现(另外的 ECMAScript 方言还有 JScript 和 ActionScript)。日常场合,这两个词是可以互换的。
可见,如chrome浏览器厂商等,把标准变成了现实,即那些标准不再是说说而已,不再是空想,而是实打实的可以为我们开发者所用了……
当然,至于其它方言,无需理会,只需要知道有个叫JavaScript的家伙就好了!
ES6 既是一个历史名词,也是一个泛指,含义是 5.1 版以后的 JavaScript 的下一代标准,涵盖了 ES2015、ES2016、ES2017 等等,而 ES2015 则是正式名称,特指该年发布的正式版本的语言标准。本书中提到 ES6 的地方,一般是指 ES2015 标准,但有时也是泛指“下一代 JavaScript 语言”。
也就是说ES6有两种身份咯,一般的身份就是ES2015标准咯,不然为啥经常看到ES7、ES8、ES9……还不如直接都叫ES6好了!
任何人都可以向标准委员会(又称 TC39 委员会)提案,要求修改语言标准。
一种新的语法从提案到变成正式标准,需要经历五个阶段。每个阶段的变动都需要由 TC39 委员会批准。
- Stage 0 - Strawman(展示阶段)
- Stage 1 - Proposal(征求意见阶段)
- Stage 2 - Draft(草案阶段)
- Stage 3 - Candidate(候选人阶段)
- Stage 4 - Finished(定案阶段)
一个提案只要能进入 Stage 2,就差不多肯定会包括在以后的正式标准里面。ECMAScript 当前的所有提案,可以在 TC39 的官方网站GitHub.com/tc39/ecma262查看。
本书的写作目标之一,是跟踪 ECMAScript 语言的最新进展,介绍 5.1 版本以后所有的新语法。对于那些明确或很有希望,将要列入标准的新语法,都将予以介绍。
xxx提了个标准(如怎么画个大饼)给TC9,结果目前到了草案阶段了,这意味着这个大饼画法在未来zzz年里肯定会纳入正式标准里边的。
虽然已经纳入标准了,但是开发者们依葫芦画瓢的做法,是咩有效果的,即画出来的大饼就是画出来的
要想画出真正的大饼,即可以吃的,而且还得让你说「真香」二字的大饼,这就得要浏览器厂商搞一些东西出来,用于解释你画出来的东西,解释完之后,就可以生成一个真实的大饼了……嗯……真香
2015 年 6 月,ECMAScript 6 正式通过,成为国际标准。从 2000 年算起,这时已经过去了 15 年。
注意:JavaScript.next 指的是 ES6,第六版发布以后,就指 ES7。
查看各大最新浏览器对ES6的支持程度:https://kangax.github.io/compat-table/es6/
可见,随着时间的推移,支持度已经越来越高了,超过 90%的 ES6 语法特性都实现了。
Node 是 JavaScript 的服务器运行环境(runtime)。它对 ES6 的支持度更高。除了那些默认打开的功能,还有一些语法功能已经实现了,但是默认没有打开。使用下面的命令,可以查看 Node 已经实现的 ES6 特性。
// Linux & Mac
$ node --v8-options | grep harmony
// Windows
$ node --v8-options | findstr harmony
在windows下的git bash会返回这样的
stdout is not a tty
结果,这样结果产生的原因是:这不能按预期工作的原因似乎是git bash将命令传递给Windows cmd shell,而不是正确处理输出流
所以 你就在power shell运行此命令即可!
一个工具通吃二者(浏览器和node)对ES6的支持程度:
浏览器端的:http://ruanyf.github.io/es-checker/
node端的:
$ npm install -g es-checker
$ es-checker
=========================================
Passes 24 feature Detections
Your runtime supports 57% of ECMAScript 6
=========================================
从中可以发现对Module模块都不支持哈!
这似乎可以使用webpack之类的来解决哈!
新建一个项目目录(如es6-demo),然后
npm init
它!然后就可以对此项目安装命令了!
Babel 是一个广泛使用的 ES6 转码器,可以将 ES6 代码转为 ES5 代码,从而在现有环境执行。这意味着,你可以用 ES6 的方式编写程序,又不用担心现有环境是否支持。如这样的效果:
// 转码前
input.map(item => item + 1);
// 转码后
input.map(function (item) {
return item + 1;
});
所以大胆地去使用箭头函数吧!当然,就目前而言你无须去转码哈!直接在浏览器运行即可!那些不支持的诸如export、import等就需要转码了!
在项目目录中,安装 Babel:
$ npm install --save-dev @babel/core
Babel 的配置文件是.babelrc
,存放在项目的根目录下。使用 Babel 的第一步,就是配置这个文件。
那么该配置文件的作用是什么呢?——用来设置转码规则和插件
这其中的基本格式是这样的:
{
"presets": [],
"plugins": []
}
presets
字段设定转码规则,官方提供以下的规则集,你可以根据需要安装。
# 最新转码规则
$ npm install --save-dev @babel/preset-env
# react 转码规则
$ npm install --save-dev @babel/preset-react
有了官方所提供的这些规则之后,我们就得将这些规则加入.babelrc
中去,就像这样:
{
"presets": [
"@babel/env",
"@babel/preset-react"
],
"plugins": []
}
注意,以下所有 Babel 工具和模块的使用,都必须先写好.babelrc
。
Babel 提供命令行工具@babel/cli
,用于命令行转码。
同样,我们也需要安装它,安装命令如下:
$ npm install --save-dev @babel/cli
基本用法如下。
# 转码结果输出到标准输出
$ npx babel example.js
# 转码结果写入一个文件
# --out-file 或 -o 参数指定输出文件
$ npx babel example.js --out-file compiled.js
# 或者
$ npx babel example.js -o compiled.js
# 整个目录转码
# --out-dir 或 -d 参数指定输出目录
$ npx babel src --out-dir lib
# 或者
$ npx babel src -d lib
# -s 参数生成source map文件
$ npx babel src -d lib -s
测试效果:
①转码结果输出到标准输出
先在根目录写个xxx.js
:
input.map(item => item + 1);
然后就可以搞事情了:
②转码结果写入一个文件
剩下的两个测试也做了,其中第3个同样不需要事先创建文件,至于那个map文件是方便我们调试使用的!
@babel/node
模块的babel-node
命令,提供一个支持 ES6 的 REPL 环境。它支持 Node 的 REPL 环境的所有功能,而且可以直接运行 ES6 代码。
首先,安装这个模块。
$ npm install --save-dev @babel/node
然后,执行babel-node
就进入 REPL 环境。
$ npx babel-node
> (x => x * 2)(1)
2
babel-node
命令可以直接运行 ES6 脚本。将上面的代码放入脚本文件es6.js
,然后直接运行。
# es6.js 的代码
# console.log((x => x * 2)(1));
$ npx babel-node es6.js
2
似乎可以把用户输入的用es6语法写的代码通过这个模块把它们运行一遍哈!
@babel/register
模块改写require
命令,为它加上一个钩子。此后,每当使用require
加载.js
、.jsx
、.es
和.es6
后缀名的文件,就会先用 Babel 进行转码。
$ npm install --save-dev @babel/register
使用时,必须首先加载@babel/register
。
// index.js
require('@babel/register');
require('./es6.js');
然后,就不需要手动对index.js
转码了。
$ node index.js
2
需要注意的是,@babel/register
只会对require
命令加载的文件转码,而不会对当前文件转码。另外,由于它是实时转码,所以只适合在开发环境使用。
我的测试:
结果:
不需要我们手动转码之后再运行index.js代码了!只要发现你require(需要)了一下,即需要某个模块,那就先转码再引入,类似于这样:
console.log('我是index.js1') //没有转码前:console.log((x => x * 2)(1)); //转码后: "use strict"; console.log(function (x) { return x * 2; }(1)); console.log('我是index.js2')
如果某些代码需要调用 Babel 的 API 进行转码,就要使用@babel/core
模块。
var babel = require('@babel/core');
// 字符串转码
babel.transform('code();', options);
// => { code, map, ast }
// 文件转码(异步)
babel.transformFile('filename.js', options, function(err, result) {
result; // => { code, map, ast }
});
// 文件转码(同步)
babel.transformFileSync('filename.js', options);
// => { code, map, ast }
// Babel AST转码
babel.transformFromAst(ast, code, options);
// => { code, map, ast }
配置对象options
,可以参看官方文档http://babeljs.io/docs/usage/options/。
下面是一个例子。
var es6Code = 'let x = n => n + 1';
var es5Code = require('@babel/core')
.transform(es6Code, {
presets: ['@babel/env']
})
.code;
console.log(es5Code);
// '"use strict";\n\nvar x = function x(n) {\n return n + 1;\n};'
上面代码中,transform
方法的第一个参数是一个字符串,表示需要被转换的 ES6 代码,第二个参数是转换的配置对象。
Babel 默认只转换新的 JavaScript 句法(syntax),而不转换新的 API,比如Iterator
、Generator
、Set
、Map
、Proxy
、Reflect
、Symbol
、Promise
等全局对象,以及一些定义在全局对象上的方法(比如Object.assign
)都不会转码。
举例来说,ES6 在Array
对象上新增了Array.from
方法。Babel 就不会转码这个方法。如果想让这个方法运行,必须使用babel-polyfill
,为当前环境提供一个垫片。
安装命令如下。
$ npm install --save-dev @babel/polyfill
然后,在脚本头部,加入如下一行代码。
import '@babel/polyfill';
// 或者
require('@babel/polyfill');
Babel 默认不转码的 API 非常多,详细清单可以查看babel-plugin-transform-runtime
模块的definitions.js文件。
这个似乎跟babel-register一个使用姿势哈!
我就奇了怪了,之前的讲解都是在命令行里操作,说好的浏览器呢?
Babel 也可以用于浏览器环境,使用@babel/standalone模块提供的浏览器版本,将其插入网页。
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">
// Your ES6 code
</script>
注意,网页实时将 ES6 代码转为 ES5,对性能会有影响。生产环境需要加载已经转码完成的脚本。
Babel 提供一个REPL 在线编译器,可以在线将 ES6 代码转为 ES5 代码。转换后的代码,可以直接作为 ES5 代码插入网页运行。
实现:使成为现实、使原本不存在的情況成为事实。
eg:
近义词:实行、完成
反义词:落空、空想
关于英文:
在更新 npm 5.2.0 的时候发现会买一送一,自动安装了 npx
npx 会帮你执行依赖包里的二进制文件
npx 会自动查找当前依赖包中的可执行文件,如果找不到,就会去 PATH 里找。如果依然找不到,就会帮你安装!
npx 甚至支持运行远程仓库的可执行文件
如:npx http-server 可以一句话帮你开启一个静态服务器
所以这给我的感觉就像是糖……
伪数组是一个含有length属性的json对象,
它是按照索引的方式存储数据,
它并不具有数组的一些方法,只能能通过Array.prototype.slice转换为真正的数组,并且带有length属性的对象
var obj = {0:'a',1:'b',length:2}; // 伪数组
var arr = Array.prototype.slice.call(obj); // 转化为数组
console.log(arr); // 返回["a","b"]
可是当我在用这个 [...obj]
语法的时候,居然不行了
说是:
我的天?wtf,mdn说到:
在JavaScript中,
Object
是不可迭代的,除非它们实现了迭代协议. 因此, 你不能使用 for…of 来迭代对象的属性.做为替代你必须使用
Object.keys
或Object.entries
来迭代对象的属性或属性值
既然这样,为了体现 这种语法[...obj]
,只好这样了:
箭头函数用不了arguments
我用了babel转码工具测试了一下,这种 [...obj]
语法是一种糖,结果如下:
"use strict";
var f = function f(a, b, c) {
var arr = Array.prototype.slice.call(arguments);
console.log(arr);
};
➹:TypeError: ‘x’ is not iterable - JavaScript - MDN
交互式解释器(REPL)既可以作为一个独立的程序运行,也可以很容易地包含在其他程序中作为整体程序的一部分使用。REPL为运行JavaScript脚本与查看运行结果提供了一种交互方式,通常REPL交互方式可以用于调试、测试以及试验某种想法。
基本上所有的脚本语言有REPL的。
音乐创作中的钩子:它是一首歌中比较出彩的,容易被记住的片段(如歌词、旋律),能成为这首歌的一种符号存在,是一首歌的记忆点。说白了就是歌曲中让你有耳朵虫效果的东西
在计算机中:就是在做这件事之前,先处理一下再做,形象一点就是在表白前,先喝点酒壮壮胆……
eg:babel的register模块,require某个模块之前,先babel一下,然后再引入……
➹:流行音乐创作中的“钩子”(hook)是一种什么技巧 ? - 知乎
➹:计算机英语中总出现的”hooks” 是什么意思? “钩子” ? 这个钩子应该怎么理解? 是回调的意思? - 知乎
➹:Web开发中的“黑话” - Livoras - SegmentFault 思否
关于void 0
:
void 运算符 对给定的表达式进行求值,然后返回 undefined
。
所以这里的_this
就是undefined
不过对于箭头函数来说,在非严格模式下,这个this是window对象哈!如:
为此我测试了严格模式下的结果:
其实想想也是很符合逻辑的,因为箭头函数的this,就是其父级作用域的this,而父级作用域的this默认就是window对象了,不管是严格模式还是非严格模式。当然,这对于非箭头函数来说,关于是否为严格模式还是很重要的!
所以问题来了,为啥 是var _this = void 0;
,而不是 var _this = window;
呢?
这个……我就不知道了,我只能说浏览器是啥情况就是啥情况了!