昨天做试题的时候遇到了这个题目
var a = 1;
function fn1() {
console.log(this.a)
}
const fn2 = () => {
console.log(this.a)
}
const obj = {
a: 10,
fn1: fn1,
fn2: fn2
}
fn1()
fn2()
obj.fn1()
obj.fn2()
哦这该死的网易,怎么出这么简单的题目,答案是:1,1,10,10 对,应该是这样的,吧?
可是再仔细一想,不对啊,我记得箭头函数的this对象好像不是在运行时基于函数的执行环境绑定的,他是有点奇怪的,事后仔细查了资料才知道,原来正确答案应该是 :1,1,10,1
一言概之,是因为:箭头函数的this和arguments只会从它自己所在作用域链的上一层继承,不会创建自己的this和argumrnts!!!(只有函数才会有this和arguments属性)
让我再举几个例子给泥们looklook:
//普通函数
var obj = {
bar: function () {
console.log(this); // 被obj调用,this指向{bar: ƒ}bar: ƒ ()__proto__: Object
var x = function() {
console.log(this)//Window对象
};
return x;//闭包,this通常(即不使用箭头函数的情况)默认为全局对象,若在严格模式则为undefined
}
};
var fn = obj.bar();
fn() ;
//箭头函数
// 创建一个含有bar方法的obj对象,
// bar返回一个函数,
// 这个函数返回this,
// 这个返回的函数是以箭头函数创建的,
// 所以它的this被永久绑定到了它外层函数的this。
// bar的值可以在调用中设置,这反过来又设置了返回函数的值。
var obj = {
bar: function () {
console.log(this); // {bar: ƒ}bar: ƒ ()__proto__: Object
var x = (() => this);
return x;
}
};
// 作为obj对象的一个方法来调用bar,把它的this绑定到obj。
// 将返回的函数的引用赋值给fn。
var fn = obj.bar();//此时外层函数已经运行完毕,他的this已经绑定到{bar: ƒ}这个环境
console.log(fn() === obj); // true
console.log(fn()); // {bar: ƒ}bar: ƒ ()__proto__: Object
// 直接调用fn而不设置this,
// 通常(即不使用箭头函数的情况)默认为全局对象
// 若在严格模式则为undefined
// 但是注意,如果你只是引用obj的方法,
// 而没有调用它,this没有及时绑定到{bar: ƒ}这个环境
var fn2 = obj.bar;
// 那么调用箭头函数后,this指向window,因为它从 bar 继承了this。
console.log(fn2()() == window); // true
/* 此时等于在全局环境中调用
function () {
console.log(this); // {bar: ƒ}bar: ƒ ()__proto__: Object
var x = (() => this);
return x;
}
*/
再来一粒,这次带有arguments
//普通函数
var name = "The Window";
var object = {
name: "My Object",
getNameFunc: function () {
console.log(arguments[0],'aa')//4
console.log(this.name)//"My Object"
return function () {//闭包,this通常指向window
console.log(arguments[0],'a')//5
return this.name;
};
}
};
console.log(object.getNameFunc('4')('5')); // The Window
//箭头函数
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(a) {
console.log(this.name)//"My Object"
console.log(arguments[0],'aa')//4
return (a) => {
console.log(arguments[0],'a')//4,这里是继承了上一层的arguments
return this.name; //虽然是闭包,但成功继承了上一层的this
};
}
};
console.log(object.getNameFunc('4')('5')); //"The Object"
//函数都是箭头函数
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : (a) => {
console.log(this.name)//"The Window"
//console.log(arguments[0],'aa')//error
return (a) => {
//console.log(arguments[0],'a')//error
return this.name;
};
}
};
console.log(object.getNameFunc('4')('5')); //"The Window"
//此时虽然是object调用了getNameFunc函数,但是箭头函数的this是指向上一层环境,即全局环境,所以this指向Window对象,而Window对象没有arguments,所以会出错
箭头函数还有一个值得注意的特性—— 无法使用call或者apply绑定this值。
由于 箭头函数没有自己的this指针,通过 call()
或 apply()
方法调用一个函数时,只能传递参数(不能绑定this),他们的第一个参数会被忽略。(这种现象对于bind方法同样成立)
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(a) {
console.log(this.name)//"outer"
console.log(arguments[0],'aa')//4
return (a) => {
console.log(arguments[0],'a')//4
return this.name;
};
}
};
console.log(object.getNameFunc.call({name:'outer'},'4').call({name:'inner'},'5')); //"outer"
再来一题,也是网易的
function fun() {
return () => {
return () => {
return () => {
console.log(this.name)
}
}
}
}
var f = fun.call({ name: 'foo' });
f.call({name:'1'})()()//foo
f().call({name:'2'})()//foo
f()().call({name:'3'})//foo
你做对了吗?
推荐阅读