KieSun / all-of-frontend

你想知道的前端内容都在这

Home Page:https://yuchengkai.cn/docs/frontend

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

第二十四题:Babel 会将箭头函数编译成什么?

KieSun opened this issue · comments

commented

上一题中大家聊了普通函数和箭头函数的区别。

那么你觉得 Babel 是如何编译箭头函数又能保留先前的特性?

去答题

新建了一个大厂真题每日打卡群,有意愿学习打卡的再进,请备注打卡

使用一个临时变量 _this 存储上下文的 this 给普通函数内部调用。

直接打开 babel playground 试一试:

const name = 'foo'

const foo = () => {
 console.log(this.name)
}

compiled:

var _this = this;

var name = 'foo';

var foo = function foo() {
  console.log(_this.name);
};

编译成普通函数,用到this就存下上下文的this,let _this = this,内部使用_this.xxx,arguments同理

会编译成普通函数,内部使用 _this转换

//in
var bob ={
  _name:"Bob",
  _friends:["Sally","Tom"],
  printFriends(){
  this._friends.forEach(f =>
        console.log(this._name +" knows "+ f));
  }
};

// out
var bob ={
  _name:"Bob",
  _friends:["Sally","Tom"],
  printFriends(){
  var _this =this;
  this._friends.forEach(function(f){
      return console.log(_this._name +" knows "+ f);
    });
  }
};
console.log(bob.printFriends());

babel会直接将箭头函数编译为普通函数
涉及到this的地方会在箭头函数定义的作用域头部将this赋值给_this

https://babeljs.io/docs/en/babel-plugin-transform-arrow-functions

箭头函数会编译成普通函数并将 this 保存下来

编译前:
image
编译后:
image

箭头函数直接编译成普通函数;
箭头函数的特性:函数内的this就是所在的执行上下文的this;
babel在箭头函数所在作用域头部将this指向_this,然后箭头函数内部使用的是_this。

示例

原代码

var a = () => {};
var a = (b) => b;

const double = [1,2,3].map((num) => num * 2);
console.log(double); // [2,4,6]

var bob = {
  _name: "Bob",
  _friends: ["Sally", "Tom"],
  printFriends() {
    this._friends.forEach(f =>
      console.log(this._name + " knows " + f));
  }
};
console.log(bob.printFriends());

babel编译后

var a = function () {};
var a = function (b) {
  return b;
};

const double = [1, 2, 3].map(function (num) {
  return num * 2;
});
console.log(double); // [2,4,6]

var bob = {
  _name: "Bob",
  _friends: ["Sally", "Tom"],
  printFriends() {
    var _this = this;

    this._friends.forEach(function (f) {
      return console.log(_this._name + " knows " + f);
    });
  }
};
console.log(bob.printFriends());

参考babel官方文档

编译成普通函数,用到this就存下上下文的this,let _this = this,内部使用_this.xxx,arguments同理

箭头函数里面的arguments就是其所在执行上下文的arguments吗

使用new 操作箭头函数或者箭头函数内部使用了yeild语句等箭头不支持语法时直接报错
使用this和arguments时外层函数分别用一个变量保存this和arguments,如果不使用是不会保存的this和arguments的

babel会把箭头函数编译成普通函数,修改this指向,为函数内上下文等,

1. this和arguments会在外部生成临时变量_this和_arguments存储

const name = 'foo';
(function(){
	return ()=>{
    	console.log(this, arguments)
    }
})();

编译后

var name = 'foo';
(function () {
  var _arguments = arguments,
      _this = this;
  return function () {
    console.log(_this, _arguments);
  };
})();

2. new的机制不会做限制,原本应该报错,编译后会new成功

const test = () => console.log("1")
const newTest = new test();

编译后

var test = function test() {
  return console.log("1");
};
var newTest = new test();

Babel编译前

var a = (param) => {
	console.log(this);
  console.log(param);
  console.log(arguments);
  console.log(this.t);
}

var m = {
	t: 20
}

a.call(m, 1); // call 不能修改 a 的 this 指向

a(1)

var b = new a();
console.log(b);

Babel 编译后

"use strict";

var _arguments = arguments,
  _this = void 0;

var a = function a(param) {
  console.log(_this);
  console.log(param);
  console.log(_arguments);
  console.log(_this.t);
};

var m = {
  t: 20
};
a.call(m, 1); // call 不能修改 a 的 this 指向

a(1);
var b = new a();
console.log(b);

关键点

  1. 箭头函数会变成普通的函数,this 指向会在创建之前绑定好
  2. new 不会出现报错的情况,因为编译成普通函数了,所以可以正常 new 也会有 prototype
  3. 同样 call apply 执行不会修改 this的指向
commented

箭头函数会被转为普通函数,函数内部如果使用了this的话,会在函数外部声明_this变量存储外部this

箭头函数会被编译成普通函数,如果函数内部使用了this,会在函数所在作用域头部将this绑定到_this上,函数内部使用_this

1.babel将箭头函数编译成普通的函数,this和arguments会被提前存储,普通函数内的this和arguments用的就是存储的。
2.因为编译成普通函数,所以new不会报错了。

let a =(arg)=>{
//doSomething
}
编译后:
var a(function(){
let _this=this;
function a(){
//doSomething
}
return a.bind(_this,...arg)
})()

大家可以在 https://www.babeljs.cn/repl 中尝试一下(注意打钩 force all transfroms)

  const name = 'foo';
  (function(){
    return ()=>{
        console.log(this, arguments)
      }
  })();
  // 转换后
  var name = 'foo';
  (function () {
    var _arguments = arguments,  
        _this = this;  
    return function () {
      console.log(_this, _arguments);
    };
  })();
  // this 和 arguments 会在外部生成临时变量_this 和_arguments 存储
  // 所以 this 指向不会被 call 等改变
  // 但是转换成普通函数后,可以用 new 了 
commented

早上刚看到题目的时候,就在想了两种方案,一种是通过bind来实现this的改变,一种是通过变量保存。但是关于arguments, 不是说箭头函数不能使用arguments吗?那按照我楼上的编译后变成了普通函数,普通函数可以new 可以获取arguments,是不是与这个箭头函数的原本用意冲突?

箭头函数会编译成普通函数,会在外部生成一个_this传递this给这个函数,函数使用_this

commented

箭头函数会被编译成普通函数,如果箭头函数中涉及了this,那么会在外部生成将this赋值给_this,传到函数中去。