我对Java语言还很陌生,遇到了一个我似乎无法理解的问题。控制台抱怨说无法识别该功能。

我有以下代码(GraphActions.js):

var VentureDispatcher = require('../dispatcher/VentureDispatcher');
var GraphStoreConstants = require('../constants/GraphStoreConstants');
var StockService = require('../utils/StockService');

var GraphActions = {};

  GraphActions.getGraphData = function(request){
    //have the API call here.
    VentureDispatcher.handleViewAction({
      actionType: GraphStoreConstants.GET_GRAPH_DATA,
      data: request
    });
    StockService.getHistoricStockData(request);
  };

  GraphActions.recieveGraphData = function(response){
    VentureDispatcher.handleServerAction({
      actionType: GraphStoreConstants.GRAPH_DATA_RESPONSE,
      response: response
    });
  };

  GraphActions.test = function(){
    console.debug("found this.");
  };

module.exports = GraphActions;




以下是在上述代码中调用该函数的Javascript文件:

var request = require('superagent');
var GraphActions = require('../actions/GraphActions');

var StockService = {

  getHistoricStockData: function(symbol){
      request.post('http://localhost:8080/historicalData')
             .send({
                        "symbol":"GOOG",
                        "from":"2016-06-01",
                        "to":"2016-07-01"
                    })
             .set('Content-Type','application/json')
             .end(function(err,res){
               if(err || !res.ok){
                  console.error('Error making request!');
               }else {
                  console.debug(JSON.stringify(res.body));
                  GraphActions.recieveGraphData(res.body);
              }
            });
  }
};

module.exports = StockService;




控制台抛出以下错误,但不太确定原因:
venture-stock.js:44673未捕获的TypeError:GraphActions.recieveGraphData不是函数。

有谁知道为什么会这样?相同的方法已在另一个位置成功调用。

在上面的代码中调试代码并评估GraphAction对象时,我得到以下内容,其中上面定义的功能不可用:

javascript - 未捕获的TypeError:<function>不是函数-LMLPHP

在其他位置,这些功能可用:

javascript - 未捕获的TypeError:<function>不是函数-LMLPHP

任何帮助,将不胜感激!

最佳答案

发生这种情况是由于模块之间存在循环引用。模块GraphActions需要模块StockService,该模块也需要GraphActionsStockService中实际需要的是recieveGraphData方法都没有关系,而需要StockService的方法是getGraphData:模块加载器没有这种级别的代码分析。 require将始终返回整个模块,因此它是一个循环引用。

那么,在这些情况下会发生什么?

模块加载器在加载GraphActions时遇到require('../utils/StockService'),然后停止执行GraphActions以便加载StockService。此时,GraphActions的导出属性为...无。这就是为什么在StockService中得到一个空对象的原因。

解决方案A

将两个模块合并为一个,例如

var GraphService = {
    getGraphData: function(request) {
        ...
        GraphService.getHistoricStockData(request);
    },
    recieveGraphData: function(response) { ... },
    getHistoricStockData: function(symbol) {
        ...
        GraphService.recieveGraphData(res.body);
    }
};
module.exports = GraphService;


解决方案B

相反,即在两个不同的模块中解耦getGraphDatarecieveGraphData。我真的不喜欢这个,因为它可能导致过多的模块碎片。

解决方案C(推荐)

只要使用CommonJS,就可以在任何需要的地方利用require的优势,因此在StockService.js中您可以这样做:

getHistoricStockData: function(symbol) {
    request.post('http://localhost:8080/historicalData')
        ...
        .end(function(err, res) {
            ...
            var GraphActions = require('../actions/GraphActions');
            GraphActions.recieveGraphData(res.body);
        });
}


现在,由于执行不会立即需要GraphActions,因此将在模块的所有依赖项完全加载后再加载该模块,因此您将获得一个完全正常工作的模块。

ES2015模块的差异

在ES6中,您不能在根级别之外使用import,即您不能在函数内部使用import。因此,您不能将解决方案C与ES6语法一起使用?

实际上,一开始就没有必要,因为CommonJS模块的分辨率不同于ES6的分辨率,后者更为先进。因此,您将编写:

import * as StockService from '../utils/StockService';
...
export function getGraphData(request) {
    ...
    StockService.getHistoricStockData(request);
};
export function recieveGraphData(response) { ... };
export function test() { ... };


并在StockService.js中:

import * as GraphActions from '../actions/GraphActions';
...
export function getHistoricStockData(symbol) {
    request.post('http://localhost:8080/historicalData')
        .send( ... )
        .set('Content-Type','application/json')
        .end(function(err, res) {
             ...
             GraphActions.recieveGraphData(res.body);
        });
};


那么这里发生了什么?加载GraphActions.js,到达import语句,模块的执行停止,然后加载StockService。到目前为止,它与CommonJS相同。

StockService中,加载程序将满足import语句,然后恢复执行GraphActions,并且正确导出了整个模块。因此,从一开始使用ES6便会变得无与伦比。

这将导致我们

解决方案D(如果可以的话,建议使用...)

由于您已经在使用Babel,请使用插件“ transform-es2015-modules-commonjs”或“ preset-es2015”并使用ES6模块。

希望这能消除您的疑虑!

(顺便说一句,它是“接收”,而不是“接收”;)

关于javascript - 未捕获的TypeError:<function>不是函数,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/38557550/

10-11 12:36