理解 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回调函数的理解!
很有共鸣,之前也是一直对回调函数感觉不明不白的,自己也看了不少解释说明.后来我觉得造成很多人对回调理解困难的一个原因就是,我在开发中见到的大多数使用了回调函数的情况都是直接上来就 传一个回调函数进去 ...
随机推荐
- .NET Remoting学习笔记(一)概念
目录 .NET Remoting学习笔记(一)概念 .NET Remoting学习笔记(二)激活方式 .NET Remoting学习笔记(三)信道 背景 自接触编程以来,一直听过这个名词Remotin ...
- 每天一个linux命令(6):rmdir 命令
今天学习一下linux中命令: rmdir命令.rmdir是常用的命令,该命令的功能是删除空目录,一个目录被删除之前必须是空的.(注意,rm - r dir命令可代替rmdir,但是有很大危险性.)删 ...
- 已知2个一维数组:a[]={3,4,5,6,7},b[]={1,2,3,4,5,6,7};把数组a与数组b 对应的元素乘积再赋值给数组b,如:b[2]=a[2]*b[2];最后输出数组b的元素。
package hanqi; import java.util.Scanner; public class Test7 { public static void main(String[] args) ...
- 解决ScrollView嵌套ListView,ListView填充容器后,界面自动滚动回顶部的问题
1.scrollView.scrollTo(0,0),有时可以,有时不行: 2.listView.post(new Runnable() { ...
- 删除配置文件解决OS X各种WiFi无法连接的顽固问题,解决MAC无法连接wif的情况 Preferences
删除配置文件解决OS X各种WiFi无法连接的顽固问题 删除配置文件解决OS X各种WiFi无法连接的顽固问题1 记住现在wifi的密码并将wifi关闭2 前往文件夹/Library/Preferen ...
- Solr调研总结
http://wiki.apache.org/solr/ Solr调研总结 开发类型 全文检索相关开发 Solr版本 4.2 文件内容 本文介绍solr的功能使用及相关注意事项;主要包括以下内容:环境 ...
- Unity 5.4 测试版本新特性---因吹丝停
原文:http://blogs.unity3d.com/2016/03/15/enhanced-visuals-better-performance-and-more-the-unity-5-4-pu ...
- Swift入门篇-字符串和字符
今天主要是介绍一下字符串的用法 ,字符串的语法和object-c语法不太一样,但是思想是一样,就是写法不太一样.如果您对.net和java语法比较熟悉的话,那您几乎没有深压力.如果您对swift 基本 ...
- 内部通信服务Factory(WCF)
WCF,很好,却又麻烦,很多时候不想用WCF的原因就是:用这个真麻烦... 麻烦的地方,比如: 一堆一堆的服务配置,散落在一个一个的folder下,更新系统时容易出错 客户端除了要知道WCF Cont ...
- 【转帖】Moodle平台的5个新玩法
[玩坏Moodle平台]Moodle平台的5个新玩法 1.RSS订阅 Moodle平台可以导入外部博客(或其他提供RSS的服务),并显示在Moodle内置的博客系统中.无论是自己的个人网站还是他人的博 ...