在编程的过程中有同学遇到不太清楚ES6中this
指向的问题,代码抽象如下:
function myFunction(){
var mthis = this;
setTimeout(()=>{
// this=mthis
console.log('setTimeout中的this:', this)
},100)
}
this
是什么,是全局上下文window
吗?这里需要跟ES5
区分一下。
ES6中箭头函数内部并没有 this
,this
会作为变量一直向上级词法作用域查找,直至找到为止。
先看一下几个相关的知识
函数的调用
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”。这里讨论的是非严格模式。
es5
中setTimeout
的延迟执行函数中的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
,以下三个变量在箭头函数之中也是不存在的,指向外层函数的对应变量:arguments
、super
、new.target
。
参考
https://www.w3school.com.cn/js/js_function_call.asp JavaScript 函数 Call
标签:myFunction,ES6,函数,对象,call,setTimeout,id From: https://blog.51cto.com/u_15747188/5870405