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 · 3620 次点击
    这是一个创建于 3296 天前的主题,其中的信息可能已经有所发展或是发生改变。

    如代码代示,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  
       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   ·   我们的愿景   ·   实用小工具   ·   5125 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 09:34 · PVG 17:34 · LAX 02:34 · JFK 05:34
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.