Javascript Babel 和 ES6 出现意外的“Uncaught TypeError: XXX is not a constructor”错误

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/36388766/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 18:59:31  来源:igfitidea点击:

Unexpected "Uncaught TypeError: XXX is not a constructor" errors with Babel and ES6

javascriptecmascript-6webpackbabeljs

提问by Silver Quettier

I am giving a try to Webpack, and am giving a try to the instructions in this tutorial, give or take a few custom things.

我正在尝试 Webpack,并且正在尝试本教程中的说明,提供或接受一些自定义的东西。

This is simple code, really, but I'm quite puzzled about this error, and feel this is something silly that I missed.

这是一个简单的代码,真的,但我对这个错误感到很困惑,觉得这是我错过的一些愚蠢的事情。

I defined two ES6 classes, each corresponding to a Handlebars template, and my app's entrypoint is supposed to replace the placeholder HTML in the index file by their contents:

我定义了两个 ES6 类,每个类对应一个 Handlebars 模板,我的应用程序的入口点应该用它们的内容替换索引文件中的占位符 HTML:

Entrypoint:

入口点:

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');
}

Index:

指数:

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

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

Button:

按钮:

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));
    }
}

Header:

标题:

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})
        );
    }
}

Sadly, it does not work, and I get both these errors when displaying the page:

可悲的是,它不起作用,并且在显示页面时出现这两个错误:

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

What could I be missing?

我可能会错过什么?

Here is my webpack configuration:

这是我的 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
    }
};

回答by Felix Kling

What could I be missing?

我可能会错过什么?

Babel assigns default exports to the defaultproperty. So if you use requireto import ES6 modules, you need to access the defaultproperty:

Babel 将默认导出分配给default属性。所以如果你使用require导入 ES6 模块,你需要访问该default属性:

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

回答by Byebye

I realize that you already have an answer. However I had a similar issue to which I found an answer. Starting my own question and answering it seems weird. So I'm just going to leave this here.

我知道你已经有了答案。但是我有一个类似的问题,我找到了答案。开始我自己的问题并回答它似乎很奇怪。所以我只想把它放在这里。

I had the same error as you got. However, I managed to solve it by changing my

我有和你一样的错误。但是,我设法通过改变我的

export default {Class}

to

export default Class

I don't know why I wrapped the Class in an object but I remember having seen it somewhere so I just started using it.

我不知道为什么我将 Class 包装在一个对象中,但我记得在某处看到过它,所以我才开始使用它。

So instead of the default returning a Class it returned an object like this {Class: Class}. This is completely valid yet it will break webpack+babel.

因此,它返回一个像这样的对象,而不是默认返回一个 Class {Class: Class}。这是完全有效的,但它会破坏 webpack+babel。

EDIT: I've since come to know why this probably breaks babel+webpack. The export defaultis meant to only have 1 export. A javascript-object can contain many properties. Which means it can have more than 1 export. (See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export).

编辑:我后来知道为什么这可能会破坏 babel+webpack。这export default意味着只有 1 个出口。一个 javascript 对象可以包含许多属性。这意味着它可以有 1 个以上的出口。(参见:https: //developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export)。

For multiple exports use: export {definition1, definition2}.

对于多个导出使用:export {definition1, definition2}.

Use-case: I've used this in a situation where I've created a library which exported different types of an editor (while the underlying code was the same, the appearance of the editor changes depending on which export you use).

用例:我在创建一个导出不同类型编辑器的库的情况下使用了它(虽然底层代码相同,但编辑器的外观会根据您使用的导出而变化)。

回答by maufarinelli

You can just put export var __useDefault = true;just after exporting your Class.

您可以export var __useDefault = true;在导出类后立即放置。

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

回答by Nicolas Zozol

It's not the problem in this particular question, but for some reasons, babel does not hoist classes in the same file.

这不是这个特定问题的问题,但由于某些原因,babel 不会在同一个文件中提升类。

So if you declare your class Tokenat the top of the file, and write later new Token(), it will run.

因此,如果您Token在文件顶部声明您的类,并稍后写入new Token(),它将运行。

If you declare your class after the constructor call, you will have the xxx is not a constructorerror

如果在构造函数调用后声明类,则会出现xxx is not a constructor错误

回答by seantomburke

I was able to fix this by adding babel-plugin-add-module-exportsto the .babelrcfile

我能够通过添加babel-plugin-add-module-exports.babelrc文件来解决这个问题

npm install babel-plugin-add-module-exports --save-dev

npm install babel-plugin-add-module-exports --save-dev

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

this adds

这增加了

module.exports = exports.default;

to the last line when compiling the class with babel.

使用 babel 编译类时到最后一行。

回答by xtro

Although this is not the cause of your particular issue, I ran into a very similar problem when trying to rip babel out of an existing node app that was using ES6's importand exportsyntax, so this post is to help out anyone else struggling with this in the future.

虽然这不是您的特定问题的原因,但我在尝试从使用 ES6importexport语法的现有节点应用程序中提取 babel 时遇到了一个非常相似的问题,因此这篇文章是为了帮助其他人在未来。

Babel will resolve any circular dependencies between one module and another, so you can use ES6's importand exportwith reckless abandon. However, if you need to get rid of babel and use native node, you will need to replace any importand exportswith require. This can reintroduce a latent circular reference issues that babel was taking care of in the background. If you find yourself in this situation, look for an area in your code that looks like this:

Babel 将解决一个模块和另一个模块之间的任何循环依赖关系,因此您可以使用 ES6import并且export不计后果地放弃。但是,如果您需要摆脱 babel 并使用本机节点,则需要将 anyimport和替换exportsrequire. 这可能会重新引入 babel 在后台处理的潜在循环引用问题。如果您发现自己处于这种情况,请在代码中查找如下所示的区域:

File A:

文件A:

const B = require('B');

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

File B:

文件乙:

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

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

There are several different ways to resolve this issue depending on how you structured your code. The easiest way is probably to pass Ba reference to Ainstead of creating a new instance of class A. You could also dynamically resolve the reference when loading A. There are a myriad of other alternatives, but this is a good place to get started.

根据您构建代码的方式,有几种不同的方法可以解决此问题。最简单的方法可能是传递B一个引用A而不是创建一个新的 class 实例A。您还可以在加载时动态解析引用A。还有无数其他选择,但这是开始的好地方。