zoukankan      html  css  js  c++  java
  • 理解 JS 回调函数中的 this

    理解 JS 回调函数中的 this:https://www.cnblogs.com/gavinyyb/p/6286750.html

    原文链接:http://www.tuicool.com/articles/z2Yvaq

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

    例如,我们定义一个函数 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 对象。

  • 相关阅读:
    【Java】REST风格
    KMP(烤馍片)算法
    Lca求法 (树链剖分 与 倍增)
    hash学习笔记
    星际网络(数学)
    P3537 [POI2012]SZA-Cloakroom (背包)
    乘车路线 (二维最短路)
    渔民的烦恼 (二分)
    Jmeter 常用函数(18)- 详解 __isDefined
    Jmeter 常用函数(17)- 详解 __substring
  • 原文地址:https://www.cnblogs.com/bydzhangxiaowei/p/11595279.html
Copyright © 2011-2022 走看看