原文地点:https://babeljs.io/blog/2018/…
原文作者:Nicolò Ribaudo
Babel 7.1.0终究支撑新的装潢器提案,能够经由过程@babel/plugin-proposal-decorators
插件运用。
汗青
装潢器这个观点三年多前被Yehuda Katz初次提出。TypeScript在版本1.5(2015年)中宣布了对装潢器的支撑以及许多ES6特征。许多主流框架,像Angular和MobX,为了进步开辟体验也最先运用装潢器。这些使装潢器变得很盛行,而且给了社区一种很稳固的错觉。
Babel在版本5内里初次完成了装潢器,但在版本6的时刻移除了,因为提案在不停的变化。Logan Smyth建立了一个非官方的插件(babel-plugin-transform-decorators-legacy
)来替代Babel5内里的装潢器,在第一个Babel7 alpha版本宣布的时刻的时刻,它被移到了Babel官方的存储库。这个插件照样运用老版本的插件语法,因为还不清晰新的提案会变成什么样。
从那个时刻最先,Daniel Ehrenberg和Brain Terlson和Yehuda Katz一同成为了提案的作者,提案险些完整被重写了。并不是一切的事变都已肯定,而且现在也没有合规实行的计划。
Babel7.0.0为@babel/plugin-proposal-decorators
插件引见了一个新的标志:设置项legacy的唯一有用值为true。为了从提案的第一阶段腻滑过渡到当前版本,须要有这类严重的转变。
在Babel7.1.0,我们引入了对这个新提案的支撑,而且在运用@babel/plugin-proposal-decorators
插件的时刻会默许启用。假如我们不在Babel7.0.0里引入设置项legacy为true的话,在默许状况下就不能够运用准确的语义(也就意味着设置项legacy的值为false)
新的提案还支撑私有字段和要领上的装潢器。我们还没有在Babel中完成这个功用(关于每一个类而言,你能够运用装潢器或许私有元素),但很快就会完成的。
新的提案的转变点
只管新的提案看上去跟旧的很类似,但照样有一些主要的差别点。
语法
旧的提案许可任何有用的左边表达式(笔墨、函数和类表达式,new表达式和函数挪用,简朴和盘算属性接见)作为装潢器的主体:
class MyClass { @getDecorators().methods[name] foo() {} @decorator [bar]() {} }
这个语法有一个题目:[…]这个标记在装潢器里举行属性接见以及定义盘算属性名字的时刻也会被用到。为了消弭这个歧义,新的提案值许可用点标记来举行属性接见(foo.bar),也能够在末了加上一个括号(foo.bar())。假如你须要更多庞杂的表达式,你能够用括号括起来:
class MyClass{ @decorator @dec(arg1, arg2) @namespace.decorator @(complex ? dec1 : dec2) method() {} }
对象装潢器
旧版本的提案许可涌现除了类和类元素装潢器以外的对象成员装潢器:const myObj = { @dec1 foo: 3, @dec2 bar() {}, };
因为跟当前对象的一些表达语法的不兼容性,在提案中被移除了。假如你在你的代码中运用了对象成员装潢器,继承关注因为它们能够会在后续提案中被引入。
- 函数装潢器的参数
新提案引入的第三个主要变化是关于传递给装潢器函数的参数。在初版提案中,类元素装潢器接收一个目的类(对象),一个变量,和一个属性描述符-类似于传递给
Object.defineProperty
的参数。类装潢器将目的组织函数作为唯一的参数。新的提案的装潢器更强大一些:元素装潢器接收一个对象,该对象除了变动属性操作符以外,还许可更转变量值,位置(
static
、prototype
或许own
)以及元素的品种(field
或method
)。他们还能够建立其他的属性并定义运转在类装潢器里的函数。
类装潢器接收一个包括每一个类元素的描述符的对象,从而保证能够在建立类之前修正它们。 晋级
因为这些不兼容性,不能在现有的装潢器上运用新的提案:这会让晋级迥殊慢,因为现有的库(MobX,Angular等)不能再没有引入严重转变的状况下举行晋级。为了处理这个题目,我们已宣布了一个有用程序包,它将装潢器包装在你的代码里。运转这个以后,你能够安全地修正你的Babel设置以运用新的提案。
你能够运用下面这行代码去晋级文件:npx wrap-legacy-decorators src/file-with-decorators.js --decorators-before-export --write
假如你的代码只在Node中运转,或许你用Webpack或Rollup打包你的代码,你能够运用外部依靠来防止在每一个文件中都注入包装函数:
npm install --save decorators-compat npx wrap-legacy-decorators src/file-with-decorators.js --decorators-before-export --external-helpers --write
开放题目
并不是一切的事变都已肯定:装潢器是一个非常大的功用,而且要以最好的体式格局定义它们是非常庞杂的。
导出类的装潢器应当放在那里
这个题目在装潢器的提案里重复涌现:装潢器应当在export这个关键字的前面照样背面?export @decorator class MyClass {} // or @decorator export class MyClass {}
基础题目是export关键字是不是是类声明的一部分,照样只是一个“包装器”。假如是前一种状况,它应当放在装潢器的背面,因为装潢器涌现在声明的开首;在第二种状况下,它应当在装潢器前面,因为装潢器是类装潢器的一部分。
怎样让装潢器和私有元素安全地互动?
装潢器引起了主要的安全题目:假如能够装潢私有元素,那末私有称号(也能够称为私有属性的变量名)能够会被走漏。有差别的安全级别须要斟酌:
1) 装潢器不该当不测走漏私有称号。恶意代码不该当以任何体式格局从其他装潢器中“盗取”私有称号。
2) 只要直接应用于私有元素的装潢器才被视为可信任:类装潢器应当没法读写私有元素?
3) 硬私有(类字段提案的目的之一)意味着私有元素应当只能有类的内部接见:任何装潢器是不是能够接见私有称号?装潢器只能装潢大众元素么?
这些题目须要进一步议论才处理,这也是Babel的用武之地。Babel的作用
跟着What’s Happening With the Pipeline(|>) Proposal?这篇文章里的趋向,跟着Babel7的宣布,我们最先应用我们在JS生态系统中的位置,经由过程让开辟职员测试和反应有关提案的差别版本的体验来协助提案的提出者们。
因为这个缘由,在@babel/plugin-proposal-decorators更新的同时,我们也引入了一个新的属性:decoratorsBeforeExport
,许可用户同时运用export @decorator class C {}
和@decorator export default class
。
我们也将引入一个属性来自定义私有属性装潢器的隐私束缚。在TC39职员做出决议之前,这些属性是必须的,如许我们能够让默许行动成为终究提案晓得的内容。
假如你直接运用我们的解析器(@babel/parse,之前的babylon),你已能够在版本7.0.0里运用decoratorsBeforeExport属性:const ast = babylon.parse(code, { plugins: [ ["decorators", { decoratorsBeforeExport: true }] ] })
用法
Babel用法:
shell版本:npm install @babel/plugin-proposal-decorators --save-dev
JSON版本:
{ "plugins": ["@babel/plugin-proposal-decorators", {"decoratorsBeforeExport": true }] }
检察@babel/plugin-proposal-decorators文档相识更多属性。
你的作用
作为JavaScript的开辟职员,你能够协助概述该言语的将来。你能够测试装潢器的新语法,并向提案的作者们提出反应看法。我们须要晓得你在现实生活的项目中是怎样运用它们的。你也能够经由过程浏览题目中的议论和proposal’s repository中的笔记中发现为什么要如许设想。
假如你想要马上尝试装潢器,你能够在我们的repl里运用差别的预设属性值。