Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rules to Replace 'New'

In his "Good Parts," Crockford suggests that 'new' should never be used. To follow that rule, how would you refactor the following code?

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

I spotted his additional advice, but it wasn't clear how to apply it in this (presumably very common) case. Would he propose to create a factory function that contains a giant object literal? If yes, isn't that inefficient? ISTM that such a factory function, upon each invocation, creates duplicate functions. In other words, there is no one prototype holding shared custom methods.

It seems something is left unsaid in his advice, I'm hoping someone can clear it up.

like image 367
Brent Arias Avatar asked Aug 08 '26 02:08

Brent Arias


1 Answers

Here I am showing how you can achieve this without using 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

This is just an example, but I would follow what @nnnnnn is saying - "use it only when appropriate. As far as I'm concerned the code in your question is perfectly fine use of new and doesn't need to be refactored."

EDIT:

The code given below will avoid creating duplicate instances of functions

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 + ")";
}
like image 166
Diode Avatar answered Aug 09 '26 15:08

Diode