深入解析JavaScript中this指针的四种调用模式

作者:异步漫步

时间:2026-10-28

浏览:460

本文基于《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的四种调用模式讲解完毕。其中方法调用模式和构造函数调用模式更为常用且重要,而函数调用模式则需要我们警惕其中的陷阱。

如有错误请及时反馈,我将尽快纠正,以免误导他人,谢谢!

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章