为了账号安全,请及时绑定邮箱和手机立即绑定

Extending Built-in Array With ES6 Classes

Extending Built-in Array With ES6 Classes

森栏 2022-11-27 16:38:22
我正在尝试扩展内置数组类并创建基于本机数组类的自定义集合。我可以使用自定义名称创建集合,效果很好,但我无法使用我的自定义方法。如果我使用 findAnimal 方法,它会给我method is not a function错误。如果我记录收集并检查原型,我看不到我的自定义方法。我意识到我将代码转译为 es5,如果没有,效果很好,ts 编译器的 es5 降级代码会出现问题。如果我们使用 babel 将代码降级为 es5,转译后的代码运行良好。要么是 ts 编译器在转译代码时遗漏了一些东西,要么是我遗漏了一些重要的配置。interface Animal {    name: string;    weight: number}class AnimalCollection extends Array <Animal> {    constructor(name, ...items) {        super(...items);        Object.defineProperty(this, 'name', {            enumerable: false,            writable: false,            value: name        })    }    findAnimal(name): Animal {        return this.find(a => a.name === name) || null;    }}const animalsArray = [    {name: 'TD-23', weight: 60},    {name: 'TD-25', weight: 50},    {name: 'TXD-26', weight: 120},    {name: 'TYD-26', weight: 40}];const animals = new AnimalCollection('Deers', ...animalsArray)console.log(animals.findAnimal('TD-23'));// Uncaught TypeError: animals.findAnimal is not a functionES5降级var __extends = (this && this.__extends) || (function () {    var extendStatics = function (d, b) {        extendStatics = Object.setPrototypeOf ||            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };        return extendStatics(d, b);    };    return function (d, b) {        extendStatics(d, b);        function __() { this.constructor = d; }        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());    };})();var __spreadArrays = (this && this.__spreadArrays) || function () {    for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;    for (var r = Array(s), k = 0, i = 0; i < il; i++)        for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)            r[k] = a[j];    return r;};
查看完整描述

3 回答

?
慕神8447489

TA贡献1780条经验 获得超1个赞

更新的答案

要回答您修改后的问题,TypeScript 不允许您扩展内置函数ArrayError。原因写在这里

在 ES2015 中,返回对象的构造函数隐式地将 this 的值替换为 super(...) 的任何调用者。生成的构造函数代码有必要捕获 super(...) 的任何潜在返回值并将其替换为这个。

因此,子类化 Error、Array 和其他类可能不再按预期工作。这是由于Error、Array等构造函数使用了ECMAScript 6的new.target来调整原型链;但是,在 ECMAScript 5 中调用构造函数时无法确保 new.target 的值。默认情况下,其他下层编译器通常具有相同的限制。

所以如果你必须在 ES5 环境下扩展内置Array,那么你可以尝试使用 Babel 来编译你的代码。但是请注意,它具有此处所述的限制。

由于 ES5(对于 transform-classes 插件)的限制,诸如 Date、Array、DOM 等内置类不能被正确地子类化。你可以尝试使用基于 Object.setPrototypeOf 和 Reflect.construct 的 babel-plugin-transform-builtin-extend,但它也有一些限制。

旧答案

虽然代码本身可以很好地找到并且在浏览器中也可以正常执行,但我认为您遇到的错误是由于 TypeScript 编译器造成的。

对于源代码

interface Animal {

    name: string;

    weight: number

}


class AnimalCollection extends Array <Animal> {

    constructor(name: string, ...items: Animal[]) {

        super(...items);


        Object.defineProperty(this, 'name', {

            enumerable: false,

            writable: false,

            value: name

        })

    }


    findAnimal(name:string): Animal | null {

        return this.find(a => a.name === name) || null;

    }

}


const animalsArray = [

    {name: 'TD-23', weight: 60},

    {name: 'TD-25', weight: 50},

    {name: 'TXD-26', weight: 120},

    {name: 'TYD-26', weight: 40}

];


const animals = new AnimalCollection('Deers', ...animalsArray)


console.log(animals.findAnimal('TD-23'));

如果编译器目标选项设置为ES5,那么它会生成破坏实现的代码。它生成的代码是


"use strict";

var __extends = (this && this.__extends) || (function () {

    var extendStatics = function (d, b) {

        extendStatics = Object.setPrototypeOf ||

            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||

            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };

        return extendStatics(d, b);

    };

    return function (d, b) {

        extendStatics(d, b);

        function __() { this.constructor = d; }

        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());

    };

})();

var __spreadArrays = (this && this.__spreadArrays) || function () {

    for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;

    for (var r = Array(s), k = 0, i = 0; i < il; i++)

        for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)

            r[k] = a[j];

    return r;

};

