任何变量或对象都有其赖以生存的上下文。如果简单地将对象理解为一段代码,那么对象处在不同的上下文,这段代码也会执行出不同的结果。

例如,我们定义一个函数 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.getUrl1pseudoWindowpseudoWindow.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,如果我们想要通过回调的方式打印出 pseudoWindowdocument.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的更多相关文章

  1. 如何理解JS回调函数

    1.回调函数英文解释: A callback is a function that is passed as an argument to another function and is execut ...

  2. 理解JS回调函数

    我们经常会用到客户端与Web项目结合开发的需求,那么这样就会涉及到在客户端执行前台动态脚本函数,也就是函数回调,本文举例来说明回调函数的过程. 首先创建了一个Web项目,很简单的一个页面,只有一个bu ...

  3. JS回调函数中的this指向(详细)

    首先先说下正常的this指向问题 什么是this:自动引用正在调用当前方法的.前的对象. this指向的三种情况 1. obj.fun()     fun中的this->obj,自动指向.前的对 ...

  4. 简单理解js回调函数

    前言 其实回调函数简单通俗点就是当有a和b两个函数,当a作为参数传给b,并在b中执行,这时a就是一个回调(callback)函数,如果a是一个匿名函数,则为匿名回调函数那下面们来通过一个实例来具体解释 ...

  5. => 应用在js回调函数中

    => 可以简化以前的回调函数的调用,具体来说: 今后,几乎所有的回调函数都可用箭头函数简化 比如: 1. 所有回调函数都可: 去function改=> 2. 如果函数体只有一句话: 可省略 ...

  6. js回调函数(callback)理解

    Mark! js学习 不喜欢js,但是喜欢jquery,不解释. 自学jquery的时候,看到一英文词(Callback),顿时背部隐隐冒冷汗.迅速google之,发现原来中文翻译成回调.也就是回调函 ...

  7. js回调函数的理解

    js回调函数(callback)理解 Mark! 讲之前说一句 function say(){ alert(,,,,,,,,) } var say=function (){ alert(,,,,,,, ...

  8. 使用匿名函数在回调函数中正确访问JS循环变量

    有时候, 需要以不同的参数调用某个URL,并且在回调函数中仍然可以访问正在使用的参数, 这时候, 需要使用闭包保存当前参数, 否则, 当回调函数执行时, 之前的参数很可能早已被修改为最后一个参数了. ...

  9. 妙谈js回调函数的理解!

    很有共鸣,之前也是一直对回调函数感觉不明不白的,自己也看了不少解释说明.后来我觉得造成很多人对回调理解困难的一个原因就是,我在开发中见到的大多数使用了回调函数的情况都是直接上来就 传一个回调函数进去 ...

随机推荐

  1. iOS应用性能调优的25个建议和技巧

    本文来自iOS Tutorial Team 的 Marcelo Fabri,他是Movile的一名 iOS 程序员.这是他的个人网站:http://www.marcelofabri.com/,你还可以 ...

  2. javaweb学习总结(二十四)——jsp传统标签开发

    一.标签技术的API 1.1.标签技术的API类继承关系 二.标签API简单介绍 2.1.JspTag接口 JspTag接口是所有自定义标签的父接口,它是JSP2.0中新定义的一个标记接口,没有任何属 ...

  3. Leetcode 102 Binary Tree Level Order Traversal 二叉树+BFS

    二叉树的层次遍历 /** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * ...

  4. Ubuntu 安装JDK步骤 ,提示没有那个文件或目录

    作为一个程序员,配置环境是最基本的功夫,然而我却捣鼓了一下午,包括安装Ubuntu,安装JDK和配置环境变量. 简单记录下自己的安装过程: 1  下载JDK tar包,使用tar -xzvf jdk* ...

  5. python爬虫代码

    原创python爬虫代码 主要用到urllib2.BeautifulSoup模块 #encoding=utf-8 import re import requests import urllib2 im ...

  6. 导出特定内容成insert语句

           )                                EXEC('SELECT ' + @insert_sql + ' FROM ' + @table  )

  7. JAVA中取子字符串的几种方式

    有这样一串字符串:String s = "共 100 页, 1 2 3 4..."; 假如我想把"100"给取出来,该如何做? 方法一: 采用split的方式 ...

  8. Codeforces Round #379 (Div. 2) D. Anton and Chess 水题

    D. Anton and Chess 题目连接: http://codeforces.com/contest/734/problem/D Description Anton likes to play ...

  9. DataTable 中varchar 转换为 Double 后重新 排序。

    DataTable  查询出某个字段为varchar 类型的.不过里面存的为数字,需要进行排序.可是如果直接排序就会不对.因为为varchar类型的,需要转换一下. 方法一: dt.Columns.A ...

  10. Fixed error when submitting assignments in Machine Learning on Coursera

    Environment: OS: OSX 10.8.5 Matlab: R2013a(8.1.0.604) 64bit   How to fix: In file submit.m, line 129 ...