JavaScript函数的4种调用模式与this指向详解

作者:函数茶馆

时间:2026-10-28

浏览:237

本文深入解析JavaScript中函数的四种调用模式:函数调用、方法调用、构造器调用及apply调用。重点剖析不同模式下this关键字的指向差异,包括全局对象、当前对象、新创建对象及动态指定对象,并结合代码示例说明构造器返回值处理及参数传递机制,帮助开发者准确掌握函数执行上下文。

文章目录

JavaScript函数调用模式概述

在JavaScript中,函数被视为一等公民,它不仅是模块化的工具,更是一种独立的数据类型,这与C#等语言中函数仅作为模块存在的概念不同。JavaScript中的函数主要包含四种调用模式:函数调用、方法调用、构造器调用以及apply调用。这几种模式的核心区别在于关键字this的指向不同,下文将逐一解析。

本文主要涵盖以下内容:

1. 深入分析函数的四种调用模式 2. 厘清函数中this关键字的具体含义 3. 明确构造函数的对象创建流程 4. 掌握利用上下文调用函数的技巧

函数调用模式与this指向

一、函数调用模式

函数调用是最基础且直观的模式。所谓函数调用,即声明函数后直接执行。例如:

代码如下:

// 声明一个函数,并调用
function func() {
alert("Hello World");
}
func();

或者:


代码如下:

// 使用函数的Lambda表达式定义函数,然后调用
var func = function() {
alert("你好,程序员");
};
func();

上述两段代码在浏览器中执行时,均会弹出对话框显示相应文字,这便是典型的函数调用。

这种调用方式看似简单,关键在于理解函数体内的this关键字。在函数调用模式下,this指向全局对象,在浏览器环境中即为window对象。例如:

代码如下:

var func = function() {
alert(this);
};
func();

执行后,对话框将打印出[object Window]。

方法调用模式的区别

二、方法调用模式

虽然函数调用是最基本的形式,但当函数被赋值给对象的属性后,其行为和称谓便发生了变化。此时,该函数不再被称为普通函数,而是称为方法。例如:

代码如下:

// 定义一个函数
var func = function() {
alert("我是一个函数么?");
};
// 将其赋值给一个对象
var o = {};
o.fn = func; // 注意这里不要加圆括号
// 调用
o.fn();

此时,o.fn被视为方法。尽管其方法体与func完全一致,但存在细微差别。参考以下代码:


代码如下:

// 接上面的代码
alert(o.fn === func);
打印结果为true,表明两者引用相同的函数对象。但若修改函数体以观察this指向:
// 修改函数体
var func = function() {
 alert(this);
};
var o = {};
o.fn = func;
// 比较
alert(o.fn === func);
// 调用
func();
o.fn();

运行结果显示两个函数引用相同,因此比较结果为true。然而,调用方式不同导致this指向不同:func()调用时打印[object Window],而o.fn()调用时打印[object Object]。

这正是函数调用与方法调用的核心区别:在函数调用中,this专指全局对象window;而在方法调用中,this专指当前调用该方法的对象,即o.fn中的this指向对象o。

构造器调用模式详解

三、构造器调用模式

在普通函数模式下,this指向window;在对象方法模式下,this指向当前对象。此外,JavaScript允许函数作为构造器使用。只需在函数调用前添加new关键字即可,如代码:

代码如下:

// 定义一个构造函数
var Person = function() {
this.name = "程序员";
this.sayHello = function() {
alert("你好,这里是" + this.name);
    };
};
// 调用构造器,创建对象
var p = new Person();
// 使用对象
p.sayHello();

上述案例首先定义构造函数Person,随后使用new关键字创建对象p,并调用其sayHello()方法。此案例展示了构造函数的基本用法,其中this指向新创建的对象。除了基础用法,构造函数还有以下特性:

1、所有需由对象访问的属性,必须通过this进行定义;

2、函数的return语句行为被改写:若返回非对象类型(如数字、布尔值或字符串),则忽略返回值并返回this;若返回对象,则返回该对象。

构造器中的this

理解对象创建过程有助于明确this的含义。如下代码:

代码如下:

var Person = function() {
this.name = "程序员";
};
var p = new Person();

首先定义函数Person,接下来分析执行过程:

1、程序执行到该语句时,暂不执行函数体,解释器此时不关注函数具体内容。

2、执行new关键字,解释器分配内存并创建对象引用,将该引用传递给函数。

3、紧接着执行函数体,将传入的对象引用赋给this。因此,在构造方法中,this即代表刚通过new创建的新对象。

4、随后通过this添加成员,即为新对象添加属性或方法。

5、函数执行完毕,返回this,并将该引用赋值给左侧变量。

综上分析,构造函数中的this始终指向当前新创建的对象。

