第二十四题:Babel 会将箭头函数编译成什么?
KieSun opened this issue · comments
使用一个临时变量 _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就是所在的执行上下文的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());
编译成普通函数,用到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);
关键点
- 箭头函数会变成普通的函数,this 指向会在创建之前绑定好
- new 不会出现报错的情况,因为编译成普通函数了,所以可以正常 new 也会有 prototype
- 同样 call apply 执行不会修改 this的指向
箭头函数会被转为普通函数,函数内部如果使用了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 了
早上刚看到题目的时候,就在想了两种方案,一种是通过bind来实现this的改变,一种是通过变量保存。但是关于arguments
, 不是说箭头函数不能使用arguments
吗?那按照我楼上的编译后变成了普通函数,普通函数可以new
可以获取arguments
,是不是与这个箭头函数的原本用意冲突?
箭头函数会编译成普通函数,会在外部生成一个_this传递this给这个函数,函数使用_this
箭头函数会被编译成普通函数,如果箭头函数中涉及了this,那么会在外部生成将this赋值给_this,传到函数中去。