这两个小型JavaScript类的最佳OOP方法

时间:2012-07-01 17:13:47

标签: javascript oop design-patterns

我正在开始一个相当大的JS项目的工作,并希望确保我干净,高效地构建代码。我一直在阅读大量关于JS中OOP的不同方法,但没有找到我真正喜欢的方法。

我很欣赏使用prototype属性提供的性能改进,但是当您尝试将真正的私有方法和变量添加到混合中时,它会变得相当混乱。另一方面,我非常喜欢closure方法,但我对降低的性能感到不满意。我查看了module模式,但发现它非常详细。某处是否有幸福的媒介?

为了说明我正在努力解决的问题,这里有两个非常小的样本类:

点类:

function Point(x, y) {
  this.x = x;
  this.y = y;
}

// Get the x coordinate.
Point.prototype.getX = function() {
  return this.x;
}

// Get the y coordinate.
Point.prototype.getY = function() {
  return this.y;
}

// Get the (x, y) coordinate.
Point.prototype.getXY = function() {
  return {x: this.x, y: this.y};
}

// Set the x coordinate.
Point.prototype.setX = function(x) {
  this.x = x;
}

// Set the y coordinate.
Point.prototype.setY = function(y) {
  this.y = y;
}

// Set the (x, y) coordinate.
Point.prototype.setXY = function(x, y) {
  this.x = x;
  this.y = y;
}

用户类:

function User(guid) {
  var guid = guid;

  // Return the user's GUID.
  this.getGuid = function() {
    return guid;    
  }
}

在任何一个给定时间内可能会有数千个点对象在使用,所以我觉得prototype方法是那里的最佳选择。但是,如果我想在坐标设置中添加任何验证,只需调用Point.x = <value>就可以绕过它。同样,我可能会在大多数时间调用Point.getXY(),这将构建基本上属于公共属性的新对象。我应该摆脱Point类的getter和setter的概念,让它创建完全开放的公共对象吗?在OOP的背景下,这似乎是错误的。

对于User类,我想在内部存储一个GUID,以便可以请求但从不修改。使用prototype方法无法完成此操作(除非我遗漏了某些内容),因此我不得不使用某种closure。我预见一次有数百名用户在运行,因此性能不如Point类那么重要。但是,我并不想在整个代码库中切换不同类型的OOP样式。

所以,作为一个普遍的问题,是否有一种方法可以解决JS中的OOP问题,这种方法可以让我在清除私有化选择函数和变量的同时使用prototype属性?或者,我是否朝错误的方向看?我应该以不同的方式接近这个吗?

4 个答案:

答案 0 :(得分:1)

您只能使用_前缀等文档和约定将方法标记为“内部”,但javascript中没有真正的强制私有对象成员。

闭包是不可接受的 - 它们将拥有数据而不是可能具有“有趣”结果的对象,尤其是当想要以这种方式使用闭包来扩展“类”时。 另一点是你将使用O(n)内存来存储所有的功能对象,如果它对于库的用户来说是不受控制的,那么它可以非常容易地使用库,从而导致记忆问题。

您可以像下面这样使用下划线前缀约定:

function Point(x, y) {
  this._x = x;
  this._y = y;
}

// Get the x coordinate.
Point.prototype.getX = function() {
  return this._x;
}

// Get the y coordinate.
Point.prototype.getY = function() {
  return this._y;
}

答案 1 :(得分:0)

我不知道你的背景但可能是oop,所以请查看coffee-script

答案 2 :(得分:0)

由于基于原型的面向对象不是真正的面向对象,我想你可能看错了地方。

基于原型的对象是它们子类的任何克隆。因此,如果您声明您的对象具有属性getXY(),那么它对从中克隆的任何内容都是开放的。

所以我想真正的问题是,您认为私人功能会在此实施中为您带来什么?

如果你真的需要私人功能,我会鼓励你处理你在封闭模式中必须处理的混乱。

答案 3 :(得分:0)

您可以在开发期间使用闭包方法,因此您知道没有人绕过验证,然后在发布代码时切换到更快的原型方法。

var Release = true;
if (Release) {
    function Point(x, y) {
        this.x = x;
        this.y = y;
    }

    // Get the x coordinate.
    Point.prototype.getX = function () {
        return this.x;
    }

    // Get the y coordinate.
    Point.prototype.getY = function () {
        return this.y;
    }

    // Get the (x, y) coordinate.
    Point.prototype.getXY = function () {
        return {
            x: this.x,
            y: this.y
        };
    }

    // Set the x coordinate.
    Point.prototype.setX = function (x) {
        this.x = x;
    }

    // Set the y coordinate.
    Point.prototype.setY = function (y) {
        this.y = y;
    }

    // Set the (x, y) coordinate.
    Point.prototype.setXY = function (x, y) {
        this.x = x;
        this.y = y;
    }
} else {
    function Point(x, y) {
        var _x = x,
            _y = y;
        return {
            // Get the x coordinate.
            getX: function () {
                return _x;
            },

            // Get the y coordinate.
            getY: function () {
                return _y;
            },

            // Get the (x, y) coordinate.
            getXY: function () {
                return {
                    x: _x,
                    y: _y
                };
            },

            // Set the x coordinate.
            setX: function (x) {
                _x = x;
            },

            // Set the y coordinate.
            setY: function (y) {
                _y = y;
            },

            // Set the (x, y) coordinate.
            setXY: function (x, y) {
                _x = x;
                _y = y;
            }
        }
    }
}