乐趣区

关于javascript:ES6中setTimeout函数的this

ES6 中 setTimeout 函数的 this

在编程的过程中有同学遇到不太分明 ES6 中 this 指向的问题,代码形象如下:

function myFunction(){
  var mthis = this;
    setTimeout(()=>{
        // this=mthis
        console.log('setTimeout 中的 this:', this)
      },100)
}

this是什么,是全局上下文 window 吗?这里须要跟 ES5 辨别一下。

ES6 中箭头函数外部并没有 thisthis 会作为变量始终向下级词法作用域查找,直至找到为止。

先看一下几个相干的常识

函数的调用

function myFunction(a, b){return a * b;}
myFunction(2, 3)

输入后果的是6

以上 myFunction 函数不属于任何对象。然而在 JavaScript 中,始终存在一种默认的全局对象。

在 HTML 中,默认全局对象是 HTML 页面自身,所有下面的函数“属于”HTML 页面。

在浏览器中,这个页面对象就是浏览器窗口。下面的函数主动成为一个窗口函数。

myFunction()window.myFunction() 是同一个函数。

这是调用函数的常见办法,但并不是一个好习惯。

全局变量、办法或函数很容易在全局对象中产生命名抵触和破绽。

this 关键词

JavaScript 中,被称为 this 的事物,指的是“领有”以后代码的对象。

this 的值,在函数中应用时,是“领有”该函数的对象。

请留神 this 并不是变量。它属于关键词。您无奈扭转 this 的值。

全局对象

作为函数调用函数

当不带拥有者对象调用对象时,this 的值成为全局对象。

在 web 浏览器中,全局对象就是浏览器对象。

本例以 this 的值返回这个 window 对象:

示例

var x = myFunction(); // x 将成为 window 对象
function myFunction() {return this;}

调用一个函数作为一个全局函数,会导致 this 的值成为全局对象。

作为变量来应用 window 对象很容易使程序解体。

作为办法来调用函数

JavaScript 中,您能够把函数定义为对象办法。

上面的例子创立了一个对象(myObject),带有两个属性(firstName 和 lastName),以及一个办法(fullName):

示例

var myObject = {
    firstName:"Bill",
    lastName: "Gates",
    fullName: function () {return this.firstName + " " + this.lastName;}
}
myObject.fullName(); // 将返回 "Bill Gates"

fullName 办法是一个函数。该函数属于对象。myObject 是函数的拥有者。

被称为 this 的事物,是“领有”这段 JavaScript 代码的对象。在此例中,this 的值是 myObject

测试一下!批改这个 fullName 办法来返回 this 的值:

示例

var myObject = {
    firstName:"Bill",
    lastName: "Gates",
    fullName: function () {return this;}
}
myObject.fullName(); // 将返回 [object Object](拥有者对象)

以对象办法来调用函数,this 的值指向对象自身。

通过结构器来调用函数

如果函数调用的后面是 new 关键字,那么这是一个结构函数调用。

它看起来像你创立一个新的函数,但因为 JavaScript 函数是对象,你实际上创立一个新对象:

示例

// 这是函数结构器:function myFunction(arg1, arg2) {
    this.firstName = arg1;
    this.lastName  = arg2;
}

// 创立了一个新对象:var x = new myFunction("Bill", "Gates");
x.firstName; // 会返回 "Bill"

结构器调用会创立新对象。新对象会从其结构器继承属性和办法。

结构器内的 this 会指向调用函数时创立的新对象。

setTimeout

(1)ES5

《javascript 高级程序设计》中说:“超时调用的代码都是在全局作用域中执行的,因而函数中的 this 的值在非严格模式下指向 window 对象,在严格模式下是 undefined”。这里探讨的是非严格模式。

es5setTimeout 的提早执行函数中的 this,永远指向window

举例来说:

function myFunction(){
    var id=1024;
    console.log('myFunction 中的 this:', this, this.id)
      setTimeout(function(){
        // 这里须要留神 id 和 this.id 是不一样的 this=window
        console.log('setTimeout 中的 this:', this, this.id, id)
    },100)
}
var myobj={id:9528}
var id=9527;
myFunction(myobj)
myFunction.call({id:1987})

输入后果:

myFunction(myobj)执行后果

myFunction 中的 this: Window 9527

setTimeout 中的 this: Window 9527 1024

myFunction.call({id:1987})执行后果

myFunction 中的 this: Object {id: 1987} 1987

setTimeout 中的 this: Window 9527 1024

补充阐明

一般而言 this 总是指向调用该办法的对象,然而应用 call()apply()办法时,就会扭转 this 的指向,this的指向会产生转移。

call.(object, arg1, arg2 ...)

apply()call() 差不多,只不过 apply 第二个参数必须传入的是一个数组,而call 第二个参数能够是任意类型。

obj1.methodName.call(obj2, argument1, argument2)

如上,call的作用就是把 obj1 的办法放到 obj2 上应用,js 中所有皆对象, 函数是对象, 函数也能够调用办法,前面的 argument1.. 这些做为参数传入。

A.call(B, x, y):就是把 A 的函数放到 B 中运行,x 和 y 是 A 办法的参数。

call 来实现继承,用 this 能够继承 myfunc1 中的所有办法和属性。

(2)ES6

ES6 中,setTimeout外面,如果执行了一个箭头函数,那么这个函数的 this 指向的是外层调用者。

function myFunction(){
    var id=1024;
     console.log('myFunction 中的 this:', this, this.id)
    setTimeout(()=>{
        // 这里须要留神 id 和 this.id 是不一样的 this=myFunction 的调用者
        console.log('setTimeout 中的 this:', this, this.id, id)
      },100)
}
var myobj={id:9528}
var id=9527;
myFunction(myobj)
myFunction.call({id:1987})

输入后果:

myFunction(myobj)执行后果

myFunction 中的 this: Window 9527

setTimeout 中的 this: Window 9527 1024

myFunction.call({id:1987})执行后果

myFunction 中的 this: Object {id: 1987} 1987

setTimeout 中的 this: Object {id: 1987} 1987 1024

ES6中箭头函数 this 会作为变量始终向下级词法作用域查找,直至找到为止。于是这里箭头函数外面的this, 向上找就是myFunction 函数的 this, 在这里就是{id:1987} 这个对象。

上面是 Babel 转箭头函数产生的 ES5 代码,就能分明地阐明 this 的指向。

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

// ES5
function foo() {
  var _this = this;

  setTimeout(function () {console.log('id:', _this.id);
  }, 100);
}

下面代码中,转换后的 ES5 版本分明地阐明了,箭头函数外面基本没有本人的this,而是援用外层的this

除了this,以下三个变量在箭头函数之中也是不存在的,指向外层函数的对应变量:argumentssupernew.target

参考

https://www.w3school.com.cn/js/js_function_call.asp JavaScript 函数 Call

https://es6.ruanyifeng.com/?search=this&x=0&y=0#docs/function#%E4%BD%BF%E7%94%A8%E6%B3%A8%E6%84%8F%E7%82%B9

退出移动版