构造器中的return

在构造函数中,return的行为发生变化:若返回值为对象,则保留原意,返回该对象;若返回非对象(如数字、布尔值或字符串),则忽略返回值,返回this。若无return语句,同样返回this。参考以下代码:

代码如下:

// 返回一个对象的 return
var ctr = function() {
this.name = "赵晓虎";
return {
name:"牛亮亮"
    };
};
// 创建对象
var p = new ctr();
// 访问name属性
alert(p.name);

执行结果打印“牛亮亮”。因为构造方法返回的是对象,所以return语句生效,返回其后的对象。再看下面代码:


代码如下:

// 定义返回非对象数据的构造器
var ctr = function() {
this.name = "赵晓虎";
return "牛亮亮";
};
// 创建对象
var p = new ctr();
// 使用
alert(p);
alert(p.name);

运行结果先弹窗打印[object Object],随后打印“赵晓虎”。因为return的是字符串(基本类型),该return语句无效,最终返回this对象。因此第一个打印[object Object],第二个打印属性值而非undefined。

apply与call调用模式

四、apply调用模式

除上述三种模式外,函数作为对象还具备apply和call方法,这构成了第四种调用模式,即apply模式。

首先介绍apply模式,它既可按函数方式使用,也可按方法方式使用,具有较高灵活性。语法格式为:函数名.apply(对象, 参数数组);

语法看似抽象,通过案例说明更为清晰:

1、新建两个js文件,分别为”js1.js”与”js2.js”;

2、添加代码

代码如下:

// js1.js 文件中
var func1 = function() {
this.name = "程序员";
};
func1.apply(null);
alert(name);
// js2.js 文件
var func2 = function() {
 this.name = "程序员";
};
var o = {};
func2.apply(o);
alert(o.name);

3、分别运行两段代码,可见第一个文件中name属性被加载到全局对象window中;第二个文件中name属性则存在于传入的对象o中。前者相当于函数调用,后者相当于方法调用。

此处参数需以数组形式传递,例如代码:

代码如下:

// 一个数组的例子
var arr1 = [1,2,3,[4,5],[6,7,8]];
// 将其展开
var arr2 = arr1.concat.apply([], arr1);
接下来介绍call模式,其与apply模式的最大区别在于参数传递方式:call不需要数组包裹,直接传递参数。参考以下代码:
// 定义方法
var func = function(name, age, sex) {
 this.name = name;
 this.age = age;
 this.sex = sex;
};
// 创建对象
var o = {};
// 给对象添加成员
// apply 模式
var p1 = func.apply(o, ["赵晓虎", 19, "男"]);
// call 模式
var p2 = func.call(o, "赵晓虎", 19, "男");

上述代码中,apply模式与call模式执行结果一致。

实际上,利用apply和call模式可以灵活控制this的指向,这在JavaScript设计模式中应用广泛。简要总结:JavaScript函数调用有四种模式,分别为函数式、方法式、构造器式和apply式。各模式中this的含义如下:函数式中this为全局对象window,方法式中this为当前对象,构造器式中this为新创建的对象,apply式中this可动态指定。若在apply模式中使用null,则表现为函数模式;若传入对象,则表现为方法模式。

综合应用示例

五、综合例子

最后通过一个案例进行总结。案例说明:有一个div元素,id为dv,鼠标移入时高度变为原来的2倍,鼠标移出时恢复原状。直接展示JS代码:

代码如下:

var dv = document.getElementById("dv");
var height = parseInt(dv.style.height || dv.offsetHeight);
var intervalId;
dv.onmouseover = function() {
// 停止已经在执行的动画
clearInterval(intervalId);
// 得到目标高度
var toHeight = height * 2;
// 获得当前对象
var that = this;
// 开启计时器,缓慢变化
intervalId = setInterval(function() {
// 得到现在的高度
var height = parseInt(dv.style.height || dv.offsetHeight);
// 记录每次需要变化的步长
var h = Math.ceil(Math.abs(height - toHeight) / 10);
// 判断变化,如果步长为0就停止计时器
if( h > 0 ) {
// 这里为什么要用that呢?思考一下吧
that.style.height = (height + h) + "px";
} else {
clearInterval(intervalId);
        }
}, 20);
};
dv.onmouseout = function() {
// 原理和之前一样
clearInterval(intervalId);
var toHeight = height;
var that = this;
intervalId = setInterval(function() {
var height = parseInt(dv.style.height || dv.offsetHeight);
var h = Math.ceil(Math.abs(height - toHeight) / 10);
if( h > 0 ) {
that.style.height = (height - h) + "px";
} else {
clearInterval(intervalId);
        }
}, 20);
};

实用工具推荐

电子包浆

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

使用 ›
图片压缩

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

使用 ›
相关文章