理解 JS 回调函数中的 this
任何变量或对象都有其赖以生存的上下文。如果简单地将对象理解为一段代码,那么对象处在不同的上下文,这段代码也会执行出不同的结果。
例如,我们定义一个函数 getUrl
和一个对象 pseudoWindow
。
function getUrl() {
console.log(this.document.URL);
}
var pseudoWindow = {
document: {
URL: "I'm fake URL"
},
getUrl1: getUrl,
getUrl2: function (callback) {
callback();
this.func = callback;
this.func();
}
}
执行 getUrl()
,打印出当前页面的 URL。
执行 pseudoWindow.getUrl1()
,打印出 I'm fake URL
。
执行 pseudoWindow.getUrl2(getUrl)
,先打印出当前页面 URL,后打印 I'm fake URL
。
下面让我们用最简单粗暴的语言来解释以上代码。
概念
什么是 this?
this 就是函数调用使用的上下文。
什么是上下文?
上下文是在句号标记法中,句号前面的那个东西。
例如 pseudoWindow.getUrl1
,pseudoWindow
是 pseudoWindow.getUrl1()
的上下文。
什么是自由变量?
当一个变量没有绑定到任何上下文时(或者说绑定到顶级作用域时,例如浏览器中的 window),它就是自由变量。
什么是变量与对象?
变量就是代码中你所用的标识符,一个标识符就是一个变量,多个变量可能指向同一个对象。例如:
pseudoWindow.getUrl1 === getUrl // 得到 true
变量所处的上下文就是对象的作用域。
代码分解
调用 getUrl()
首先 getUrl
函数是定义在全局环境中,它是一个自由变量,在浏览器中(以下描述均为浏览器环境)它的上下文就是 window
,所以 window.getUrl()
和 getUrl()
是等价的。因此 this
指向 window
对象,打印出当前 URL。
调用 pseudoWindow.getUrl1()
首先 pseudoWindow
是一个对象,它可以充当上下文角色。我们给它定义了一个属性 getUrl1
,你可以将属性视为被绑定到某个上下文的变量,变量 getUrl1
本身又指向了变量 getUrl
所指向的对象,所以 pseudoWindow.getUrl1 === getUrl
才会为 true
。
当我们调用 pseudoWindow.getUrl1()
时,它的意思是执行 getUrl()
这段代码,执行代码所需的参数为空,上下文为 pseudoWindow
。
所以函数中的 this
指向了 pseudoWindow
,而 pseudoWindow
对象恰好又有 document
属性,该属性恰好又有 URL
属性,因此打印出 I'm fake URL
。
调用 pseudoWindow.getUrl2(getUrl)
同理我们又定义了一个变量 getUrl2
,并绑定到 pseudoWindow
对象身上,使之成为后者的一个属性。而这个属性本身又指向一个匿名函数,我们姑且称之为 A,该函数对象接受另一个函数对象作为回调函数。
因此执行 pseudoWindow.getUrl2(getUrl)
时,意思是执行代码 A,执行代码所需的参数为 getUrl
这段代码,上下文为 pseudoWindow
。
因此函数 A 中的 this
指向了 pseudoWindow
。
当程序执行到函数 A 内部的 callback()
时,因为变量 callback
没有绑定到任何上下文,因此它相当于一个自由变量,它的上下文就指向了 window
对象,因此首先打印出当前页面的 URL。
接下来 this.func = callback
意味着三件事:
- 我们新申明了一个变量
func
。 - 通过
=
操作符,我们将该变量指向了callback
所指向的函数对象。 - 通过
.
操作符,我们将该变量绑定到了this
对象上,使之成为后者的一个属性,而本例中this
指向的就是pseudoWindow
对象。
于是当程序执行到 this.func()
时,它的意思是执行 callback
这段代码,执行代码所需的参数为空,上下文为 pseudoWindow
。于是打印出了 I'm fake URL
。
这段代码带来的一个副作用是我们隐式地为 pseudoWindow
对象添加了一个新的属性 func
,如果我们想要通过回调的方式打印出 pseudoWindow
的 document.URL
属性,又不想对 pseudoWindow
对象造成任何影响,那么我们可以使用函数的 apply
方法。所有函数都有 apply
方法,它会将它接收的第一个参数设置为函数的上下文。
例如本例中我们可以改写代码成这样子:
var pseudoWindow = {
document: {
URL: "I'm fake URL"
},
getUrl1: getUrl,
getUrl2: function (callback) {
callback();
callback.apply(this);
}
}
严格地说,你应该先检查 callback 参数类型是否是函数对象。
总结
Javascript 支持将函数作为参数传递,回调函数变量指向的函数对象都未与任何上下文绑定,所有未与明确上下文绑定的变量都是自由变量,浏览器器中所有自由变量的上下文都是 window 对象。
理解 JS 回调函数中的 this的更多相关文章
- 如何理解JS回调函数
1.回调函数英文解释: A callback is a function that is passed as an argument to another function and is execut ...
- 理解JS回调函数
我们经常会用到客户端与Web项目结合开发的需求,那么这样就会涉及到在客户端执行前台动态脚本函数,也就是函数回调,本文举例来说明回调函数的过程. 首先创建了一个Web项目,很简单的一个页面,只有一个bu ...
- JS回调函数中的this指向(详细)
首先先说下正常的this指向问题 什么是this:自动引用正在调用当前方法的.前的对象. this指向的三种情况 1. obj.fun() fun中的this->obj,自动指向.前的对 ...
- 简单理解js回调函数
前言 其实回调函数简单通俗点就是当有a和b两个函数,当a作为参数传给b,并在b中执行,这时a就是一个回调(callback)函数,如果a是一个匿名函数,则为匿名回调函数那下面们来通过一个实例来具体解释 ...
- => 应用在js回调函数中
=> 可以简化以前的回调函数的调用,具体来说: 今后,几乎所有的回调函数都可用箭头函数简化 比如: 1. 所有回调函数都可: 去function改=> 2. 如果函数体只有一句话: 可省略 ...
- js回调函数(callback)理解
Mark! js学习 不喜欢js,但是喜欢jquery,不解释. 自学jquery的时候,看到一英文词(Callback),顿时背部隐隐冒冷汗.迅速google之,发现原来中文翻译成回调.也就是回调函 ...
- js回调函数的理解
js回调函数(callback)理解 Mark! 讲之前说一句 function say(){ alert(,,,,,,,,) } var say=function (){ alert(,,,,,,, ...
- 使用匿名函数在回调函数中正确访问JS循环变量
有时候, 需要以不同的参数调用某个URL,并且在回调函数中仍然可以访问正在使用的参数, 这时候, 需要使用闭包保存当前参数, 否则, 当回调函数执行时, 之前的参数很可能早已被修改为最后一个参数了. ...
- 妙谈js回调函数的理解!
很有共鸣,之前也是一直对回调函数感觉不明不白的,自己也看了不少解释说明.后来我觉得造成很多人对回调理解困难的一个原因就是,我在开发中见到的大多数使用了回调函数的情况都是直接上来就 传一个回调函数进去 ...
随机推荐
- atitit.微信项目开发效率慢的一些总结
atitit.微信项目开发效率慢的一些总结 #---理念问题..这个是最大的问题.. 要有专人提升开发效率才好.. #---没有一个好的开发方法体系.... ini deve 法. fell asd+ ...
- 为什么说外卖O2O行业的未来在于尖端技术?
7月13日,百度公司董事长兼CEO李彦宏在发布会上谈及百度外卖时表示,百度外卖里有非常多的人工智能技术的应用,比如同样的商家订单,先配送后配送,时间路线规划等等,都有人工智能的技术,涉及机器学习的问题 ...
- 一些新的web性能优化技术
1.IconFont:图标字体,这是近年来新流行的一种以字体代替图片的技术.它可以适应任何分辨率而不会出现图片模糊问题,与图片相比它具有更小的容量,更高的灵活性(像字体一样可以设置图标大小.颜色.透明 ...
- html5使用FileReader上传图片
客户端代码是网上找的,修改为.net代码. <html><head> <meta charset="utf-8"> <titl ...
- 【由VerySky原创】CX51、CX52 ——数据表
今天通过DEBUG CX52 得出所保存的数据表是ECMCA:
- DotNetMQ的一个小demo
DotNetMQ是一个新的.独立的.开源的,完全基于C#和.NET Framework3.5的消息队列系统 下载源代码 - 1.28 MB 下载二进制文件 - 933 KB 下载例子 - 534 KB ...
- MongoDB图形化管理工具
NoSQL的运动不止,MongoDB 作为其中的主力军发展迅猛,也带起了一股开发图形化工具的风潮:气死反过来说,看一个产品是否得到认可,可以侧面看其第三方工具的数量和成熟程度:简单的收集了MongoD ...
- 结合Domino打造全功能的Grid
1. 需求说明: 在domino开发中我们经常会遇到表单上需要一个类似table的组件,你可以增删改等.比如我有一个张报核单据,上面需要详细列出每项金额的明细,我们先看完成后的效果: 上面 ...
- C++ Data Member内存布局
如果一个类只定义了类名,没定义任何方法和字段,如class A{};那么class A的每个实例占用1个字节的内存,编译器会会在这个其实例中安插一个char,以保证每个A实例在内存中有唯一的地址,如A ...
- ubuntu 16.04 U盘多媒体不自动弹出
如下图: 设置 --> 详细信息 --> 可移动媒体 来自为知笔记(Wiz)