替换'新'的规则

时间:2012-03-05 03:39:01

标签: javascript prototype

在他的“好的部分”中,克罗克福德建议永远不要使用“新的”。要遵循该规则,您将如何重构以下代码?

function Range(from, to) { 
    this.from = from; 
    this.to = to; 
} 

Range.prototype = { 
    includes: function(x) {
        return this.from <= x && x <= this.to;
    }, 

    foreach: function(f) { 
        for(var x = Math.ceil(this.from); x <= this.to; x++) f(x);
    },

    toString: function() { 
        return "(" + this.from + "..." + this.to + ")"; 
    } 
};

// Here are example uses of a range object 
var r = new Range(1,3); // Create a range object 
r.includes(2); // => true: 2 is in the range 
r.foreach(console.log); // Prints 1 2 3

我发现了他的additional advice,但目前尚不清楚如何将其应用于此(可能非常常见)的情况。他会建议创建一个包含巨大对象字面值的工厂函数吗?如果是,那效率不高吗? ISTM,在每次调用时,这样的工厂函数会创建重复的函数。换句话说,没有一个原型持有共享自定义方法。

在他的建议中似乎没有说清楚,我希望有人可以清理它。

3 个答案:

答案 0 :(得分:2)

我在这里展示如何在不使用new

的情况下实现这一目标
Range = function(from, to) {

    function includes(x) {
        return this.from <= x && x <= this.to;
    }

    function foreach(f) {
        for (var x = Math.ceil(this.from); x <= this.to; x++) f(x);
    }

    function toString(){
        return "(" + this.from + "..." + this.to + ")";
    }

    return {
        from: from,
        to: to,
        includes: includes,
        foreach:  foreach,
        toString: toString
    };
};

var r = Range(1, 3);
console.log(r.includes(2)); // => true: 2 is in the range
r.foreach(console.log); // Prints 1 2 3

这只是一个例子,但我会遵循@nnnnn所说的 - “只在适当的时候使用它。就我而言,你问题中的代码完全可以正常使用new并且不会不需要重构。“

编辑:

下面给出的代码将避免创建重复的函数实例

Range = function(from, to) {
    return {
        from: from,
        to: to,
        includes: Range.includes,
        foreach:  Range.foreach,
        toString: Range.toString
    };
};

Range.includes = function(x) {
    return this.from <= x && x <= this.to;
}

Range.foreach = function (f) {
    for (var x = Math.ceil(this.from); x <= this.to; x++) f(x);
}

Range.toString = function() {
    return "(" + this.from + "..." + this.to + ")";
}

答案 1 :(得分:1)

我认为他会建议这样做:

function Range(from, to) {
  if (!(this instanceof Range)) {
    return new Range(from, to);  // Yes, the new operator is used here, but...
  }

  this.from = from;
  this.to = to;
}

// ... now, the rest of the world can create ranges WITHOUT the new operator:
var my_range = Range(0, 1);

答案 2 :(得分:0)

我喜欢这种技术,我将其称为保证实例:

var Range = function fn(from, to) {
    if (!(this instanceof fn)) {
        return new fn(from, to);
    };
    this.from = from; 
    this.to = to; 
} 

Range.prototype = { 
    includes: function(x) {
        return this.from <= x && x <= this.to;
    }, 

    foreach: function(f) { 
        for(var x = Math.ceil(this.from); x <= this.to; x++) f(x);
    },

    toString: function() { 
        return "(" + this.from + "..." + this.to + ")"; 
    } 
};

// Here are example uses of a range object 
var r = new Range(1,3); // Create a range object 
r.includes(2); // => true: 2 is in the range 
r.foreach(console.log); // Prints 1 2 3