JavaScript 面向对象之二 —— 函数上下文(this的指向)

本系列文章根据《爱前端邵山欢老师深入浅出的js面向对象》视频整理归纳

函数上下文

在 JavaScript 中,函数的上下文是有规律可循的,基本可以分为以下几项:

规律一:函数用圆括号调用,函数上下文是 window 对象。

如下,函数 function fun(){} 的上下文是什么,即 this 的指向是谁, 不是根据它如何定义,而是根据如何调用得出的,在这里fun() 是通过函数名加圆括号直接调用的,所以此时函数的上下文,即 this 指向就是 window 对象。

function fun(){
    var a = 1;
    console.log(this.a);
}
var a = 2;
fun();    //  输出为 2

而我们知道,所有的全局变量都是 window 对象的属性(函数里面的局部变量,不是 window 的属性,不是任何东西的属性,就是一个变量。),所以在这里最后输出 2。

规律二:函数如果作为一个对象的方法,对象使用点方法进行调用,那么函数的上下文就是这个对象。

如下,定义一个函数 fun,并将其作为新建对象 obj 的一个属性 c,通过 对象.函数() 的方法进行调用:

function fun(){
    var a = 1;
    console.log(this.a);
}
var obj = {
    'a' = 2,
    'b' = 3,
    'c' = fun
};
obj.c();    //  输出为 2

此时函数的上下文为 obj 对象,即函数里的 this 指向这个对象 obj,所以输出为 2。

规律三:函数是事件处理函数,那么函数的上下文就是触发这个事件的对象。

如下,我们创建三个 div,给其设定背景色,定义一个函数 fun,将其作为三个 DOM 元素的事件处理函数,使点击不同的 div 时,相应 div 背景色发生变化。

HTML 部分

<div id="box1"></div>
<div id="box2"></div>
<div id="box3"></div>

CSS 部分

div {
    width: 50px;
    height: 50px;
    background-color: red;
    margin: 10px 0;
}

JavaScript 部分

function fun(){
    this.style.backgroundColor = 'blue';
}
document.getElementById('box1').onclick = fun;
document.getElementById('box2').onclick = fun;
document.getElementById('box3').onclick = fun;

在这里函数不会执行,直到我们点击了某一个 div 标签,此时点击谁,函数上下文就是谁,this 就指向谁。

规律四:函数被定时器调用时,上下文是 window 对象。

如下,定义函数 fun,在定时器 setInterval 中调用:

funcyion fun(){
    console.log(this.a);
}
var a = 1;
setInterval(fun,1000);  // 每隔一秒输出一次 1

因为函数被定时器调用,上下文是 window 对象,所以输出为 1。

我们经常会因为对于被定时器调用的函数 this 指向理解有误,而犯如下的错误:

点击 div,使之2秒后变为蓝色:

var box = getElementById('box');
box.onclick = function(){
    setTimeout(function(){
        this.style.backgroundColor = 'blue';
    },2000);
}

上述代码在点击 div 2秒后会报错,因为我们理所当然的认为 this 指向触发事件处理函数的对象,但其实在这里,函数是在定时器内调用的,所以函数的上下文是 window 对象,即这里的 this 指向 window 对象,而 window 对象没有背景颜色这个属性,所以会报错。

而我们要实现最初想达成的效果,可以通过在定时器外面的事件处理函数中,把 this 存为局部变量 that 来备份上下文,因为在这里 this 就是 box 这个元素。

var box = document.getElementById('box');
box.onclick = function (){
    var that = this;
    setTimeout(function(){
        that.style.backgroundColor = 'blue';
    },2000)
}

规律五:数组中存放的函数,被数组索引调用,函数上下文就是这个数组。

如下,定义一个函数 fun,使之成为数组的一项:

function fun(){
    console.log(this.length);
}
var arr = [fun,1,2];
arr[0]();   // 3

在这里函数是从数组中索引并加圆括号进行调用的,所以最终调用者可以认为是这个数组,所以上下文就是这个数组,即 this 的指向也是这个数组。


综合练习:

function fun1(c,d,e,f,g){
    console.log(this.length);
}
function fun2(a,b){
    arguments[0](4,5,6,7,8);
}
fun2(fun1,1,2,3);

输出为 4

解析:

涉及知识点一: arguments.callee

在函数内部,我们无法通过 this 得到函数自身,必须使用arguments.callee。

function fun(){
    console.log(arguments.callee === fun); 
}
fun();  //  输出 true

涉及知识点二:函数的长度是什么

函数的长度是形参列表的长度(即函数定义时写在 fun 圆括号内的字母个数),与实参长度无关(即函数调用时圆括号内的参数个数),
arguments.callee.length = 形参个数
arguments.length = 实参个数

function fun(a,b,c,d,e){  // 此处的 a,b,c,d,e 是形参
    console.log(arguments.callee.length);  //  5
    console.log(arguments.length);  //  6
}
fun(1,2,3,4,5,6);  // 输出 5  6
// 此处的 1,2,3,4,5,6 为实参

此时再回头看我们的练习题, fun1 作为 fun2 的实参进行调用,而 fun2 中的 arguments[0] 就是 fun2,所以函数的最终调用,是 arguments 对象进行方括号索引得到 fun1 ,然后加圆括号执行调用,而 arguments 是一个对象,可以参照我们总结的规律五得出,fun1 函数中的 this 指向 arguments 对象,那么最终我们所要输出的就是 arguments.length,它的值则为fun2(fun1,1,2,3)的实参个数,所以最终输出为 4

如果我们将 fun1 函数变成:

function fun1(){
    console.log(this.callee.length);
}

那么结果将输出 arguments.callee.length,即 fun2 的形参个数 2

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值