我需要存储一个点列表,并检查该列表中是否已包含新点
class Point {
x: number;
y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
}
window.onload = () => {
var points : Point[] = [];
points.push(new Point(1,1));
var point = new Point(1,1);
alert(points.indexOf(point)); // -1
}
显然,打字稿使用引用比较,但在这种情况下没有意义。在Java或C#中,我会使用似乎不可能的typescript重载equals
方法。
我考虑使用foreach
遍历数组并检查每个条目是否相等,但这看起来相当复杂并且会使代码膨胀。
打字稿中是否有类似equals
的内容?我怎样才能实现自己的比较?
答案 0 :(得分:3)
你可以做的一件事就是试试linq.js。有了这个,你可以这样做:
var foundPoint = Enumerable.From(points)
.SingleOrDefault(function(p) {
return p.x == targetX && p.y == targety;
});
...然后你可以在你的对象上实现这个功能
class Point {
x: number;
y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
static equals(points: Point[], candidate: Point): boolean {
var foundPoint = Enumerable.From(points)
.SingleOrDefault((p: Point): boolean => {
return p.x == candidate.x && p.y == candidate.y;
});
return foundPoint != null;
}
}
...并像这样使用
var points = createPointsArray();
var point = getSomePoint();
// is point already in array?
var isPointInPoints = Point.equals(points, point)
答案 1 :(得分:2)
Typescript不会向JavaScript添加任何功能。它只是“打字”和一些语法改进。
所以,没有办法以与你在C#中所做的相同的方式覆盖equals
。
但是,您最终可能会使用C#中的Hash
或强类型Dictionary
来执行高效查找(除了可能的数组),而不是使用“索引” “功能。
为此,我建议您使用关联数组结构来存储Point
。
你会做类似的事情:
class Point {
constructor(public x:Number = 0,
public y:Number = 0 ) {
}
public toIndexString(p:Point):String {
return Point.pointToIndexString(p.x, p.y);
}
static pointToIndexString(x:Number, y:Number):String {
return x.toString() + "@" + y.toString();
}
}
var points:any = {};
var p: Point = new Point(5, 5);
points[p.toIndexString()] = p;
如果Point
不存在,则检查points
关联数组将返回undefined
。
包装数组的函数很简单:
function findPoint(x:Number, y:Number):Point {
return points[Point.pointToIndexString(x, y)];
}
循环所有点很容易:
// define the callback (similar in concept to defining delegate in C#)
interface PointCallback {
(p:Point):void;
}
function allPoints(callback:PointCallback):void {
for(var k in points) {
callback(points[k]);
}
}
allPoints((p) => {
// do something with a Point...
});
答案 2 :(得分:1)
您可以将集合包装在PointList
中,只允许通过Point
方法添加add
个对象,该方法会检查以确保不会添加重复项。
这有利于将“无重复”规则封装在一个地方,而不是希望所有调用代码在添加副本之前检查,这会在很多地方复制规则。
class Point {
constructor(public x: number, public y: number) {
}
}
class PointList {
private points: Point[] = [];
get length() {
return this.points.length;
}
add(point: Point) {
if (this.exists(point)) {
// throw 'Duplicate point';
return false;
}
this.points.push(point);
return true;
}
exists(point: Point) {
return this.findIndex(point) > -1;
}
findIndex(point: Point) {
for (var i = 0; i < this.points.length; i++) {
var existingPoint = this.points[i];
if (existingPoint.x === point.x && existingPoint.y === point.y) {
return i;
}
}
return -1;
}
}
var pointList = new PointList();
var pointA = new Point(1, 1);
var pointB = new Point(1, 1);
var pointC = new Point(1, 2);
pointList.add(pointA);
alert(pointList.length); // 1
pointList.add(pointB);
alert(pointList.length); // 1
pointList.add(pointC);
alert(pointList.length); // 2
答案 3 :(得分:0)
我会实现我自己的比较方法。在这种情况下,我将扩展 Array.prototype
- 除非您确切知道自己在做什么,否则我不建议这样做 - 但是您可以很好地创建自己的类,该类继承自 Array
并实现 { {1}} 方法类似于下面定义的方法。
.contains()
interface Equatable {
/**
* Returns `true` if the two objects are equal, `false` otherwise.
*/
equals(object: any): boolean
}
class Point implements Equatable {
public equals(toPoint: Point): boolean {
return this.x === toPoint.x && this.y === toPoint.y;
}
}
// Augment the global scope
declare global {
interface Array<T extends Equatable> {
/**
* Returns `true` if an object is found, `false` otherwise. This method uses the `.equals()` method to compare `Equatable` objects for equality.
*/
contains(object: T): boolean
}
}
// Extend the Array.prototype.
Array.prototype.contains = function(object: Equatable) {
return this.findIndex(element => {
return element.equals(object);
}) !== -1;
}
接口允许您将此行为扩展到任何其他对象:
Equatable