目录:
一、介绍
二、property-mutators插件介绍与使用
三、源码解析
1、第一件事情
2、第二件事情
四、学到的知识
字数:大约900字
一、介绍
Babel 插件是用于扩展 Babel 编译器的功能的组件,它们可以添加新的语法、转换器、插件等,以便更好地适应不同的开发需求。在前端开发中,Babel 插件通常与打包工具(如 webpack)一起使用,以便将 ES6+ 代码转换为向后兼容的 JavaScript 代码,并打包成浏览器可以识别的静态资源。
二、property-mutators插件介绍与使用
上一节讲了ES3中两个插件,这一节看ES5中的插件。
@babel/plugin-transform-property-mutators
@babel/plugin-transform-property-mutators 是一个 Babel 插件,它提供了一组转换器,用于转换对象属性的定义方式。具体来说,它可以将对象字面量中的 get 和 set 属性转换成 Object.defineProperty 的形式,以及将对象字面量中的 method 属性转换成对象字面量的方法简写形式。
举个例子,将以下代码:
// babel03/src/index.js
const obj = {
get name() {
return this._name;
},
set name(value) {
this._name = value;
},
method() {
console.log("hello");
},
};
使用 @babel/plugin-transform-property-mutators 插件转换后,会得到以下代码:
const obj = Object.defineProperties({
method() {
console.log("hello");
}
}, {
name: {
get: function () {
return this._name;
},
set: function (value) {
this._name = value;
},
configurable: true,
enumerable: true
}
});
实际操作一下:
yarn add --dev @babel/plugin-transform-property-mutators
// babel03/babel.config.js
module.exports = {
plugins:[
[
'@babel/plugin-transform-property-mutators'
]
]
};
运行
npx babel src/index.js -d dist
结果
// babel03/dist/index.js
const obj = Object.defineProperties({
method() {
console.log("hello");
}
}, {
name: {
get: function () {
return this._name;
},
set: function (value) {
this._name = value;
},
configurable: true,
enumerable: true
}
});
可以看到,get 和 set 属性被转换成了 Object.defineProperty,而 method 属性则被转换成了对象字面量的方法简写形式。
这个插件主要用于支持一些旧版本的 JavaScript 运行环境,例如 IE8。在现代的 JavaScript 运行环境中,可以直接使用对象字面量的 get 和 set 属性,以及方法简写形式,而不需要通过 Object.defineProperty 进行定义。
三、源码解析
export default declare(api => {
api.assertVersion(7);
return {
name: "transform-property-mutators",
visitor: {
ObjectExpression(path) {
const { node } = path;
let mutatorMap: MutatorMap | undefined;
const newProperties = node.properties.filter(function (prop) {
if (
t.isObjectMethod(prop) &&
!prop.computed &&
(prop.kind === "get" || prop.kind === "set")
) {
pushAccessor(
(mutatorMap ??= {}),
prop as t.ObjectMethod & { kind: "get" | "set"; computed: false },
);
return false;
}
return true;
});
if (mutatorMap === undefined) {
return;
}
node.properties = newProperties;
path.replaceWith(
t.callExpression(
t.memberExpression(
t.identifier("Object"),
t.identifier("defineProperties"),
),
[node, toDefineObject(mutatorMap)],
),
);
},
},
};
});
通过分析,我们会发现,其实他就主要做了两件事情。
第一件事情
过滤对象的属性,只需要get、set、isObjectMethod,得到新的对象。
node.properties = newProperties;
// pushAccessor
export function pushAccessor(
mutatorMap: MutatorMap,
node: t.ObjectMethod & { kind: "get" | "set"; computed: false },
) {
const alias = t.toKeyAlias(node);
const map = (mutatorMap[alias] ??= {
_inherits: [],
_key: node.key,
} as DefineMap);
map._inherits.push(node);
const value = t.functionExpression(
null,
node.params,
node.body,
node.generator,
node.async,
);
value.returnType = node.returnType;
t.inheritsComments(value, node);
map[node.kind] = value;
return map;
}
第二件事情
根据新对象转成Object.defineProperty 的形式
toDefineObject(mutatorMap)
export function toDefineObject(mutatorMap: any) {
const objExpr = t.objectExpression([]);
Object.keys(mutatorMap).forEach(function (mutatorMapKey) {
const map = mutatorMap[mutatorMapKey];
map.configurable = t.booleanLiteral(true);
map.enumerable = t.booleanLiteral(true);
const mapNode = t.objectExpression([]);
const propNode = t.objectProperty(map._key, mapNode, map._computed);
Object.keys(map).forEach(function (key) {
const node = map[key];
if (key[0] === "_") return;
const prop = t.objectProperty(t.identifier(key), node);
t.inheritsComments(prop, node);
t.removeComments(node);
mapNode.properties.push(prop);
});
objExpr.properties.push(propNode);
});
return objExpr;
}
尽管这份代码已经是6年前写的了。但是3个月前还有人在维护,并且将用到的types和方法抽离到了当前目录下。所以学这些永远都不晚,当下即最新。
四、学到的知识
一定要不停的学习。ES6、7、8、9 + 这些每个新增知识都要去记住,并使用。例如?. ?? ??= !! 这些基础的内容
代码里面不要使用乱七八糟的命令方式
不要再写 ==; 都用===
尽可能的简洁