JavaScript的this详解

本文深入解析JavaScript中this关键字的动态绑定机制,包括执行上下文、方法调用、使用new构造函数、apply和call方法等情况下的行为变化。通过具体实例阐述了如何在不同场景下正确理解和使用this,以避免常见的使用陷阱。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原创声明:本文除了标明引用的内容外,都为本人原创,请尊重本人的知识产权,不能用于商业用途。欢迎转载,转载请在文章开头处插入以下内容:

本文转载自"狂龙ing”的Blog,地址为“http://blog.youkuaiyun.com/kuanglong2016/article/details/17395955"

背景知识

很多人初次在JavaScript中使用this时,会感到迷惑,特别是学习过Java/Python语言的人。JavaScript的this与Java中的this以及Python的self作用很类似,但是又有区别,所以很容易造成使用上的的困惑。例如:
function someFunc() {
	var self = this;//save this in a local variable self
	something.on("click", function() {
		console.log(self);
	});
};
很多地方都可以看到类似以上的代码var self = this,看完本问你就明白为什么要这么做了。

概念和原理

要了解this就必须先了解JavaScript中“执行上下文(execution context)”的概念。JavaScript在运行过程中会跟踪和保存多个上下文的栈,当代码运行到一个对象内部时,就把该对象的上下文压栈(实际上,上下文也是一个对象,压栈就是把该上下文对象的“指针”压栈),并执行对象内部的代码,最近进栈的上下文就称为”执行上下文“(参考JavaScript: The Good Parts)。JavaScript执行过程中,this关键字会动态绑定到执行上下文上。
有三种情况可以导致执行上下文的切换(参考Understanding the "this" keyword in JavaScript):
1. 方法调用(method invocation):作为对象属性的函数(function)一般被称为方法(method)
var counter = {
  val: 0,
  increment: function () {
    this.val += 1;
  }
};
counter.increment();
console.log(counter.val); // 1
counter['increment']();
console.log(counter.val); // 2
此时this被绑定到函数所在对象。如果作为普通函数,而不是方法来调用,如下:
var inc = counter.increment;
inc();
console.log(counter.val); // 2
console.log(val); // NaN 
这里inc被赋值为counter的方法,inc实际上是window.inc。因此当调用inc时,this实际上指向的是window。当程序执行到this.val += 1时,执行的代码实际上等价于window.val += 1,但是window.val 是undefined,而undefined + 1 会返回NaN,所以最后打印出NaN。

2. 使用new调用构造函数:
function F (v) {
  this.val = v;
}
var f = new F(“Woohoo!”);
console.log(f.val); // Woohoo!
console.log(val); // ReferenceError
当使用new来调用构造函数时,this会动态绑定到新生成的对象上。但是如果直接调用该构造函数的话,它跟其他任何普通函数没有任何区别,如下:
var f = F(“Oops!”);
console.log(f.val); // undefined
console.log(val); // Oops!
此时构造方法作为普通函数来调用,没有生成新的对象,this不变,还是绑定到global对象window上。

3. 使用call或apply:JavaScript中有两个特殊的函数可以手动绑定函数执行的上下文,call和apply,他们会绑定this到第一个参数上。
var add = function (x, y) {
      this.val = x + y;
    },
    obj = {
      val: 0
    };
add.apply(obj, [2, 8]);
console.log(obj.val); // 10
call和apply的作用一样,唯一的区别就是提供参数的方式不一样,apply使用数组的方式,call则逐个地列出参数
add.call(obj, 2, 8);
console.log(obj.val); // 10

4. 另注:如果是使用eval函数时,规则则会更加复杂,因为我一般不使用eval也不推荐其他人使用eval,所以就不多做介绍。

功能作用:

常见情况:
1.  对象中的匿名函数:
var myObj = {
    show: function(){
        var help = function(){
            console.log("'this' in anonymous is %o", this);
        }
        help();
    }
};
myObj.show();//'this' in anonymous is Window
因为匿名函数不是myObj的属性,而是Window的属性。因此如果要在匿名函数中得到myObj的引用,则需要临时保存this,如下:
var myObj = {
    show: function(){
        var self = this;//save this to a local variable self
        var help = function(){
            console.log("'this' in anonymous is %o", self);
        }
        help();
    }
};
myObj.show();//'this' in anonymous is Object { show=function()}

2. 事件处理函数:(参考The this keyword
如果使用如下形式:
element.onclick = doSomething;
此时,doSomething中的this可以动态的绑定到element,因为onclick是element的方法。
如果使用:
<element onclick="doSomething()">
则doSomething是作为一个普通函数直接调用,而不是element的方法,所以doSomething中的this会被绑定到Window。
实际效果如下:
function onclick(){
	doSomething();
}

总结

1. 默认:this = 全局对象
2. 通过对象属性的方式调用方法:this = 该对象
3. 使用new调用构造函数:this = 新对象
4. 使用apply或call:this = apply或call的第一个参数

主要参考文献



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值