详解JS中的this、apply、call、bind(经典面试题)
发布时间 - 2026-01-11 03:19:00 点击率:次这又是一个面试经典问题~/(ㄒoㄒ)/~~也是 ES5中众多坑中的一个,在 ES6 中可能会极大避免 this 产生的错误,但是为了一些老代码的维护,最好还是了解一下 this 的指向和 call、apply、bind 三者的区别。

this 的指向
在 ES5 中,其实 this 的指向,始终坚持一个原理:this 永远指向最后调用它的那个对象,来,跟着我朗读三遍:this 永远指向最后调用它的那个对象,this 永远指向最后调用它的那个对象,this 永远指向最后调用它的那个对象。记住这句话,this 你已经了解一半了。
下面我们来看一个最简单的例子:
例 1:
var name = "windowsName";
function a() {
var name = "Cherry";
console.log(this.name); // windowsName
console.log("inner:" + this); // inner: Window
}
a();
console.log("outer:" + this) // outer: Window
这个相信大家都知道为什么 log 的是 windowsName,因为根据刚刚的那句话“this 永远指向最后调用它的那个对象”,我们看最后调用 a 的地方 a();,前面没有调用的对象那么就是全局对象 window,这就相当于是 window.a();注意,这里我们没有使用严格模式,如果使用严格模式的话,全局对象就是 undefined,那么就会报错 Uncaught TypeError: Cannot read property 'name' of undefined。
再看下这个例子:
例 2:
var name = "windowsName";
var a = {
name: "Cherry",
fn : function () {
console.log(this.name); // Cherry
}
}
a.fn();
在这个例子中,函数 fn 是对象 a 调用的,所以打印的值就是 a 中的 name 的值。是不是有一点清晰了呢~
我们做一个小小的改动:
例 3:
var name = "windowsName";
var a = {
name: "Cherry",
fn : function () {
console.log(this.name); // Cherry
}
}
window.a.fn();
这里打印 Cherry 的原因也是因为刚刚那句话“this 永远指向最后调用它的那个对象”,最后调用它的对象仍然是对象 a。
我们再来看一下这个例子:
例 4:
var name = "windowsName";
var a = {
// name: "Cherry",
fn : function () {
console.log(this.name); // undefined
}
}
window.a.fn();
这里为什么会打印 undefined 呢?这是因为正如刚刚所描述的那样,调用 fn 的是 a 对象,也就是说 fn 的内部的 this 是对象 a,而对象 a 中并没有对 name 进行定义,所以 log 的 this.name 的值是 undefined。
这个例子还是说明了:this 永远指向最后调用它的那个对象,因为最后调用 fn 的对象是 a,所以就算 a 中没有 name 这个属性,也不会继续向上一个对象寻找 this.name,而是直接输出 undefined。
再来看一个比较坑的例子:
例 5:
var name = "windowsName";
var a = {
name : null,
// name: "Cherry",
fn : function () {
console.log(this.name); // windowsName
}
}
var f = a.fn;
f();
这里你可能会有疑问,为什么不是 Cherry,这是因为虽然将 a 对象的 fn 方法赋值给变量 f 了,但是没有调用,再接着跟我念这一句话:“this 永远指向最后调用它的那个对象”,由于刚刚的 f 并没有调用,所以 fn() 最后仍然是被 window 调用的。所以 this 指向的也就是 window。
由以上五个例子我们可以看出,this 的指向并不是在创建的时候就可以确定的,在 es5 中,永远是this 永远指向最后调用它的那个对象。
再来看一个例子:
例 6:
var name = "windowsName";
function fn() {
var name = 'Cherry';
innerFunction();
function innerFunction() {
console.log(this.name); // windowsName
}
}
fn()
读到现在了应该能够理解这是为什么了吧(o゚▽゚)o。
怎么改变 this 的指向
改变 this 的指向我总结有以下几种方法:
使用 ES6 的箭头函数
在函数内部使用 _this = this
使用 apply、call、bind
new 实例化一个对象
例 7:
var name = "windowsName";
var a = {
name : "Cherry",
func1: function () {
console.log(this.name)
},
func2: function () {
setTimeout( function () {
this.func1()
},100);
}
};
a.func2() // this.func1 is not a function
在不使用箭头函数的情况下,是会报错的,因为最后调用 setTimeout 的对象是 window,但是在 window 中并没有 func1 函数。
我们在改变 this 指向这一节将把这个例子作为 demo 进行改造。
箭头函数
众所周知,ES6 的箭头函数是可以避免 ES5 中使用 this 的坑的。箭头函数的 this 始终指向函数定义时的 this,而非执行时。,箭头函数需要记着这句话:“箭头函数中没有 this 绑定,必须通过查找作用域链来决定其值,如果箭头函数被非箭头函数包含,则 this 绑定的是最近一层非箭头函数的 this,否则,this 为 undefined”。
例 8 :
var name = "windowsName";
var a = {
name : "Cherry",
func1: function () {
console.log(this.name)
},
func2: function () {
setTimeout( () => {
this.func1()
},100);
}
};
a.func2() // Cherry
在函数内部使用 _this = this
如果不使用 ES6,那么这种方式应该是最简单的不会出错的方式了,我们是先将调用这个函数的对象保存在变量 _this 中,然后在函数中都使用这个 _this,这样 _this 就不会改变了。
例 9:
var name = "windowsName";
var a = {
name : "Cherry",
func1: function () {
console.log(this.name)
},
func2: function () {
var _this = this;
setTimeout( function() {
_this.func1()
},100);
}
};
a.func2() // Cherry
这个例子中,在 func2 中,首先设置 var _this = this;,这里的 this 是调用 func2 的对象 a,为了防止在 func2 中的 setTimeout 被 window 调用而导致的在 setTimeout 中的 this 为 window。我们将 this(指向变量 a) 赋值给一个变量 _this,这样,在 func2 中我们使用 _this 就是指向对象 a 了。
使用 apply、call、bind
使用 apply、call、bind 函数也是可以改变 this 的指向的,原理稍后再讲,我们先来看一下是怎么实现的:
使用 apply
例 10:
var a = {
name : "Cherry",
func1: function () {
console.log(this.name)
},
func2: function () {
setTimeout( function () {
this.func1()
}.apply(a),100);
}
};
a.func2() // Cherry
使用 call
例 11:
var a = {
name : "Cherry",
func1: function () {
console.log(this.name)
},
func2: function () {
setTimeout( function () {
this.func1()
}.call(a),100);
}
};
a.func2() // Cherry
使用 bind
例 12:
var a = {
name : "Cherry",
func1: function () {
console.log(this.name)
},
func2: function () {
setTimeout( function () {
this.func1()
}.bind(a)(),100);
}
};
a.func2() // Cherry
apply、call、bind 区别
刚刚我们已经介绍了 apply、call、bind 都是可以改变 this 的指向的,但是这三个函数稍有不同。
在 MDN 中定义 apply 如下;
apply() 方法调用一个函数, 其具有一个指定的this值,以及作为一个数组(或类似数组的对象)提供的参数
语法:
fun.apply(thisArg, [argsArray])
thisArg:在 fun 函数运行时指定的 this 值。需要注意的是,指定的 this 值并不一定是该函数执行时真正的 this 值,如果这个函数处于非严格模式下,则指定为 null 或 undefined 时会自动指向全局对象(浏览器中就是window对象),同时值为原始值(数字,字符串,布尔值)的 this 会指向该原始值的自动包装对象。
argsArray:一个数组或者类数组对象,其中的数组元素将作为单独的参数传给 fun 函数。如果该参数的值为null 或 undefined,则表示不需要传入任何参数。从ECMAScript 5 开始可以使用类数组对象。浏览器兼容性请参阅本文底部内容。
apply 和 call 的区别
其实 apply 和 call 基本类似,他们的区别只是传入的参数不同。
call 的语法为:
fun.call(thisArg[, arg1[, arg2[, ...]]])
所以 apply 和 call 的区别是 call 方法接受的是若干个参数列表,而 apply 接收的是一个包含多个参数的数组。
例 13:
var a ={
name : "Cherry",
fn : function (a,b) {
console.log( a + b)
}
}
var b = a.fn;
b.apply(a,[1,2]) // 3
例 14:
var a ={
name : "Cherry",
fn : function (a,b) {
console.log( a + b)
}
}
var b = a.fn;
b.call(a,1,2) // 3
bind 和 apply、call 区别
我们先来将刚刚的例子使用 bind 试一下
var a ={
name : "Cherry",
fn : function (a,b) {
console.log( a + b)
}
}
var b = a.fn;
b.bind(a,1,2)
我们会发现并没有输出,这是为什么呢,我们来看一下 MDN 上的文档说明:
bind()方法创建一个新的函数, 当被调用时,将其this关键字设置为提供的值,在调用新函数时,在任何提供之前提供一个给定的参数序列。
所以我们可以看出,bind 是创建一个新的函数,我们必须要手动去调用:
var a ={
name : "Cherry",
fn : function (a,b) {
console.log( a + b)
}
}
var b = a.fn;
b.bind(a,1,2)() // 3
总结
以上所述是小编给大家介绍的JS中的this、apply、call、bind,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对网站的支持!
# js
# call
# apply
# bind
# this
# JavaScript中call
# bind的区别与实现
# 一文了解JavaScript中call/apply/bind的使用
# 一文搞懂JavaScript中bind
# call的实现
# JavaScript手写call
# bind方法
# JS 函数的 call、apply 及 bind 超详细方法
# JavaScript函数之call、apply以及bind方法案例详解
# 浅谈JavaScript中的apply/call/bind和this的使用
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
如何选择可靠的免备案建站服务器?
详解阿里云nginx服务器多站点的配置
今日头条微视频如何找选题 今日头条微视频找选题技巧【指南】
Laravel如何使用模型观察者?(Observer代码示例)
Gemini怎么用新功能实时问答_Gemini实时问答使用【步骤】
详解免费开源的.NET多类型文件解压缩组件SharpZipLib(.NET组件介绍之七)
linux写shell需要注意的问题(必看)
长沙企业网站制作哪家好,长沙水业集团官方网站?
Android仿QQ列表左滑删除操作
*服务器网站为何频现安全漏洞?
如何在阿里云购买域名并搭建网站?
Laravel如何记录日志_Laravel Logging系统配置与自定义日志通道
Python自动化办公教程_ExcelWordPDF批量处理案例
如何续费美橙建站之星域名及服务?
Laravel怎么生成二维码图片_Laravel集成Simple-QrCode扩展包与参数设置【实战】
手机软键盘弹出时影响布局的解决方法
PHP正则匹配日期和时间(时间戳转换)的实例代码
弹幕视频网站制作教程下载,弹幕视频网站是什么意思?
Thinkphp 中 distinct 的用法解析
北京企业网站设计制作公司,北京铁路集团官方网站?
lovemo网页版地址 lovemo官网手机登录
如何用5美元大硬盘VPS安全高效搭建个人网站?
公司网站制作需要多少钱,找人做公司网站需要多少钱?
制作电商网页,电商供应链怎么做?
Android使用GridView实现日历的简单功能
如何在腾讯云免费申请建站?
企业在线网站设计制作流程,想建设一个属于自己的企业网站,该如何去做?
网站制作软件免费下载安装,有哪些免费下载的软件网站?
Laravel如何使用Blade模板引擎?(完整语法和示例)
如何在阿里云香港服务器快速搭建网站?
uc浏览器二维码扫描入口_uc浏览器扫码功能使用地址
如何在Ubuntu系统下快速搭建WordPress个人网站?
Laravel Asset编译怎么配置_Laravel Vite前端构建工具使用
如何用免费手机建站系统零基础打造专业网站?
JavaScript实现Fly Bird小游戏
Bootstrap整体框架之JavaScript插件架构
Laravel如何使用Facades(门面)及其工作原理_Laravel门面模式与底层机制
微信小程序 wx.uploadFile无法上传解决办法
制作旅游网站html,怎样注册旅游网站?
Laravel Sail是什么_基于Docker的Laravel本地开发环境Sail入门
Python文件异常处理策略_健壮性说明【指导】
如何在建站之星绑定自定义域名?
如何在宝塔面板中创建新站点?
网站优化排名时,需要考虑哪些问题呢?
mc皮肤壁纸制作器,苹果平板怎么设置自己想要的壁纸我的世界?
Android Socket接口实现即时通讯实例代码
Laravel如何为API生成Swagger或OpenAPI文档
如何在 React 中条件性地遍历数组并渲染元素
什么是javascript作用域_全局和局部作用域有什么区别?
高端智能建站公司优选:品牌定制与SEO优化一站式服务

