跳到主要内容

转换箭头函数

一、前言


转换前:

const sum = (a,b)=>{
console.log(this);
return a+b;
}

转换后:

var _this = this;
const sum = function(a,b){
console.log(_this);
return a+b
}

二、官方实现


2.1 通过 @babel/preset-env 插件

  1. 安装@babel/corebabel-types@babel/preset-env 依赖

    • @babel/core: babel 核心包
    • babel-types: babel 工具包: 1. 判断验证某个节点是不是某个类型 2.动态创建某个类型的节点
    • @babel/preset-env: babel 转换库预设
  2. 具体实现如下:

    const babelCore = require("@babel/core"); // babel 核心包
    const types = require("babel-types"); // babel 工具包: 1. 判断验证某个节点是不是某个类型 2.动态创建某个类型的节点

    const sourceCode = `const sum = (a,b)=>{ console.log(this); return a+b;}`;
    const targetCode = babelCore.transform(sourceCode, {
    presets: ["@babel/preset-env"],
    });
    console.log(targetCode.code);

2.2 通过 babel-plugin-transform-es2015-arrow-functions 插件

  1. 安装@babel/corebabel-typesbabel-plugin-transform-es2015-arrow-functions 依赖

    • @babel/core: babel 核心包
    • babel-types: babel 工具包: 1. 判断验证某个节点是不是某个类型 2.动态创建某个类型的节点
    • babel-plugin-transform-es2015-arrow-functions: babel 插进: 转换箭头函数
  2. 具体实现如下:

    const babelCore = require('@babel/core'); // babel 核心包
    const types = require('babel-types'); // babel 工具包: 1. 判断验证某个节点是不是某个类型 2.动态创建某个类型的节点
    const transformArrowFunctions = require('babel-plugin-transform-es2015-arrow-functions'); // babel 插进: 转换箭头函数

    const sourceCode = `const sum = (a,b)=>{ console.log(this); return a+b;}`;
    const targetCode = babelCore.transform(sourceCode, {
    plugins: [transformArrowFunctions],
    });
    console.log(targetCode.code);

三、模拟实现


  1. 安装@babel/corebabel-types依赖

    • @babel/core: babel 核心包
    • babel-types: babel 工具包: 1. 判断验证某个节点是不是某个类型 2.动态创建某个类型的节点
  2. 具体实现如下:

    1. 定义transformArrowFunctionSelf,用于充当转换箭头函数插件
    2. transformArrowFunctionSelf 函数的工作如下:
      • 寻找箭头函数所在的上层作用域: 不是箭头函数的函数作用域或者全局作用域
      • 向上层作用域添加语句: var _this = this
      • 替换箭头函数内部this_this
      • 改变箭头函数节点typeFunctionExpression
    3. 寻找箭头函数所在的上层作用域 通过 nodePath.findParent 来实现
    4. 查询箭头函数内部作用域调用 this 的地方 通过 nodePath.traverse 来实现,里面通过ThisExpression访问器来判断是否有this调用
    5. 向上层作用域添加语句 通过 thisEnvFn.scope.push 来实现
    6. 替换箭头函数内部this_this 通过 thisPath.replaceWith 来实现
    const babelCore = require("@babel/core");
    const types = require("babel-types");

    function getScopeInfoInformation(nodePath) {
    const thisPaths = [];
    nodePath.traverse({
    ThisExpression(thisPath) {
    thisPaths.push(thisPath);
    },
    });
    return thisPaths;
    }

    function hoistFunctionEnvironment(nodePath) {
    const thisEnvFn = nodePath.findParent(
    (p) => (p.isFunction() && !p.isArrowFunctionExpression()) || p.isProgram(),
    );
    const thisPaths = getScopeInfoInformation(nodePath);
    const thisBinding = "_this";
    if (thisPaths.length > 0) {
    thisEnvFn.scope.push({
    id: types.identifier(thisBinding),
    init: types.thisExpression(),
    });
    thisPaths.forEach((thisPath) => {
    const thisBindingIdentifier = types.identifier(thisBinding);
    thisPath.replaceWith(thisBindingIdentifier);
    });
    }
    }

    const transformArrowFunctionSelf = {
    visitor: {
    ArrowFunctionExpression(nodePath) {
    const { node } = nodePath;
    hoistFunctionEnvironment(nodePath);
    node.type = "FunctionExpression";
    },
    },
    };
    const sourceCode = `const sum = (a,b)=>{ console.log(this); return a+b;}`;
    const targetCode = babelCore.transform(sourceCode, {
    plugins: [transformArrowFunctionSelf],
    });
    console.log(targetCode.code);