关于 JS 作用域与 this 的一点疑问

2018-11-30 13:56:18 +08:00
 gam2046

本人,后端开发人员,对 JS 了解不多。不知道标题是否准确。

出于自用目的,正在写一个 userscript。编写过程中遇到了一点障碍,奈何不知道应该如何表述,所以没法搜。

样例代码

class Foo {
    constructor() {
        this.field = new Map()
    }

    requestOnLoad(details) {
        /*
         * 此方法由于产生于回调
         * 而 JavaScript 中函数本身也属于对象
         * 因此
         * 此时的 this 代表的是 GM_xmlhttpRequest 方法所产生的回调函数
         * 并不指向与 Foo 对象的实例
         * 
         * 但是,我希望在此方法内访问 Foo 对象的实例,并设置 field 属性
         */
        this.field.set('aa', 'bb') // 如何能够让这句话符合预期呢?
    }

    invoke() {
        GM_xmlhttpRequest({
            url: requestUrl,
            method: "GET",
            onload: this.requestOnLoad,
        });
    }
}

new Foo().invoke()

因此当样例代码执行时,this 指向的对象与预期不符,导致我没法调用 field.set 方法。同时,奈何我搜了一堆 ES6 相关资料。

也没见到有相关的解释。

请教各位前端大佬,对于样例代码中,requestOnLoad 方法内,应该如何正确的访问到 Foo 对象的实例呢?

3024 次点击
所在节点    JavaScript
10 条回复
wxsm
2018-11-30 14:02:07 +08:00
使用箭头函数。

requestOnLoad: (details) => {
//...
}
imyxz
2018-11-30 14:04:57 +08:00
应该是这样吧(new Food()).invoke()
wildnode
2018-11-30 14:12:11 +08:00
箭头函数可解
sker101
2018-11-30 14:12:13 +08:00
onload 的函数试试.bind ( this )
gam2046
2018-11-30 14:12:33 +08:00
@wxsm 感谢。你是指这样调用嘛?
GM_xmlhttpRequest({
url: requestUrl,
method: "GET",
onload: (details)=>{ /*Do something*/},
onerror: this.requestOnError,
onabort: this.requestOnAbort,
ontimeout: this.requestOnTimeout
});

但是有一点很尴尬的事情,按照我既往的经验,我设计的是,后面还有一个 class 会继承( extends )这个 Foo,因此 requestOnLoad 实际做的事情,并不在 Foo 里面定义。这样话,我就没法这么写了。是否还有其他变通方法呢?
xqin
2018-11-30 14:17:11 +08:00
GM_xmlhttpRequest({
url: requestUrl,
method: "GET",
onload: this.requestOnLoad.bind(this),
});

@gam2046

onload: this.requestOnLoad.bind(this),
gam2046
2018-11-30 14:18:39 +08:00
感谢 @sker101 提供的方法。该方法可以解决我遇到的问题,顺便我去搜了下相关资料

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind

解决方案:

GM_xmlhttpRequest({
url: requestUrl,
method: "GET",
onload: this.requestOnLoad.bind(this) // 此时在回调方法中 this 对象即为 bind 方法中传递的对象
});
DrugsZ
2018-11-30 14:58:55 +08:00
constructor() {
this.field = new Map()
this.requestOnLoad = this.requestOnLoad.bind(this)
}
这样好一点吧,
SoloCompany
2018-11-30 21:36:05 +08:00
https://github.com/tc39/proposal-bind-operator

虽然有 babel 的实现, 却仍然是 stage 0 提案

onload: ::this.requestOnLoad
TwoDays91
2018-11-30 22:18:11 +08:00
除了 bind 方法 onload: () => {this.requestonload()}也可以

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/513062

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX