意外的“未捕获的TypeError:XXX不是构造函数”错误与Babel和ES6

polhcujo  于 2022-12-08  发布在  Babel
关注(0)|答案(8)|浏览(186)

我正在尝试Webpack,并且正在尝试this tutorial中的说明,给予或取一些自定义的东西。
这是简单的代码,真的,但我很困惑这个错误,并觉得这是一些愚蠢的,我错过了。
我定义了两个ES6类,每个类对应一个Handlebars模板,应用程序的入口点应该用它们的内容替换索引文件中的占位符HTML:

进入点:

import './bloj.less'

// If we have a link, render the Button component on it
if (document.querySelectorAll('a').length) {
    require.ensure([], () => {
        const Button = require('./Components/Button.js');
        const button = new Button('9gag.com');

        button.render('a');
    }, 'button');
}

// If we have a title, render the Header component on it
if (document.querySelectorAll('h1').length) {
    require.ensure([], () => {
        const Header = require('./Components/Header.js');

        new Header().render('h1');
    }, 'header');
}

索引:

<!DOCTYPE html>
<html>
<head>
</head>
<body>
    <h1>My title</h1>
    <a>Click me</a>

    <script src="build/bloj.js"></script>
</body>
</html>

按钮:

import $ from 'jquery';
import './Button.less';

export default class Button {

    constructor(link) {
        this.link = link;
    }

    onClick(event) {
        event.preventDefault();
        alert(this.link);
    }

    render(node) {
        const text = $(node).text();
        var compiled = require('./Button.hbs');

        // Render our button
        $(node).html(
            compiled({"text": text, "link": this.link})
        );

        // Attach our listeners
        $('.button').click(this.onClick.bind(this));
    }
}

标题:

import $ from 'jquery';
import './Header.less';

export default class Header {
    render(node) {
        const text = $(node).text();
        var compiled = require('./Header.hbs');

        // Render the header
        $(node).html(
            compiled({"text": text})
        );
    }
}

遗憾的是,它不起作用,当显示页面时,我得到了这两个错误:

Uncaught TypeError: Header is not a constructor
Uncaught TypeError: Button is not a constructor

"我会错过什么"
以下是我的Webpack配置:

var path = require('path');
var webpack = require('webpack');
var CleanPlugin = require('clean-webpack-plugin');
var ExtractPlugin = require('extract-text-webpack-plugin');

var production = process.env.NODE_ENV === 'production';
var appName = 'bloj';
var entryPoint = './src/bloj.js';
var outputDir =  './build/';
var publicDir = './build/';

// ************************************************************************** //

var plugins = [
    //new ExtractPlugin(appName + '.css', {allChunks: true}),
    new CleanPlugin(outputDir),
    new webpack.optimize.CommonsChunkPlugin({
        name:      'main',
        children:  true,
        minChunks: 2
    })
];

if (production) {
    plugins = plugins.concat([
        new webpack.optimize.DedupePlugin(),
        new webpack.optimize.OccurenceOrderPlugin(),
        new webpack.optimize.MinChunkSizePlugin({
            minChunkSize: 51200 // 50ko
        }),
        new webpack.optimize.UglifyJsPlugin({
            mangle:   true,
            compress: {
                warnings: false // Suppress uglification warnings
            }
        }),
        new webpack.DefinePlugin({
            __SERVER__:      false,
            __DEVELOPMENT__: false,
            __DEVTOOLS__:    false,
            'process.env':   {
                BABEL_ENV: JSON.stringify(process.env.NODE_ENV)
            }
        })
    ]);
}

module.exports = {
    entry:  entryPoint,
    output: {
        path:     outputDir,
        filename: appName + '.js',
        chunkFilename: '[name].js',
        publicPath: publicDir
    },
    debug:   !production,
    devtool: production ? false : 'eval',
    module: {
        loaders: [
            {
                test: /\.js/,
                loader: "babel",
                include: path.resolve(__dirname, 'src'),
                query: {
                    presets: ['es2015']
                }
            },
            {
                test: /\.less/,
                //loader: ExtractPlugin.extract('style', 'css!less')
                loader: "style!css!less"
            },
            {
                test:   /\.html/,
                loader: 'html'
            },
            {
                test: /\.hbs/,
                loader: "handlebars-template-loader"
            }
        ]
    },
    plugins: plugins,
    node: {
        fs: "empty" // Avoids Handlebars error messages
    }
};
bpzcxfmw

