深入解析JavaScript中this指针的四种调用模式
本文基于《JavaScript The Good Parts》深入解析JavaScript中this指针的本质。详细阐述了方法调用、函数调用、构造函数调用及Apply调用这四种模式下的this指向规则,并通过代码示例演示了如何解决函数调用中的this丢失问题以及利用new和apply实现对象继承,帮助开发者避开常见陷阱。
JavaScript this指针概述
过去对this的理解往往停留在表面,知道如何使用却未深究其本质。此次借助《JavaScript The Good Parts》一书,对这一概念进行了深入的剖析(所有调试过程均可在浏览器控制台F12中观察)。
接下来,我们将详细探讨this指针的具体行为。
在函数声明时,除了定义的形参(parameters)外,每个函数内部还隐式包含两个额外参数:this和arguments。其中arguments代表实际接收到的参数,是一个类数组对象。此处对arguments仅作简要提及,核心重点在于解析this指针的工作机制。
this指针的四种调用模式
在面向对象编程中,this的值取决于函数的调用模式。JavaScript中主要存在四种调用模式:方法调用模式、函数调用模式、构造函数调用模式以及Apply调用模式。
方法调用模式
方法调用模式
当函数作为对象的属性被定义时,我们称之为对象的方法。在调用该方法时,this关键字会自动指向该方法所属的对象。
代码如下:
<script type="text/javascript">
var people = {
name : "Yika",
sayName : function(){
console.log(this.name); //"Yika"
//this已经绑定在了people对象上了
}
}
people.sayName();
</script>
如上例所示,this指向了sayName方法所属的对象,这种通过this获取所属对象上下文的方式被称为公共方法(public method)。
函数调用模式
函数调用模式
当一个函数并非作为对象的方法被调用时,它便是以函数形式被调用。
在此模式下,this会指向全局对象window。即使该函数是在另一个外部函数的内部被调用,this依然指向window,请看示例。
代码如下:
<script type="text/javascript">
var name = "window-Yika";
var people = {
name : "people-Yika",
student : function(){
console.log(this); //这里的this绑定的是对象people
function sayName(){
var name = "sayName-Yika";
console.log(this.name); //window-Yika
//即使sayName函数本身和它所在的people对象都有name值,但是this是指向window的
};
sayName();
}
}
people.student();
</script>
通过上述示例,我们大致了解了如何解决JavaScript中这一看似“设计缺陷”的问题。
解决方法是在student函数内部(即第6行附近),将当前的this缓存到一个变量中,然后将该变量传递给内部的sayName函数即可解决。
代码如下:
var people = {
name : "people-Yika",
student : function(){
var self = this; //将this缓存起来
function sayName(){
var name = "sayName-Yika";
console.log(self.name); //"people-Yika",此时的self指向的是people对象
};
sayName();
}
}
构造函数调用模式
构造函数调用模式
提到JavaScript中的构造函数,通常会想到“函数名首字母大写”以及“使用new操作符调用”。函数名大写是为了规范命名,但为何必须使用new?如果函数前带有new关键字,JavaScript会在后台创建一个指向该函数prototype的新对象,并将this绑定到这个新对象上。JavaScript是基于原型继承的语言,若对prototype不熟悉可查阅相关资料,此处重点讨论this的绑定机制。
我们先观察构造函数的一般形态。
代码如下:
<script type="text/javascript">
function People(name){
this.name = name; //这里的this,用new调用后便指向了新对象Yika
this.sayName = function(){
console.log(this.name); //输出
}
}
var Yika = new People("Yika");
Yika.sayName(); //输出“Yika" ,因为Yika是通过new调用得来的,this都绑定在了Yika对象上。
</script>
乍看之下可能令人困惑:为何之前函数内的this指向window,而此处无需缓存即可指向People函数?
不必担心,前文提到函数通过new调用时会在后台执行一些操作,我们来看看具体做了什么。
代码如下:
<script type="text/javascript">
function People(name){
var that = {}; //坏事一:自己生成一个对象
that.name = name;
that.sayName = function(){
console.log(that.name);
};
return that; //坏事二,自己会改变return的行为,return刚生成的对象
}
var Yika = People("Yika"); //这里可以省略new,模仿调用new操作符
Yika.sayName(); //和刚才一样输出"Yika"
</script>
这样看来便清晰了:new不仅会生成一个新对象,还会自动返回该对象,因此this自然指向了这个新对象。
务必使用new来调用构造函数,否则出错时不会有警告,因此保持大写命名约定十分必要。
Apply调用模式
Apply调用模式
apply方法允许我们将参数数组传递给被调用函数,同时允许我们指定this的值。
function.apply(this绑定的值, arguments参数数组)
apply的内容丰富,此处仅举一例以助理解:
代码如下:
<script type="text/javascript">
function People(name){
this.name = name;
this.sayName = function(){
console.log(this.name); //sayName这个方法是属于People构造函数的
}
}
function Student(name){
People.apply(this, arguments);//借用构造函数的集成方式,就是在Student构造函数里,通过apply调用People构造函数,并改变People的this值
//这样每次创建Student实例时,都会调用People构造函数
}
var student = new Student("Yika");
student.sayName(); //输出“Yika”
</script>
我们可以通过apply轻松修改函数的this绑定对象,与apply相似的方法call也具有相同效果,有兴趣者可自行搜索学习。
至此,关于改变this的四种调用模式讲解完毕。其中方法调用模式和构造函数调用模式更为常用且重要,而函数调用模式则需要我们警惕其中的陷阱。
如有错误请及时反馈,我将尽快纠正,以免误导他人,谢谢!
D3.js 比例尺与坐标轴的配置详解
2026-11-05 16:54:46
JavaScript怎么遍历对象的Symbol键和不可枚举属性
2026-11-05 13:13:39
封装一个健壮的JS字符串判空工具函数
2026-11-05 12:16:14
JavaScript合并数组的三种常用方法:concat、扩展运算符与push
2026-11-05 11:22:29
JavaScript立即执行函数(IIFE)是什么及基本语法
2026-11-05 10:51:19
