打字稿:避免参考比较

时间:2014-01-28 13:07:26

标签: javascript web reference comparison typescript

我需要存储一个点列表,并检查该列表中是否已包含新点

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的内容?我怎样才能实现自己的比较?

4 个答案:

答案 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