this关键字在JavaScript中扮演了至关重要的角色,每次它的出现都伴随着它的指向问题,这也是很多初学者容易出错的地方。
不过,这篇文章将会带你一次性搞定this指向的问题,望能给大家提供帮助!
一、谁最终调用函数,this就指向谁!
这句话是需要牢记的口诀,将this的指向问题转换为分析确定函数最终调用者的问题,以下是对这句话的解释和补充:
① this指向谁,不应该考虑函数在哪里里声明的,而是应该考虑函数在哪调用;
② this指向的永远是对象,而不可能是函数。
③ this指向的对象叫做函数的上下文(context),也叫函数的调用者。
那么问题又来了,函数的最终调用者如何确定呢?我们先来看一个面试题:
阅读如下代码,输入的结果应该是?
var length = 10
function fn() {
alert(this.length)
}
var obj = {
length: 5,
method: function(fn) {
fn() // ?
arguments[0]() // ?
}
}
obj.method(fn);
试着确定一下,题干中函数的最终调用者是谁?有了答案的话我们继续往下看:
★★★ 二、this指向的规律 :(跟函数的调用方式息息相关!)
① 通过 【 函数名() 】 调用的,this永远指向window;
② 通过 【 对象.方法 】调用的,this永远指向对象。obj.func();
③ 函数作为数组中的 一个元素,通过数组下标调用的 【 arr[i]() 】,this指向数组arr。
④ 函数作为window内置函数的回调函数使用,this指向window;
setTimeout() setInterval()等
⑤ 函数作为构造函数,使用new关键字调用,this指向新new出的对象。
针对以上的规律我们分别举例说明:
① 通过 【 函数名() 】 调用的,this永远指向window;
function func () {
console.log(this);
}
func();//函数名+()调用,this指向window
② 通过 【 对象.方法 】调用的,this永远指向对象。
var obj = {
name:"wq";
func:func;
}
obj.func();//通过对象.方法调用的,this永远指向对象。
Window.onclick = function () {
document.getElementById("zz").onclick = function () {
func();//函数名+()调用,this指向window
}
document.getElementById("zz").onclick = func;//广义对象 通过对象.方法调用的,this永远指向对象
}
③ 函数作为数组中的 一个元素,通过数组下标调用的 【 arr[i]() 】,this指向数组arr。
var arr [1,2,3,func,4,5,6]
arr[3]();//函数作为数组中的 一个元素,通过数组下标调用的 【 arr[i]() 】,this指向数组arr
④ 函数作为window内置函数的回调函数使用,this指向widow;
setTimeout(func,1000);//函数作为window内置函数的回调函数使用,this指向window;
⑤ 函数作为构造函数,使用new关键字调用,this指向新new出的对象。
var obj1 = new func()//函数作为构造函数,使用new关键字调用,this指向新new出的对象obj1。
var obj1 ={
name:"obj1",
arr:[func,1,2,3,4]
}
obj1.arr[0]()//最终的调用者是数组。
setTimeout(obj1.arr[0],2000);//,作为内置函数进行调用,故this指向window;相当于setTimeout(func,2000);
在结合了相关实例对这几句话进行理解之后,我们再回过头来看一下上面的那道面试题:
阅读如下代码,输出的结果应该是?
var length = 10
function fn() {
alert(this.length)
}
var obj = {
length: 5,
method: function(fn) {
fn() // ? 10
arguments[0]() // ? 1
}
}
obj.method(fn); 答案:fn() // 10 通过函数名()调用,this指向window,即全局变量length。
arguments[0]() // 1 函数作为数组中的 一个元素,通过数组下标调用的 【 arr[i]() 】,注意此时的数组是arguments,传入实参fn.
tips:
在JavaScript中,arguments对象是比较特别的一个对象,实际上是当前函数的一个内置属性。arguments非常类似Array,但实际上又不是一个Array实例。
arguments对象的长度是由实参个数而不是形参个数决定的。
最后我们再通过几道面试题来巩固下:
var fullname = 'John Doe';
var obj = {
fullname: 'Colin Ihrig',
prop: {
fullname: 'Aurelio De Rosa',
getFullname: function() {
return this.fullname;
}
}
};
console.log(obj.prop.getFullname());
// 函数的最终调用者 obj.prop var test = obj.prop.getFullname;
console.log(test());
// 函数的最终调用者 test() this-> window obj.func = obj.prop.getFullname;
console.log(obj.func());
// 函数最终调用者是obj var arr = [obj.prop.getFullname,1,2];
arr.fullname = "JiangHao";
console.log(arr[0]());
// 函数最终调用者数组
如有错误,欢迎大家指正交流!谢谢!