推荐关注
Meteor
JSLint - a JavaScript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
JavaScript 权威指南第 5 版
Closure: The Definitive Guide
cheroky

现在我把闭包跟 this 分开来看了,又遇到了些问题,望各位解答

  •  
  •   cheroky · May 22, 2017 · 4473 views
    This topic created in 3277 days ago, the information mentioned may be changed or developed.

    谢谢上一个帖子各位大牛细心解答,是应该把 this 分开看。然后我看 you dont know js,先把 this 搞懂,里面说的 this 的会突然指向 window 的变量,结合楼内大神的答案,其实可以用 window 解释,然后我遇到了回调函数 this 的下面问题:

    var name = "global";
    var obj = {
    	name: "Yes",
    	getName: function() {
    		console.log(this.name);
    	}
    }
    
    function doo(f) {
    	f(); 
    }
    
    doo(obj.getName) //"global"
    

    至少这个例子我可以理解为 obj.getName 的调用点再 doo 函数里,所以 this 应该指向这个,而调用这个函数可以解释为 window.doo(obj.getName),doo 的 this 指向 window,所以最终的 this 指向 window。那如果我用一个有 this 的对象来调用呢。代码如下:

    var name = "global";
    var obj = {
    	name: "Yes",
    	getName: function() {
    		console.log(this.name);
    	}
    }
    
    var obj2 = {
    	name: "Yes2",
    	getName: function(f) {
    		f();
    	}
    }
    
    obj2.getName(obj.getName) //"global"
    

    发现这个 this 还是指向 window,有点想不通。。。

    26 replies    2017-05-26 16:10:56 +08:00
    UncleRiver
        1
    UncleRiver  
       May 22, 2017
    参考一下这个:
    http://stackoverflow.com/questions/7043509/this-inside-object

    > Javascript has no block scope, only function scope
    whimsySun
        2
    whimsySun  
       May 22, 2017
    函数被传递时没有通过 bind 方法指定 this,this 指向其调用方的上下文,调用方你可以理解为 ${invoke}.${function}. 如果 invoke 没有指定,就是 this 就指向 global。
    上面的例子:
    调用 obj2.getName 时候 getName 的调用方就是 obj2,this 既 obj2. obj.getName 本传递后,仅做为一个函数传递,使用的时候也没有指定调用方,既 this 为 global

    如果你需要 obj2.getName(obj.getName) 输出 “ Yes ”, 通过 obj2.getName(obj.getName.bind(obj))

    如果你需要 obj2.getName(obj.getName) 输出 ‘ Yes2 ’, 修改 obj2,`obj2.getName = function(f) { f.apply(this) }`
    whimsySun
        3
    whimsySun  
       May 22, 2017
    @UncleRiver 和楼主的例子是两种情况
    ericls
        4
    ericls  
       May 22, 2017
    @UncleRiver `let` and `const` are block scoped
    otakustay
        5
    otakustay  
       May 22, 2017
    只看调用不看怎么定义和怎么传参,你只要看到 doo 里是 f()(函数调用),那么这个 f 只要没 bind,无论它怎么定义的怎么传进来的,它的 this 都是 global,和 doo 的 this 是啥以及这个 f 怎么来都没关系
    cheroky
        6
    cheroky  
    OP
       May 22, 2017
    @whimsySun 感谢热心回答。但是我还有问题是这个函数作为对象的方法被调用,不是应该指向该对象么?而且这个函数既不是全局函数。而且用 obj2 调用,为什么不指向 obj2?
    lijsh
        7
    lijsh  
       May 22, 2017   ❤️ 1
    @cheroky #6 你只是传 obj.getName 这个方法进去,等价于传 function() {
    console.log(this.name);
    },传进去就变闭包了,调用的时候就指向全局。
    必须 obj.getName() 才是 obj 调用
    wodewone
        8
    wodewone  
       May 22, 2017
    js 执行要看它的运行环境而不是它的初始环境
    xilixjd
        9
    xilixjd  
       May 22, 2017
    你确定你看完了 u don't know 吗。。
    this 的指向是看在哪调用的,好像有 4 种调用形式
    你这个例子跟第一种是一样的
    sensui7
        10
    sensui7  
       May 22, 2017   ❤️ 1
    > 至少这个例子我可以理解为 obj.getName 的调用点再 doo 函数里...

    你理解错了, 这里不存在 obj.getName 的调用, 你只不过是把  obj.getName 赋值给了形式参数f,你调用的是形参f. 形参f是什么, 是函数调用阿.
    ChefIsAwesome
        11
    ChefIsAwesome  
       May 22, 2017
    别想了,你不用 this 就完事了。
    cheroky
        12
    cheroky  
    OP
       May 22, 2017
    @lijsh 试了一下,不知道是不是等同于下面的代码:
    var name = "global";

    var obj2 = {
    name: "Yes2",
    getName: function() {
    (function() {
    console.log(this.name);
    })();
    }
    }
    obj2.getName() //"global"
    结果是一样的不知道是不是同个原理
    bramblex
        13
    bramblex  
       May 22, 2017
    const f = function () {console.log(this)}

    f() // => window / global

    const aaa = {}

    aaa.f = f

    aaa.f() // => aaa

    这个你能理解嘛?

    f() 等效于 f.apply(window/global)
    bramblex
        14
    bramblex  
       May 22, 2017
    上面的要是你都理解,把他反过来你就不会了?

    const aaa = {f: function() {console.log(this)}}

    const f = aaa.f

    f()
    cheroky
        15
    cheroky  
    OP
       May 22, 2017
    @bramblex 这个我能理解,我的理解是
    f=aaa.f 相当于 window.f=aaa.f 是吧,调用 window.f(),this 指向 window。问题是我的例子我把函数直接调用,和作为参数传出去再调用,我输出了 this 之后,发现函数作为参数传过去为什么 this 指向了 window,中间有涉及到 window 吗?
    whimsySun
        16
    whimsySun  
       May 22, 2017   ❤️ 1
    @cheroky 不知道你之前是不是学过一些面向对象的语言,收到了影响。js 里面,你可以把函数当成一个单一个体,只是在调用的使用会有归属,不知道这个你能不能理解
    Exin
        17
    Exin  
       May 22, 2017 via iPhone
    建议楼主把 You dont know js 中的相关章节先仔细完整地阅读,讲的还是蛮清楚的
    bramblex
        18
    bramblex  
       May 22, 2017
    @cheroky

    const aaa = {f: function(){console.log(this)}}

    下面两条有什么区别吗?

    xxx(aaa.f)

    ===
    const f = aaa.f
    xxx(f)

    如果你觉得上面两条没区别吗? f 只在调用的时候才会去找调用它的对象,传参的时候又没调用。

    最后 f = aaa.f 和 window.f = aaa.f 有本质区别的。
    Biwood
        19
    Biwood  
       May 22, 2017   ❤️ 1
    你这个问题问的挺好的,以后再项目中你会遇到很多次这种情况。

    先说原因,obj2.getName(obj.getName) 等价于 obj2.getName(匿名函数),这个 obj.getName 引用的是一个匿名函数,传参的时候,匿名函数被赋值给了形参 f,这一步是关键,形参 f 默认没有绑定任何 Context,你觉得 f 的 Context 是 obj2 吗? f 不是 obj2 的属性,所以显然不是。对于没有手动绑定 Context 的函数,默认 Context 为全局对象,浏览器里面就是 window 对象,严格模式下面会是 undefined。

    配合 ES5 里面的 Function.prototype.bind() 的用法,理解起来会容易许多。你可以在 Chrome 浏览器调试栏里面执行如下代码:

    var name = "global";
    var obj = {
    name: "Yes",
    getName: function() {
    console.log(this.name);
    }
    }

    var obj2 = {
    name: "Yes2",
    getName: function(f) {
    console.dir(f);
    f();
    }
    }

    obj2.getName(obj.getName.bind(obj2))

    对比一下跟你原来的写法有什么不同,同时看看打印出来的函数对象的具体结构,大概就能理解了
    bramblex
        20
    bramblex  
       May 22, 2017   ❤️ 1
    @cheroky

    楼主你的问题在于,你根本不理解在 js 函数和其他变量是一样的东西,一个函数里面的 this 是不会绑定一个特定的对象的,而是会在 [函数调用的那一刻] 寻找所调用它的对象。

    所以你上面的例子,只有到 f() 这个执行,才会去找调用 f 的对象。但是现在没人在调用 f 啊,所以就默认是 window 或者 global
    bramblex
        21
    bramblex  
       May 22, 2017
    这个 this 叫做 “上下文指针”,指向的是这个函数在被调用的那一刻,直接调用这个函数的对象。

    而函数在创建的时候,这个 this 是毫无意义的。
    cheroky
        22
    cheroky  
    OP
       May 22, 2017
    @Biwood
    @bramblex
    @whimsySun
    大概有点理解了,那就是 function a(){b();} 虽然放在 a()里面,这个 b()并不不不不不不不不不不不不不是 a()调用的!!!!??,所以也不存在 this 指向 a,然后最后 b()所以指向的是 window ?
    IdJoel
        23
    IdJoel  
       May 22, 2017
    留一下 不忙了看 感谢 LZ 和大牛
    catoncat
        24
    catoncat  
       May 22, 2017 via iPhone
    js 的 this 不是 self 而是 context
    saga
        25
    saga  
       May 23, 2017   ❤️ 1
    wedaren
        26
    wedaren  
       May 26, 2017   ❤️ 1
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   2956 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 220ms · UTC 15:20 · PVG 23:20 · LAX 08:20 · JFK 11:20
    ♥ Do have faith in what you're doing.