6.28学习 babel转换,es6的装饰器
- 1.babel转换
- 1.1出现问题
- 1.2babel转换
- 2.装饰器
- 2.1类装饰器
- 2.2方法装饰器
1.babel转换
1.1出现问题
先来一段代码,运行,有可能是会报错的,为什么呢?因为JS以前只能运行在浏览器中,Node.js 出现之后,不管是服务器上,还是我们自己的的笔记本上,只要安装了 Node.js 就可以运行 JS 代码了。所以是node帮我们运行了代码的。
有可能报错的原因是node的版本很多,这种很新的语法可能在低版本的node版本是不支持的。
class Animal{
static flag = '哺乳类';
constructor(){
this.name = 'XXX'
}
say(){
console.log('say')
}
}
let animal1 = new Animal();
console.log(animal1,Animal.flag)
animal1.say()
目前我的node版本是14.15.1,是可以支持的
但是我把node的版本降为8.17.0的话,就会报错的
我们下面就以8.17.0的版本演示下面的内容。
1.2babel转换
如果版本不支持的话,我们就可以用babel/将我们的高级代码(es7等)转换为es5代码。这里就要装一个包babel-cli。但是babel-cli是以前的写法了,现在一般是@babel/cli。执行命令:
npm init npm install @babel/cli --dev
安装后会发现在node_modules目录下多一个.bin目录
这里再引入一个 npx命令,它是node5.2版本以上会提供的,帮我们执行node_modules/.bin目录下的文件。那我们执行下 npx babel试一下
看到报错了,未找到@babel/core模块。那我们再npm install @babel/core --dev把它装上后再试一下npx babel
还是报错,语法不对这里是。要告诉它编译的是哪个文件和编译后要变成什么文件。
会发现确实目录下多了个编译后的文件,我这里是es5.js。但是打开一看发现,跟原来编译前的代码一摸一样!!!那不是没编译嘛。
其实是 @babel/core只做转换的动作,但是你还需要告诉它转换的规则是什么。这里就要在你项目的最外层,和node_modules同级目录建一个.babelrc文件。
我们下载包@babel/preset-env,并且在.babelrc中配置
{
"presets": ["@babel/preset-env"],
"plugins": []
}
然后再执行我们的npx命令(我的是npx babel .\index.js -o ./es5.js),发现编译出来的文件不一样了!!!
再运行
但是这个@babel/preset-env包也只能转换已定案的语法,像更高级的语法,例如装饰器,static xxx = 'xx’等还是无法转译的。
@babel/plugin-proposal-class-properties 这个包就是用来转换static xxx = ‘xx’(类的属性的) 不支持的话可以安装。
其实npx的执行顺序可以看作 @babel/cli ==> @babel/core ==> 转换(读取.babelrc中的配置)
2.装饰器
2.1类装饰器
装饰器写在类外面的是类装饰器
//装饰器 mobx nest vue
//装饰器可以修饰 类的属性 类的原型上的方法
//修饰的时候就是把这个类 属性... 传递给修饰的函数
@flag
class Animal{
// static flag = '哺乳类';
name = 'XXX'
say(){
console.log('say')
}
}
function flag(Constructor){
Constructor.type = '哺乳类'
}
console.log(Animal.flag)
类装饰器有个参数,就是会被装饰的类
这里执行npx命令就会报错
他还给了提示,那我们就把@babel/plugin-proposal-decorators装上,并且在.babelrc中配置
{
"presets": ["@babel/preset-env"],
"plugins": ["@babel/plugin-proposal-decorators"]
}
再来npx,还是报错。。。
,babelrc配置写错了
{
"presets": ["@babel/preset-env"],
"plugins": [
["@babel/plugin-proposal-decorators", { "legacy": true }]
]
}
再npx可以的了
上面的装饰器是可以传参的,例如
@flag('哺乳类')
function flag(value){
return function (Constructor) {
Constructor.type = value
}
}
其实@flag可以看成个语法糖
@@flag('哺乳类')
flag('哺乳类')(Animal)
function flag(value){
return function (Constructor) {
Constructor.type = value
}
}
2.2方法装饰器
写在类里面的装饰器就是方法装饰器,他有三个参数的。第一个参数是类的原型对象,上例是Animal.prototype,装饰器的本意是要“装饰”类的实例,但是这个时候实例还没生成,所以只能去装饰原型(这不同于类的装饰,那种情况时target参数指的是类本身);第二个参数是所要装饰的属性名,第三个参数是该属性的描述对象。
@flag
class Animal{
// static flag = '哺乳类';
@readonly
name = 'XXX'
say(){
console.log('say')
}
}
function flag(Constructor){
Constructor.type = '哺乳类'
}
console.log(Animal.type)
//直接编译会出错的 npx babel .\class-decorator.js -o es5.js
//1)类的静态属性
//2)类的属性(实例上的属性)
// function readonly() {
// console.log(arguments)//有三个参数 Animal的实例 属性 配置项({
configurable: true,
enumerable: true,
writable: true,
initializer: [Function: initializer]
})
// }
function readonly(target,property,descriptor) {
console.log(target == Animal.prototype)
}
所以把这段代码编译后执行会报错,
因为这个时候实例还没生成,这样写就不会报错
setTimeout(function () {
console.log(target == Animal.prototype);
});
方法装饰器可以修改属性的描述对象(descriptor),然后被修改的描述对象再用来定义属性。
我们在方法前面定义一个装饰器,它的第三个参数是不一样的
//装饰器 mobx nest vue
//装饰器可以修饰 类的属性 类的原型上的方法
//修饰的时候就是把这个类 属性... 传递给修饰的函数
@flag
class Animal{
// static flag = '哺乳类';
@readonly
name = 'XXX'
@before
say(){
console.log('say')
}
}
function flag(Constructor){
Constructor.type = '哺乳类'
}
console.log(Animal.type)
function readonly(target,property,descriptor) {
setTimeout(() => {
console.log(target == Animal.prototype)
console.log(descriptor)
});
}
function before(target,property,descriptor) {
console.log(descriptor)
}
可以写一些逻辑代码,例如切片
function before(target,property,descriptor) {
console.log(descriptor)
let oldSay = descriptor.value;
descriptor.value = function () {
console.log('before')
oldSay.call(target)
}
}
let animal = new Animal()
animal.say()
结果: