ES6 方法得到一个空的“this”并且类变量不可访问[重复]

问题描述 投票:0回答:4

我正在使用 ES6 类将 Node 中的一些功能捆绑在一起。这是(基本上)它的样子:

class processDocs {
  constructor(id) {
    this.id = id;
    // console.log(this) returns { id: id }
  }

  getDocs(cb) {
    // console.log(this) returns null
    docs
      .query(qb => {
         qb.where('id', this.id);
      })
      .fetch()
      .then(function(documents) {
        cb(null, documents);
      })
    ;
  }

  alterDocs(documents, cb) {
    //some logic
  }

  reindexSearch(cb) {
    //some logic
  }

  process() {
    // console.log(this) returns { id: id }
    async.waterfall([
      this.getDocs,
      this.alterDocs,
      this.reindexSearch
    ]);
  }
}


export default processDocs;

我认为对于 ES6 类,分配公共变量的方法就是简单地引用

this
,而通过构造函数初始化这些变量的方法正是它在我的类定义中显示的方式。

这是我调用该类的方式(在单独的文件中):

var Processor = require('./processDocs');

var pr = new Processor(id);
var docs;
pr.process();

问题是,当我从构造函数中

console.log
输出
this
时,我得到了预测的
{ id: id }
值;但是,每当我在
this
运行时注销
getDocs
时,它都是空的。但是,当我在瀑布前的
process
中注销
this
时,我得到了原来的对象。

这有什么原因吗?

顺便说一句,我正在使用节点:

process()

和babel-node

v0.10.33
,并且我使用
4.6.6
标志运行babel-node。在有人问之前,我无法更新到较新的 Node 版本,因为主要依赖项停留在
--harmony

编辑

我能够创建一个解决方法,但它不太像 es6。问题似乎出在v0.10.x。我不得不使用

async.waterfall
来修复它:

.bind


node.js ecmascript-6 babeljs
4个回答
7
投票

考虑这个例子

async.waterfall([ this.getDocs.bind(this), this.alterDocs.bind(this), this.reindexSearch.bind(this) ]);

输出是

class processDocs { constructor(id) { this.id = id; console.log(this) } getDocs(cb) { console.log(this) } alterDocs(documents, cb) { //some logic } reindexSearch(cb) { //some logic } process() { console.log(this) } } var process = new processDocs(10); var docs = process.getDocs(function(){}); var processInstance = process.process(); var docsAsFunction = process.getDocs; docsAsFunction(function(){});

如您所见,最后一个是 undefines,它正在调用“docsAsFunction”,因为您没有直接从其类中调用该函数,因此上下文不同。

您可以阅读相关内容,例如

这里

编辑 2024 年 - 因为它“仍然是一件事”,我正在扩展答案。

有多种解决方案。

    正确使用
  1. 我想说最好的解决方案是正确使用它。这意味着:

永远不要将函数“从其实例中取出”。如果您稍后需要调用该函数,只需保留整个实例,例如这样:

processDocs {id: 10} processDocs {id: 10} processDocs {id: 10} undefined

    如无必要,请勿使用
  • class A { constructor(id) { this.id = id; } someFunction(){ console.log(this); } } const a1 = new A(5); const a2 = new A(20); const arr = [a1, a2]; // some business logic arr.forEach(a => a.someFunction());

    和课程。当您需要存储库、控制器、服务等文件时,它默认会创建单例,这正是您想要的(它基本上类似于 Java 中的 @Autowired,但是是本机的)。

    
    

    例如
      this
    • 看起来类似于下面的代码。那么您不必考虑将
      somethingService.js
      用作
      doSomething()
      ,或者您只需要函数本身并直接使用
      somethingService.doSomething()
      
      
  • doSomething()
    使用自己
  1. 有一段时间,在构造函数中使用“self”非常流行,然后在任何地方都使用它而不是
const someDefaultValue = 10; export function doSomething() { console.log(someDefaultValue); }

。我认为这是一个有点hacky的解决方案,但考虑到JavaScript中

this
的奇怪行为,
this
的工作方式更像其他语言中的
self
,所以这是一种方法。

this


2
投票

class Simple { constructor(id) { this.id = id; self = this; } showThis(text) { console.log(this, ` ** ${text} **`) } } class SimpleWithSelf { constructor(id) { this.id = id; const self = this; } showThis(text) { console.log(self, ` ** ${text} **`) } } const simple = new Simple(10); simple.showThis("normal usage using instance of class"); const showThisFn = simple.showThis; showThisFn("function using without instance"); const simpleWithSelf = new SimpleWithSelf(10); simpleWithSelf.showThis("normal usage using instance of class with self"); const showThis = simpleWithSelf.showThis; showThis("function using without instance with self");

参见 
这篇 MDN 文章

:“箭头函数捕获封闭上下文的 this 值”


1
投票
getDocs = (cb) => { // console.log(this) will not returns null docs .query(qb => { qb.where('id', this.id); }) .fetch() .then(function(documents) { cb(null, documents); }) ; }

的正文更新为:


process()

使用箭头函数可确保使用正确的上下文调用类的成员函数。


0
投票

process() { // console.log(this) returns { id: id } async.waterfall([ (cb)=>{this.getDocs(cb);}, (documents,cb)=>{this.alterDocs(documents,cb);}, (cb)=>{this.reindexSearch(cb);} ]); }

然后,当我需要它时,我在构造函数中使用这个命令

let bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; //from coffeescript's => operator //use in a class's constructor to make the this pointer always refer to the object in which a function resides function fixThisPointer(_this, func){ _this[func.name] = bind(_this[func.name], _this); } function fixThisPointer2(_this, funcNameArray){ for (name of funcNameArray){ _this[name] = bind(_this[name], _this); } }

或者这个命令

fixThisPointer(this, foo)

© www.soinside.com 2019 - 2024. All rights reserved.