现在我把闭包跟 this 分开来看了,又遇到了些问题,望各位解答 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a Javascript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
Javascript 权威指南第 5 版
Closure: The Definitive Guide
cheroky
V2EX    Javascript

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

  •  
  •   cheroky 2017-05-22 12:47:47 +08:00 4049 次点击
    这是一个创建于 3066 天前的主题,其中的信息可能已经有所发展或是发生改变。

    谢谢上一个帖子各位大牛细心解答,是应该把 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 条回复    2017-05-26 16:10:56 +08:00
    UncleRiver
        1
    UncleRiver  
       2017-05-22 12:57:03 +08:00
    参考一下这个:
    http://stackoverflow.com/questions/7043509/this-inside-object

    > Javascript has no block scope, only function scope
    whimsySun
        2
    whimsySun  
       2017-05-22 13:08:43 +08:00
    函数被传递时没有通过 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  
       2017-05-22 13:10:53 +08:00
    @UncleRiver 和楼主的例子是两种情况
    ericls
        4
    ericls  
       2017-05-22 13:11:18 +08:00
    @UncleRiver `let` and `const` are block scoped
    otakustay
        5
    otakustay  
       2017-05-22 13:27:09 +08:00
    只看调用不看怎么定义和怎么传参,你只要看到 doo 里是 f()(函数调用),那么这个 f 只要没 bind,无论它怎么定义的怎么传进来的,它的 this 都是 global,和 doo 的 this 是啥以及这个 f 怎么来都没关系
    cheroky
        6
    cheroky  
    OP
       2017-05-22 13:29:57 +08:00
    @whimsySun 感谢热心回答。但是我还有问题是这个函数作为对象的方法被调用,不是应该指向该对象么?而且这个函数既不是全局函数。而且用 obj2 调用,为什么不指向 obj2?
    lijsh
        7
    lijsh  
       2017-05-22 13:33:08 +08:00   1
    @cheroky #6 你只是传 obj.getName 这个方法进去,等价于传 function() {
    console.log(this.name);
    },传进去就变闭包了,调用的时候就指向全局。
    必须 obj.getName() 才是 obj 调用
    wodewone
        8
    wodewone  
       2017-05-22 13:42:24 +08:00
    js 执行要看它的运行环境而不是它的初始环境
    xilixjd
        9
    xilixjd  
       2017-05-22 13:43:58 +08:00
    你确定你看完了 u don't know 吗。。
    this 的指向是看在哪调用的,好像有 4 种调用形式
    你这个例子跟第一种是一样的
    sensui7
        10
    sensui7  
       2017-05-22 14:11:06 +08:00   1
    > 至少这个例子我可以理解为 obj.getName 的调用点再 doo 函数里...

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

    var obj2 = {
    name: "Yes2",
    getName: function() {
    (function() {
    console.log(this.name);
    })();
    }
    }
    obj2.getName() //"global"
    结果是一样的不知道是不是同个原理
    bramblex
        13
    bramblex  
       2017-05-22 15:16:48 +08:00
    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  
       2017-05-22 15:18:10 +08:00
    上面的要是你都理解,把他反过来你就不会了?

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

    const f = aaa.f

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

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

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

    而函数在创建的时候,这个 this 是毫无意义的。
    cheroky
        22
    cheroky  
    OP
       2017-05-22 16:55:35 +08:00
    @Biwood
    @bramblex
    @whimsySun
    大概有点理解了,那就是 function a(){b();} 虽然放在 a()里面,这个 b()并不不不不不不不不不不不不不是 a()调用的!!!!??,所以也不存在 this 指向 a,然后最后 b()所以指向的是 window ?
    IdJoel
        23
    IdJoel  
       2017-05-22 17:17:22 +08:00
    留一下 不忙了看 感谢 LZ 和大牛
    crs0910
        24
    crs0910  
       2017-05-22 22:54:14 +08:00 via iPhone
    js 的 this 不是 self 而是 context
    saga
        25
    saga  
       2017-05-23 17:40:49 +08:00   1
    wedaren
        26
    wedaren  
       2017-05-26 16:10:56 +08:00   1
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2773 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 27ms UTC 15:06 PVG 23:06 LAX 08:06 JFK 11:06
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86