假设我有以下代码,我想使用自定义 Babel 插件进行转换:
let c;
c = document;
console.log(c.readyState);
目标是替换所有出现的 document.readyState
具有自定义功能,例如window.getDocumentReadyState()
.
所以输出应该是这样的:
let c;
c = document;
console.log(window.getDocumentReadyState());
这里的难点在于判断对象c
是哪个值居然有当MemberExpression
访问者被调用,因为我只想替换 document
的 MemberExpressions .这就是为什么我需要查明 c
的当前值是否为是document
.
这是一个只替换每个 <obj>.readyState
的实现成员表达式:
/**
* Replace document.readyState with
* window.getDocumentReadyState();
*/
MemberExpression(path) {
const { node, parent } = path;
const objName = node.object.name;
const propName = node.property.name;
if (t.isAssignmentExpression(parent)) {
return;
}
if (t.isCallExpression(parent)) {
const isCallee = parent.callee === node;
if (isCallee) return;
}
if (propName === 'readyState') {
const customReadyStateFn = t.callExpression(
t.memberExpression(
t.identifier('window'),
t.identifier('getDocumentReadyState'),
),
[t.identifier(objName)],
);
path.replaceWith(customReadyStateFn);
}
},
使用此实现,我执行运行时检查以确定对象的类型是否为 document (HTMLDocument)
里面window.getDocumentReadyState
,因为我无法使用 Babel 做同样的事情。
但是必须有一种方法可以可靠地判断这个变量是否具有值 document
使用静态分析,对吧?
本质上,我需要在当前范围内找到这个变量的最后一个 AssignmentExpression。
我已经尝试使用 path.scope.getBinding(<variableName>)
在范围内查找变量, 但问题是最后一个 AssignmentExpression 没有出现在 binding.references
中.如果该值是在声明期间分配的(let c = document
),那就没问题,因为可以使用 binding
访问该引用。 .
我还尝试遍历范围,但未调用 AssignmentExpression 访问者。
我对 Babel 和 AST 还很陌生,已经到了不知道下一步该做什么的地步,我真的很想摆脱运行时检查。
你会如何解决这样的问题?
最佳答案
也许有点晚了,但我认为可以做到。
需要遍历所有左边的Identifier,检查右边的值是否为document。这样做时,您保留一个数组,其中包含值等于文档的所有变量名称,如果它们的值发生变化并且不再是文档,则将它们从数组中删除。
然后在遍历 MemberExpression 时检查对象名称是否在数组中。
关于javascript - 巴别塔 : Determine the variable value in the current scope,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60834925/