请教有一个 Javascript 问题 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a Javascript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
Javascript 权威指南第 5 版
Closure: The Definitive Guide
whatisnew
V2EX    Javascript

请教有一个 Javascript 问题

  •  
  •   whatisnew 2015-04-16 00:45:39 +08:00 4185 次点击
    这是一个创建于 3836 天前的主题,其中的信息可能已经有所发展或是发生改变。

    如代码代示,js对象内访问,用 thisobj 都可以,但是在 对象方法内在 callback 里用 this 就会报未定义,但是用 obj.remove 就可以,求大神给指点一下,如何写比较好比较正确。

    define(function() { var obj = { add: function(id) { // 这里可以用 this this.edit(id, function() { // 这里报 this 未定义 this.remove(id); // 如果用 obj.remove() 就可以 obj.remove(id); }); // 也可以用 obj.edit() // 哪种效率比较高呢? // 或者是比较标准的正确写法呢? }, edit: function(id) { console.log('edit'); }, remove: function(id) { console.log('remove'); } }; return obj; }); 
    31 条回复    2015-04-16 11:02:23 +08:00
    Hyperion
        1
    Hyperion  
       2015-04-16 00:56:05 +08:00   2
    调用this.edit 之前 _this = this;

    在传入函数里使用_this.
    ChiangDi
        2
    ChiangDi  
       2015-04-16 00:59:31 +08:00 via Android   1
    是报 this.remove 未定义吧?
    sneezry
        3
    sneezry  
       2015-04-16 01:17:53 +08:00   2
    this.edit(id, function() {
    this.remove(id);
    }.bind(this));

    但是,this.edit不是只接受一个参数吗??
    whatisnew
        4
    whatisnew  
    OP
       2015-04-16 07:00:10 +08:00
    @sneezry 哈哈,是的,这是一个示例。
    whatisnew
        5
    whatisnew  
    OP
       2015-04-16 07:01:03 +08:00
    @Hyperion 这样的话在对象内使用 `this` 和 `obj` 有啥区别呢?效率区别?标准区别?
    whatisnew
        6
    whatisnew  
    OP
       2015-04-16 07:10:49 +08:00
    @ChiangDi 是的,确切的来说是 this.remove 未定义。超出了作用域。
    FrankFang128
        7
    FrankFang128  
       2015-04-16 07:46:34 +08:00 via Android   1
    极端得讲一下:
    1 this 永远指向 window
    2 除非你显式指定 this
    3 显式地指定this有如下方法:
    3.1 使用点语法指定,如obj.remove
    3.2 使用call和apply指定
    3.3 浏览器内置方法默认指定,如事件的回调等
    3.4 其他不建议的方法
    FrankFang128
        8
    FrankFang128  
       2015-04-16 07:49:59 +08:00 via Android
    不要再用OOP的角度来理解JS的this了,不然你永远学不会。
    好好看看犀牛书,不要看了蝴蝶书就以为自己会JS了。
    FrankFang128
        9
    FrankFang128  
       2015-04-16 07:52:45 +08:00 via Android
    3.2 还应加上 bind 等方法。
    whatisnew
        10
    whatisnew  
    OP
       2015-04-16 08:28:32 +08:00
    @FrankFang128 果然大神,一看就知道我纠结在哪了,真的这么多年 cpp java php 习惯性 oop 了,着手码几行 js 真心不适应,正在强迫自己适应中。

    从前端同事那里借了这个犀牛书,正在专研中!哈哈

    不过,我在 `var obj {..}` 里 `console` 出来了 `this`,出来一个对象,是 `var obj` 声明的这个对象本身。
    如果是 this 指向 window 的话,他应该有更多对象才对吧?
    FrankFang128
        11
    FrankFang128  
       2015-04-16 08:36:43 +08:00 via Android
    @whatisnew 我上面说的是浏览器,所以用了极端两字。非浏览器的 this 会默认指向 null 或 global
    FrankFang128
        12
    FrankFang128  
       2015-04-16 08:37:46 +08:00 via Android
    @whatisnew 你说的后半段我没看懂,贴出代码吧
    mcfog
        13
    mcfog  
       2015-04-16 08:37:47 +08:00 via Android   1
    @FrankFang128 挑个刺,漏了strict mode哈
    FrankFang128
        14
    FrankFang128  
       2015-04-16 08:38:58 +08:00 via Android
    @mcfog 嗯,“极端”。手机码字
    FrankFang128
        15
    FrankFang128  
       2015-04-16 08:43:13 +08:00 via Android
    @mcfog 所以就简化了一些
    Septembers
        16
    Septembers  
       2015-04-16 08:54:19 +08:00 via Android
    @mcfog ES5特性 ES3并没有
    FrankFang128
        17
    FrankFang128  
       2015-04-16 08:54:55 +08:00   5
    现在有电脑了,就再说下吧。
    this和obj的区别,obj 很简单,就是一个对象的引用,你给 obj 赋值后它就固定了。
    但 this 不是,this 是一个函数在被调用时的上下文:
    1. 只有函数被调用时 this 才能确定是什么。
    如 obj.add 里的第一个 this,被你显式地指定为 obj,所以 this === obj
    但是如果你这样调用 `var anotherAdd= obj.add; anotherAdd()`,那么 anotherAdd 被调用时的 this 就又是 window 了
    2. 每执行一个函数,都对应一个 this。
    所以你 obj.add 里的第2个 this,也就是`this.remove(id);` 这一句里的 this,由于没有显式指定,就有指向 window 了(在这一句话被执行的时候)
    FrankFang128
        18
    FrankFang128  
       2015-04-16 08:57:15 +08:00
    不知道有没有说清楚,总之就是每看到一个 function 关键字,this 就有可能变化。
    this 跟对象无关,只与 function 有关。
    FrankFang128
        19
    FrankFang128  
       2015-04-16 08:59:34 +08:00
    17 楼说得有点乱,没看懂就忽略,看 18 楼吧。
    whatisnew
        20
    whatisnew  
    OP
       2015-04-16 09:06:47 +08:00
    @FrankFang128 懂了!哈哈,太赞了!新技能 get 高兴中
    200cc
        21
    200cc  
       2015-04-16 09:09:17 +08:00
    js可以用prototype来实现oop.
    感觉这样理解起来更容易.
    Hyperion
        22
    Hyperion  
       2015-04-16 09:11:09 +08:00   1
    使用this 其实完全没有什么问题, 而且上面对this 的解释似乎有点小问题?

    可以参考MDN 的这个链接, 似乎是有意漏掉了某个?
    https://developer.mozilla.org/en-US/docs/Web/Javascript/Reference/Operators/this

    Javascript 的this 不是难理解, 只是因为它本身的一组特性综合导致他和别的语言不一样. 关于在闭包里使用this , 我最早是从阮一峰的blog 上看到最完整的概述的.

    效率问题, 都是引用. 作为一种习惯, 理解this 很重要, 因为这个已经是通行的做法了.

    掏出犀牛书第六版(第五版没有在学校), p188页 译者注释.

    仅作讨论, 求同存异. 希望不要引起争执.

    书, 个人不提供建议, 自认水平有限. 犀牛这本圣经扫了几遍, 但看红皮还是有很多要补的地方, 比如逻辑操作符具体的特性, 各种实现类方式的利弊, 以及各种兼容实现问题.
    whatisnew
        23
    whatisnew  
    OP
       2015-04-16 09:14:13 +08:00
    @200cc prototype 实现的 oop 会有效率上的提升吗?因为我看到 prototype oop 在调用的时候太惨了 new(_) 那个下划线,那些个 find 真心觉得是乱码一样,比较难理解。
    Hyperion
        24
    Hyperion/strong>  
       2015-04-16 09:24:54 +08:00
    @whatisnew 可以去看Javascript 高级程序设计, 相关例子会比犀牛书更完整.
    superbear
        25
    superbear  
       2015-04-16 09:45:28 +08:00
    callback里的this没有这属性,this此时指向的是window。楼上很多大牛
    neone
        26
    neone  
       2015-04-16 10:16:54 +08:00   2
    @sneezry Javascript中函数没有签名,传入函数的参数可以通过局部变量arguments(类数组对象)访问到。
    @whatisnew 可以看看《Javascript高级程序设计 第三版》的7.2.2关于this对象这一节,里面的例子和你这个问题差不多。
    200cc
        27
    200cc  
       2015-04-16 10:25:54 +08:00   1
    @whatisnew
    个人理解,oop的目的在于处理代码的复用性与可读性.效率的问题更依赖于或算法或运行环境来解决.

    至于你提到的new(_)什么什么的, 应该是你看的那段代码编写的不规范, 和prototype没关系啊. 推荐你去读一下阮一峰的博客:Javascript 面向对象编程, 深入浅出, 不能再赞.
    sneezry
        28
    sneezry  
       2015-04-16 10:32:14 +08:00 via iPhone
    @neone 受教
    whatisnew
        29
    whatisnew  
    OP
       2015-04-16 10:38:19 +08:00
    @200cc 找到了,不错不错!赞!
    hussion
        30
    hussion  
       2015-04-16 10:44:05 +08:00
    this.remove(); 非严格模式下,此处this指向的是window,严格模式下是null,所以,你懂得。。。
    jarlyyn
        31
    jarlyyn  
       2015-04-16 11:02:23 +08:00
    var self=this;

    this是js里比较蛋疼的一个坑。

    主要和使用回调/对象有关系,其实你用用call,apply,需要你制定thisarg就能明白了。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2318 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 24ms UTC 16:04 PVG 00:04 LAX 09:04 JFK 12:04
    Do have faith in what you're doing.
    ubao msn 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