如何在不污染String.prototype的情况下继承和链接String?

时间:2013-12-19 17:46:05

标签: javascript string inheritance prototype chaining

我希望能做的是这样的事情:

var where = new Where();
where('a'); // returns a string 'WHERE a' that I can chain against

where('a').andWhere('b'); // reuturns 'WHERE a AND b' that is also chainable

where('a').andWhere('b').orWhere('c'); // 'WHERE a AND b OR c', and so on ...

where方法应返回所有意图和目的的字符串,包含所有类似字符串的方法,但使用两种自定义andWhereorWhere方法。

当我尝试从Sting.prototype继承时,我的where方法返回了一个对象,而不是一个字符串。当然,如果我直接从方法返回一个字符串,它们没有andWhereorWhere方法,所以链接破坏了。

下面的代码实现了我想要的,但它通过污染String.prototype来实现。有没有办法获得相同的行为,但是封装在自定义对象中?

Object.defineProperty(String.prototype, "andWhere", {
  value: function _andWhere(clause) {
    return [this, 'AND', clause].join(' ');
  },
  configurable: true,
  enumerable: false,
  writeable: true
});

Object.defineProperty(String.prototype, "orWhere", {
  value: function _orWhere(clause) {
    return [this, 'OR', clause].join(' ');
  },
  configurable: true,
  enumerable: false,
  writeable: true
});


function where(clause){
  return ['WHERE', clause].join(' ');
}

where('a').andWhere('b').orWhere('c');
// => 'WHERE a AND b OR c'

修改

我仍然希望直接访问该对象的所有字符串方法。换句话说,返回的对象就像一个字符串,但有几个方法。例如:

var whereStr = where('a').andWhere('b').orWhere('c');
whereStr.length; // => 18
whereStr.concat(' and so on'); // => 'WHERE a AND b OR c and so on'

如果它有任何区别,这主要是针对Node,但理想情况下适用于任何最近的(ES5)javascript实现。再次,如果我很糟糕并且使用String.prototype,这可以完美地运行,我希望有一种方法可以替换掉。

1 个答案:

答案 0 :(得分:4)

更新在将“长度”属性创建为“getter”的示例中添加。

function Where(conditional) {
    var thisObj = this;

    //Setup the length property's "getter"
    this.__defineGetter__( "length", function() {
        return thisObj.clause.length;
    });

    this.start( conditional );
}

Where.prototype = {
    AND_STR: " AND ",
    OR_STR: " OR ",
    add: function(conditional, prefix) {
        this.clause += prefix + conditional;
    },
    and: function(conditional) {
        this.add( conditional, this.AND_STR ); 
        return this;
    },
    or: function(conditional) { 
        this.add( conditional, this.OR_STR ); 
        return this;
    },
    start: function(conditional) {
        this.clause = "WHERE " + conditional;
    },
    toString: function() {
        return this.clause;
    }
}

//Use it like this (this shows the length of the where statement):
alert( new Where( "a" ).and( "b" ).or( "c" ).length );