猿问

Extending Built-in Array With ES6 Classes

我正在尝试扩展内置数组类并创建基于本机数组类的自定义集合。


我可以使用自定义名称创建集合,效果很好,但我无法使用我的自定义方法。如果我使用 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 function

ES5降级


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;

};

森栏
浏览 125回答 3
3回答

慕神8447489

更新的答案要回答您修改后的问题,TypeScript 不允许您扩展内置函数Array等Error。原因写在这里。在 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 {&nbsp; &nbsp; name: string;&nbsp; &nbsp; weight: number}class AnimalCollection extends Array <Animal> {&nbsp; &nbsp; constructor(name: string, ...items: Animal[]) {&nbsp; &nbsp; &nbsp; &nbsp; super(...items);&nbsp; &nbsp; &nbsp; &nbsp; Object.defineProperty(this, 'name', {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; enumerable: false,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; writable: false,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value: name&nbsp; &nbsp; &nbsp; &nbsp; })&nbsp; &nbsp; }&nbsp; &nbsp; findAnimal(name:string): Animal | null {&nbsp; &nbsp; &nbsp; &nbsp; return this.find(a => a.name === name) || null;&nbsp; &nbsp; }}const animalsArray = [&nbsp; &nbsp; {name: 'TD-23', weight: 60},&nbsp; &nbsp; {name: 'TD-25', weight: 50},&nbsp; &nbsp; {name: 'TXD-26', weight: 120},&nbsp; &nbsp; {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 () {&nbsp; &nbsp; var extendStatics = function (d, b) {&nbsp; &nbsp; &nbsp; &nbsp; extendStatics = Object.setPrototypeOf ||&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };&nbsp; &nbsp; &nbsp; &nbsp; return extendStatics(d, b);&nbsp; &nbsp; };&nbsp; &nbsp; return function (d, b) {&nbsp; &nbsp; &nbsp; &nbsp; extendStatics(d, b);&nbsp; &nbsp; &nbsp; &nbsp; function __() { this.constructor = d; }&nbsp; &nbsp; &nbsp; &nbsp; d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());&nbsp; &nbsp; };})();var __spreadArrays = (this && this.__spreadArrays) || function () {&nbsp; &nbsp; for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;&nbsp; &nbsp; for (var r = Array(s), k = 0, i = 0; i < il; i++)&nbsp; &nbsp; &nbsp; &nbsp; for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; r[k] = a[j];&nbsp; &nbsp; return r;};var AnimalCollection = /** @class */ (function (_super) {&nbsp; &nbsp; __extends(AnimalCollection, _super);&nbsp; &nbsp; function AnimalCollection(name) {&nbsp; &nbsp; &nbsp; &nbsp; var items = [];&nbsp; &nbsp; &nbsp; &nbsp; for (var _i = 1; _i < arguments.length; _i++) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; items[_i - 1] = arguments[_i];&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; var _this = _super.apply(this, items) || this;&nbsp; &nbsp; &nbsp; &nbsp; Object.defineProperty(_this, 'name', {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; enumerable: false,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; writable: false,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value: name&nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp; return _this;&nbsp; &nbsp; }&nbsp; &nbsp; AnimalCollection.prototype.findAnimal = function (name) {&nbsp; &nbsp; &nbsp; &nbsp; return this.find(function (a) { return a.name === name; }) || null;&nbsp; &nbsp; };&nbsp; &nbsp; return AnimalCollection;}(Array));var animalsArray = [&nbsp; &nbsp; { name: 'TD-23', weight: 60 },&nbsp; &nbsp; { name: 'TD-25', weight: 50 },&nbsp; &nbsp; { name: 'TXD-26', weight: 120 },&nbsp; &nbsp; { 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 {&nbsp; &nbsp; constructor(name, ...items) {&nbsp; &nbsp; &nbsp; &nbsp; super(...items);&nbsp; &nbsp; &nbsp; &nbsp; Object.defineProperty(this, 'name', {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; enumerable: false,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; writable: false,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value: name&nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; }&nbsp; &nbsp; findAnimal(name) {&nbsp; &nbsp; &nbsp; &nbsp; return this.find(a => a.name === name) || null;&nbsp; &nbsp; }}const animalsArray = [&nbsp; &nbsp; { name: 'TD-23', weight: 60 },&nbsp; &nbsp; { name: 'TD-25', weight: 50 },&nbsp; &nbsp; { name: 'TXD-26', weight: 120 },&nbsp; &nbsp; { name: 'TYD-26', weight: 40 }];const animals = new AnimalCollection('Deers', ...animalsArray);console.log(animals.findAnimal('TD-23'));这当然有效。所以我认为 ES5 或更低版本的 TypeScript 编译器存在问题,这会破坏实现。我试过使用Babel 进行编译,它适用于 ES5。

慕森卡

导致错误的是您编写函数的方式interface Animal {&nbsp; &nbsp; name: string;&nbsp; &nbsp; weight: number}class AnimalCollection extends Array <Animal> {&nbsp; &nbsp; constructor(name, ...items) {&nbsp; &nbsp; &nbsp; &nbsp; super(...items);&nbsp; &nbsp; &nbsp; &nbsp; Object.defineProperty(this, 'name', {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; enumerable: false,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; writable: false,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value: name&nbsp; &nbsp; &nbsp; &nbsp; })&nbsp; &nbsp; }&nbsp; &nbsp; findAnimal:Animal=(name:String)=> {&nbsp; &nbsp; &nbsp; &nbsp; return this.find(a => a.name === name) || null;&nbsp; &nbsp; }}const animalsArray = [&nbsp; &nbsp; {name: 'TD-23', weight: 60},&nbsp; &nbsp; {name: 'TD-25', weight: 50},&nbsp; &nbsp; {name: 'TXD-26', weight: 120},&nbsp; &nbsp; {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

慕哥9229398

我可以看到你遗漏了一些any,这是对我有用的代码:interface Animal {&nbsp; &nbsp; name: string;&nbsp; &nbsp; weight: number}class AnimalCollection extends Array <Animal> {&nbsp; &nbsp; constructor(name: string, ...items : Array <Animal>) { // <-- missing types&nbsp; &nbsp; &nbsp; &nbsp; super(...items);&nbsp; &nbsp; &nbsp; &nbsp; Object.defineProperty(this, 'name', {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; enumerable: false,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; writable: false,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value: name&nbsp; &nbsp; &nbsp; &nbsp; })&nbsp; &nbsp; }&nbsp; &nbsp; findAnimal(name : any): Animal|null { // <-- missing null&nbsp; &nbsp; &nbsp; &nbsp; return this.find(a => a.name === name) || null;&nbsp; &nbsp; }}const animalsArray = [&nbsp; &nbsp; {name: 'TD-23', weight: 60},&nbsp; &nbsp; {name: 'TD-25', weight: 50},&nbsp; &nbsp; {name: 'TXD-26', weight: 120},&nbsp; &nbsp; {name: 'TYD-26', weight: 40}];const animals = new AnimalCollection('Deers', ...animalsArray)console.log(animals.findAnimal('TD-23'));但是此代码生成以下 JS:"use strict";class AnimalCollection extends Array {&nbsp; &nbsp; constructor(name, ...items) {&nbsp; &nbsp; &nbsp; &nbsp; super(...items);&nbsp; &nbsp; &nbsp; &nbsp; Object.defineProperty(this, 'name', {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; enumerable: false,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; writable: false,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value: name&nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; }&nbsp; &nbsp; findAnimal(name) {&nbsp; &nbsp; &nbsp; &nbsp; return this.find(a => a.name === name) || null;&nbsp; &nbsp; }}const animalsArray = [&nbsp; &nbsp; { name: 'TD-23', weight: 60 },&nbsp; &nbsp; { name: 'TD-25', weight: 50 },&nbsp; &nbsp; { name: 'TXD-26', weight: 120 },&nbsp; &nbsp; { name: 'TYD-26', weight: 40 }];const animals = new AnimalCollection('Deers', ...animalsArray);console.log(animals.findAnimal('TD-23'));这不会产生任何错误
随时随地看视频慕课网APP

相关分类

JavaScript
我要回答