var AnimalCollection = /** @class */ (function (_super) {

    __extends(AnimalCollection, _super);

    function AnimalCollection(name) {

        var items = [];

        for (var _i = 1; _i < arguments.length; _i++) {

            items[_i - 1] = arguments[_i];

        }

        var _this = _super.apply(this, items) || this;

        Object.defineProperty(_this, 'name', {

            enumerable: false,

            writable: false,

            value: name

        });

        return _this;

    }

    AnimalCollection.prototype.findAnimal = function (name) {

        return this.find(function (a) { return a.name === name; }) || null;

    };

    return AnimalCollection;

}(Array));

var animalsArray = [

    { name: 'TD-23', weight: 60 },

    { name: 'TD-25', weight: 50 },

    { name: 'TXD-26', weight: 120 },

    { name: 'TYD-26', weight: 40 }

];

var animals = new (AnimalCollection.bind.apply(AnimalCollection, __spreadArrays([void 0, 'Deers'], animalsArray)))();

console.log(animals.findAnimal('TD-23'));

但是,如果我们将targetin设置tsconfig.json为等于或大于ES2015,那么它生成的代码是


"use strict";

class AnimalCollection extends Array {

    constructor(name, ...items) {

        super(...items);

        Object.defineProperty(this, 'name', {

            enumerable: false,

            writable: false,

            value: name

        });

    }

    findAnimal(name) {

        return this.find(a => a.name === name) || null;

    }

}

const animalsArray = [

    { name: 'TD-23', weight: 60 },

    { name: 'TD-25', weight: 50 },

    { name: 'TXD-26', weight: 120 },

    { name: 'TYD-26', weight: 40 }

];

const animals = new AnimalCollection('Deers', ...animalsArray);

console.log(animals.findAnimal('TD-23'));

这当然有效。所以我认为 ES5 或更低版本的 TypeScript 编译器存在问题,这会破坏实现。我试过使用Babel 进行编译,它适用于 ES5。


查看完整回答
反对 回复 2022-11-27
?
慕森卡

TA贡献1806条经验 获得超8个赞

导致错误的是您编写函数的方式


interface Animal {

    name: string;

    weight: number

}


class AnimalCollection extends Array <Animal> {

    constructor(name, ...items) {

        super(...items);


        Object.defineProperty(this, 'name', {

            enumerable: false,

            writable: false,

            value: name

        })

    }


    findAnimal:Animal=(name:String)=> {

        return this.find(a => a.name === name) || null;

    }

}


const animalsArray = [

    {name: 'TD-23', weight: 60},

    {name: 'TD-25', weight: 50},

    {name: 'TXD-26', weight: 120},

    {name: 'TYD-26', weight: 40}

];


const animals = new AnimalCollection('Deers', ...animalsArray)


console.log(animals.findAnimal('TD-23'));

// Uncaught TypeError: animals.findAnimal is not a function


查看完整回答
反对 回复 2022-11-27
?
慕哥9229398

TA贡献1877条经验 获得超6个赞

我可以看到你遗漏了一些any,这是对我有用的代码:


interface Animal {

    name: string;

    weight: number

}


class AnimalCollection extends Array <Animal> {

    constructor(name: string, ...items : Array <Animal>) { // <-- missing types

        super(...items);


        Object.defineProperty(this, 'name', {

            enumerable: false,

            writable: false,

            value: name

        })

    }


    findAnimal(name : any): Animal|null { // <-- missing null

        return this.find(a => a.name === name) || null;

    }

}


const animalsArray = [

    {name: 'TD-23', weight: 60},

    {name: 'TD-25', weight: 50},

    {name: 'TXD-26', weight: 120},

    {name: 'TYD-26', weight: 40}

];


const animals = new AnimalCollection('Deers', ...animalsArray)


console.log(animals.findAnimal('TD-23'));

但是此代码生成以下 JS:


"use strict";

class AnimalCollection extends Array {

    constructor(name, ...items) {

        super(...items);

        Object.defineProperty(this, 'name', {

            enumerable: false,

            writable: false,

            value: name

        });

    }

    findAnimal(name) {

        return this.find(a => a.name === name) || null;

    }

}

const animalsArray = [

    { name: 'TD-23', weight: 60 },

    { name: 'TD-25', weight: 50 },

    { name: 'TXD-26', weight: 120 },

    { name: 'TYD-26', weight: 40 }

];

const animals = new AnimalCollection('Deers', ...animalsArray);

console.log(animals.findAnimal('TD-23'));

这不会产生任何错误


查看完整回答
反对 回复 2022-11-27
  • 3 回答
  • 0 关注
  • 124 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信