[英]Extending Built-in Array With ES6 Classes - Method is not a function error
我正在尝试扩展内置数组 class 并创建基于自定义 collections 的本机数组 class。
我可以使用自定义名称创建集合,效果很好,但我不能使用我的自定义方法。 如果我使用 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;
};
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'));
为了回答您修改后的问题,TypeScript 不允许您扩展内置函数,如Array
、 Error
等。原因写在这里。
在 ES2015 中,返回 object 的构造函数隐式地将 this 的值替换为 super(...) 的任何调用者。 生成的构造函数代码必须捕获 super(...) 的任何潜在返回值并将其替换为 this。
因此,子类化 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'));
但是,如果我们将tsconfig.json
中的target
设置为等于或大于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。
我可以看到您缺少一些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'));
不会产生任何错误
这是您编写 function 的方式导致错误
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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.