bpzcxfmw1#

我还能错过什么?
Babel将默认导出分配给default属性。因此,如果使用require导入ES6模块,则需要访问default属性:

const Button = require('./Components/Button.js').default;
e37o9pze

e37o9pze2#

我知道你已经有了答案。但是我也有一个类似的问题,我找到了答案。开始我自己的问题,并回答它似乎很奇怪。所以我只是要离开这里。
我遇到了和你一样的错误。不过,我设法通过更改我的

export default {Class}

export default Class

我不知道为什么我把类 Package 在一个对象中,但我记得在什么地方见过它,所以我就开始使用它。
因此,它返回了一个{Class: Class}这样的对象,而不是默认的返回一个类。这是完全有效的,但它将打破webpack+babel。
编辑:我后来知道了为什么这可能会破坏babel+webpack。export default意味着只有一个导出。一个javascript对象可以包含很多属性。这意味着它可以有不止一个导出。(参见:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export)的数据。
对于多个导出,请用途:export {definition1, definition2} .
用例:我在创建一个导出不同类型编辑器的库时使用了这个方法(虽然底层代码是相同的,但编辑器的外观会根据您使用的导出而变化)。

iezvtpos

iezvtpos3#

您可以在导出类后输入export var __useDefault = true;

export default class Header {
...
} 
export var __useDefault = true;
yjghlzjz

yjghlzjz4#

我可以通过将babel-plugin-add-module-exports添加到.babelrc文件中来修复此问题
npm install babel-plugin-add-module-exports --save-dev

{
  "presets": ["@babel/env"],
  "plugins": ["add-module-exports"]
}

这增加了

module.exports = exports.default;

到最后一行。

7kqas0il

7kqas0il5#

虽然这不是您的特定问题的原因,但我在尝试从使用ES6的importexport语法的现有节点应用程序中剥离babel时遇到了一个非常类似的问题,所以这篇文章是为了帮助将来遇到这个问题的其他人。
Babel将解决一个模块与另一个模块之间的任何循环依赖关系,因此您可以随意使用ES6的importexport。您需要将任何importexports替换为require。这可能会重新引入babel在后台处理的潜在循环引用问题。如果您发现自己处于这种情况,请在代码中查找如下所示的区域:
文件A:

const B = require('B');

class A {
  constructor() {
    this.b = new B();
  }
}
module.exports = A;

文件B:

const A = require('A'); // this line causes the error

class B {
  constructor() {
    this.a = new A();
  }
}
module.exports = B;

有几种不同的方法可以解决这个问题,这取决于你的代码结构。最简单的方法可能是给B传递一个对A的引用,而不是创建A类的一个新示例。你也可以在加载A时动态解析引用。还有很多其他的方法,但这里是一个很好的开始。

kcwpcxri

kcwpcxri6#

这不是这个特定问题的问题,但由于某些原因,巴别塔没有在同一个文件中提升类。
所以如果你在文件的顶部声明你的类Token,然后写new Token(),它就会运行。
如果在构造函数调用之后声明类,则会出现xxx不是构造函数错误

cnh2zyt3

cnh2zyt37#

我收到了同样的错误消息,并发现原因是循环导入语句。即:我有两个相互导入的文件,其中一个文件包含一个export default class,该文件包含一个依赖于另一个文件中的export function的方法。我的解决方案是将其中一个依赖项(函数)移出类,放入一个utils.js文件中,无论如何,这是一个更合适的位置!

bhmjp9jg

bhmjp9jg8#

这是我使用/导入类的方式:

实用程序类js

export default class Utils {
    somefunction(val) {
        return val
    }
}

在我的控制器中使用实用程序:

import {default as U} from '../helpers/Utils.class';
const Utils = new U();

console.log(Utils.somefunction(123));

相关问题