在 学习JavaScript 的过程中,this 这个关键字常常困扰着初学者甚至一些进阶的开发者;尤其对一些学过面向对象编程的同学来说,JS中的this含义会很不一样。下面就来说说怎么理解Javascript中的this关键字。
Javascript中函数的调用方式
首先我们来看看javascript中函数的调用方式:
function func(argu[0], argu[1]){
//define a function func
}
var obj = { //define a object obj
func: function(argu[0], argu[1]){
//define a method func in object
}
}
func(argu[0], argu[1])
obj.func(argu[0], argu[1]) //call the function func
上面的调用方式是我们经常使用的形式,称为语法糖。上述形式可以等价转换为function.call的形式:
func.call(undeined, argu[0], argu[1])
//函数调用call形式,等价于func(argu[0], argu[1])
obj.func.call(obj, argu[0], argu[1])
//对象方法call形式,等价于obj.func(argu[0], argu[1])
这样,JS中的this就很好理解了。
this 是 JavaScript 中的一个关键字,当一个函数被调用时,除了传入函数的显式参数以外,名为 this 的隐式参数也被传入了函数。this 参数指向了一个自动生成的内部对象,这个内部对象被称为函数上下文(context)。
this的指向时动态的,有办法事先确定到底指向哪个对象,只有执行函数时才能确定。
与其他面向对象的语言不同的是, JavaScript 中的 this 依赖于函数的调用方式。所以,想要明白 this 的指向问题,还必须先研究函数在 JavaScript 中是如何被调用的。
在全局上下文中
在全局运行上下文中(在任何函数体外部),this指代全局对象,无论是否在严格模式下('use strict')
//在浏览器中,全局对象为window
console.log(this === window) //true
this.name = 'frank'
console.log(window.name) //print frank
在函数上下文中
取决于函数如何调用:
1. 作为函数进行调用
在非严格模式下,不在调用时设置this值的时候(使用语法糖),this的值会默认设置为全局对象:
function test(){
console.log(this)
}
test() //print window
而在严格模式下,this将保持他进入执行环境时的值,不设置为undefined:
function test(){
"use strict"; //使用严格模式
console.log(this)
}
test() //print undefined
2. 作为方法进行调用
当一个函数被一个对象的属性引用时,可以通过对象调用这个函数:
var obj = {
func: function() {
console.log(this)
}
}
obj.func() //print obj
函数 func 的调用对象为 obj,所以函数上下文便是 obj。由此可见,将函数作为对象的一个方法进行调用时,该对象就是函数上下文,并且在函数内部可以用 this 来访问这个对象。
但是,当a对象的方法被赋予b对象,该方法就变成了普通函数,其中的this就从指向a对象变成了指向b对象。
var obj = {
func: function() {
console.log(this)
}
}
var temp = obj.func
temp() //print window(global)
3. 使用 apply() 和 call() 方法进行调用
JavaScript 的每个函数都有 apply() 和 call() 函数,可以利用任何一个函数都可以显式指定任何一个对象作为其函数上下文。
通过 call() 方法来调用函数,我们要给 call() 传入一个this作为函数上下文对象,另外还要传入函数原本的参数。apply() 方法的使用方式类似,唯一不同的是call()方法传入的所有参数,而apply()是传入的参数数组。
我们使用call为例:
function func() {
let result = 0;
for(let i = 0; i < arguments.length; i++) {
result += arguments[i];
}
this.result = result;
}
var obj = {}
func.call(obj, 1, 2, 3)
obj.result === 6 //the result is 6
将函数的上下文定义为 obj,并且传入 1、2、3 三个参数,func.call(obj, 1, 2, 3)
。由于this指向了obj,在执行完函数后,obj中的result属性变为6。
同样,利用call()或者apply()方法,我们可以在一个对象中调用另一个对象中的函数:
var array1= []
var array2= [] //define 2 arrays
array1.push.call(array2, 1, 2, 3) //在array1中调用array2的push方法
console.log(array1) //print []
console.log(array2) //print [1, 2, 3]
在上述例子中,定义了两个数组array1和array2,通过array1调用了array2中的push方法,最后改变了array2。
由于有call()和apply()方法,这就使得Javascript非常灵活。
4. 作为构造器进行调用
ES6中箭头函数与this
参考文章
- 前端学习指南-this 的值到底是什么?一次说清楚
- MDN中文-Javascript参考教程this
- 前端解忧杂货铺-JavaScript this 讲解