未捕获的类型错误:<function> 不是函数

Mat*_*nMV 0 javascript webpack

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

我有以下代码(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;
Run Code Online (Sandbox Code Playgroud)

以下 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;
Run Code Online (Sandbox Code Playgroud)

控制台抛出以下错误并且不太确定原因 : Venture-stock.js:44673 Uncaught TypeError: GraphActions.recieveGraphData is not a function。

有谁明白为什么会这样?在另一个地方调用相同的方法没有问题。

在上面代码中调试代码和评估 GraphAction 对象时,我得到以下信息,上面定义的函数不可用:

在此处输入图片说明

在其他位置,功能可用:

在此处输入图片说明

任何帮助,将不胜感激!

Max*_*Art 6

这是因为您的模块之间存在循环引用。模块GraphActions需要模块StockService,模块需要GraphActions. 如果什么实际需要在不要紧,StockService它的recieveGraphData方法,而需要的方法StockServicegetGraphData:模块加载没有这个级别的代码分析。require总是会返回整个模块,所以它是一个循环引用。

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

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

方案一

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

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

方案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);
        });
}
Run Code Online (Sandbox Code Playgroud)

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

与 ES2015 模块的区别

在 ES6 中,不能import在根级别之外使用,即不能import在函数内部使用。所以你不能用 ES6 语法使用解决方案 C?

其实一开始就没有必要,因为 CommonJS 模块解析与 ES6 不同,后者更高级。所以,你会写:

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

并在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);
        });
};
Run Code Online (Sandbox Code Playgroud)

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

StockService,加载器会遇到import语句,然后执行GraphActionsresume,整个模块被正确导出。所以从 ES6 开始,你就会成为金子。

这将导致我们

解决方案 D(最推荐...如果可以的话)

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

希望这能解开你的疑惑!

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