箭头函数this指向的问题

唐伯虎点蚊香
  • 376
function foo() {
  setTimeout(() => {
    console.log('id:', this.id);
  }, 100);
}

var id = 21;

foo.call({ id: 42 });
// id: 42

箭头函数内部的this是指向定义时所在的对象,不是执行时所在的对象。按照这个道理的话,setTimeout内部的函数不管是不是箭头函数应该都是指向window啊。定义的时候,内部的this不应该指向window,执行的时候才是指向调用的对象{ id: 42 }吗?求教

回复
阅读 1.4k
17 个回答

明确两件事

  1. 箭头函数的this在定义时就确定,就是所在作用域
  2. function的this只有调用时能确定,明白这两点才能继续
function foo() {
  setTimeout(() => {
    console.log('id:', this.id);
  }, 100);
}

var id = 21;

foo.call({ id: 42 });
  1. function foo内部的箭头函数跟function foo一致
  2. 接下来看function foo的this怎么确定,看到调用方式是用的call,这里this为{id:42}这个对象

如果是foo({id:42}),那么this是undefined或window(取决于严格模式)

你可以理解成箭头函数写在哪里,就获取哪里的this
这里明显就直接读取foo的执行环境中的this,而foo被你强制绑定到{ id: 42 }上,所以this自然指向这个对象。

call()apply()方法会改变this的指向。

this不是window,而是{id:42},function的this不是window,foo.call的第一个参数就是foo函数里面的this.

function foo() {
var x=this;
setTimeout(() => {

var y=this;
console.log('id:', this.id);

}, 100);
}

定义时的this,指的是x和y都是指向同一个this,显然x是{id:42},所以y也是。

这里箭头函数中的 this 即函数 foo 里的 this。直接调用时 this.idwindow.id;使用 call 时将 foo 的 this 指向了 {id: 42} 对象,此时 this.id 为 42。

foo(); // id: 21
foo.call({ id: 42 }); // id: 42

因为.call()方法是先将foo的this值绑定到obj对象上,再执行foo 如果含有id就不会在继续在原型链中找了

function foo() {
  setTimeout(() => {
    console.log('id:', this.id);
  }, 100);
  
  this.fun =()=>{
    console.log(this);
  }
}
var id = 21;
var obj = { id: 42 };

foo.call(obj);

console.log(obj)

clipboard.png

箭头函数没有自己的this, 它的this是继承而来。默认指向在定义它时所处的对象(宿主对象),而不是执行时的对象。比如:

function a() { 
   console.log(this);  //window
}  
a(); 

写到这里相信你应该明白了吧~

原本foothiswindow的,后来call之后this指向变成{id: 42}了。
所以执行的是foo.call({}),而不是foo()本身。(这里很关键!)

如果此时你再去执行foo() ,打印的还是21

foo没执行,setTimeout里面箭头函数还没定义啊,就像下面的fun,没有执行foo时候内存是没有fun这个函数的
严格来说 “箭头函数内部的this是指向定义时所在的对象”不对的,箭头函数是没有this的,它只会从自己的作用域链的上一层继承this,规则就和下面代码的变量ttt一样;
最后看看MDN关于箭头函数的解释

var ttt = '888'
function foo() {
  var ttt = '999'
  setTimeout(() => {
    console.log(ttt) // 999
    console.log('id:', this.id);
  }, 100);

  var fun = () => {console.log(this.id)}
  setTimeout(fun, 100)
}

如果只是想了解箭头函数this指向的问题,我这个例子不知道能不能帮到你

var test = {

aa:function(){
    console.log(this);
    setTimeout(function(){
        console.log(this)
    },1)
},
bb(){
    console.log(this);
    setTimeout(()=>{
        console.log(this)
    })
}};

test.aa()
    >{aa: ƒ, bb: ƒ}
    >Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, parent: Window, …}
    
test.bb()
    >{aa: ƒ, bb: ƒ}
    >{aa: ƒ, bb: ƒ}
 

1.普通函数调用 this 指向 window

function fn() {
    console.log(this);
}
window.fn();

2.方法调用 this 指向 调用该方法的对象

var obj = {
    fun: function () {
        console.log(this);
    }
}
obj.fun();

3.作为构造函数的调用 构造函数内部的this指向由该构造函数创建的对象

var gf = {
    name : "tangwei",
    bar : "c++",
    sayWhat : function() {
        console.log(this.name + "said:love you forever");
    }
}

4.作为事件的处理函数 触发该事件的对象

btn.onclick = function () {
    console.log(this);
}

5.作为定时器的参数 this 指向 window

setInterval(function() {
    console.log(this);
}, 1000);

总结:函数内部的this,是由函数调用的时候来确定其指向的

箭头函数的this指向由其定义时所在的上下文环境决定。

你要是直接 foo() ,那就是指向全局,但是你写了 foo.call(),就会指向你传入的这个对象。
因为箭头函数中的 this 会捕获它外层的 this 指向。

fun.call(thisArg, arg1, arg2, ...)

其中 thisArg 为函数运行时指定的 this 值。

你这里 foo 方法运行时,指定的对象为 { id: 42 } ,那么 this.id 当然是 42

参考MDN:https://developer.mozilla.org...

箭头函数导致this总是指向函数定义生效时所在的对象,而普通函数则是定义生效的时候。这里箭头函数的定义生效是在foo函数生成时,而它的真正执行要等到 100 毫秒后,100秒后生效时所在对象是{id:42}。
http://es6.ruanyifeng.com/#do...

另外 call在这里改变了函数的作用域,使其指向{id:42}

setTimeOut所传递的函数中的this,会指向全局对象(window)。但是箭头函数不会创建自己的this,它只会从自己的作用域链的上一层继承this.

所以应该使用foo函数作用域中的this,即使用call指定的{id:42}对象

哇好多答案!

忍不住也跟一波.

call改变了this的指向

function foo() {
  //1、首先箭头函数没有this,这个你也说了
  setTimeout(() => {
  2、这里的this会像(原型链)一样往上找所在的作用域,找到当前所在的函数作用域
    console.log('id:', this.id);
  }, 100);
}

var id = 21;
//3、默认当前所在函数作用域是window,当前作用域又通过call改变了this的指向,所以最后执行结果为call指向的this。
foo.call({ id: 42 });
// id: 42

对比问题我来以注释形式描述下我的理解

你知道吗?

宣传栏