views:

774

answers:

6

I'm working on a plug-in for jQuery and I'm getting this JSLint error:

Problem at line 80 character 45: Do not use 'new' for side effects.

(new jQuery.fasterTrim(this, options));

I haven't had much luck finding info on this JSLint error or on any side effects that new might have.

I've tried Googling for "Do not use 'new' for side effects." and got 0 results. Binging gives me 2 results but they both just reference the JSLint source. Hopefully this question will change that. :-)

Update #1: Here's more source for the context:

  jQuery.fn.fasterTrim = function(options) {
    return this.each(function() {
      (new jQuery.fasterTrim(this, options));
    });
  };

Update #2: I used the Starter jQuery plug-in generator as a template for my plug-in, which has that code in it.

+6  A: 

It's complaining because you're calling "new" but then throwing away the returned object, I bet. Why is that code using "new"? In other words, why isn't it just

jQuery.fasterTrim(this, options);

edit OK, well that "Starter" tool generates the code that way because it really does want a new object created, and yes it really is to take advantage of side effects. The constructor code that "Starter" generates stashes a reference to the new object on the affected element, using the jQuery "data" facility.

Pointy
I updated the question to show the surrounding source, which originated from the Starter code.
travis
The problem that js lint detected is creating a new object and throwing it away. Basically, jslint assumes that a new call whose return value is not stored must cause a side effect (why else would you instantiate it), and constructors with side effects are usually bad design. Js lint is telling you that fastTrim uses bad design.Just use $.fasterTrim(" Hello ");
Juan Mendes
@Juan well it looks like that "Starter" tool generates that code, so the asker of the question is basically a victim of that stuff. I've used that page myself just now, and sure enough that seems to be the pattern it gives you. I don't know why.
Pointy
hmm, so is there a safer way to do that same thing in a way that JSLint would approve of?
travis
Well there probably are better ways to do that, though I'm no formalist so I can't prescribe anything. If you're using that Starter tool (which really doesn't look so bad), you may want to just ignore that JSLint error. It doesn't seem so totally evil to me that the Starter code happens to do that.
Pointy
Its an interesting point about constructors with side effects being a bad thing. I suppose I could connect the new object to the DOM object outside the function, but it seems strange to move a single line for that reason. Obviously a jQuery widget implies side effects when you create it, so I think its a moot point. Oh, and +1 from me :)
Doug Neiner
+5  A: 

You are using new to perform some action instead of to create an object and return it. JSLint considers this an invalid use of new.

You should either use it like this:

var x = new SomeConstructor();

Or perform some action like this:

SomeMethod();

But never use new to perform an action like this:

new SomeCosntructor(args);

Doing so is considered using new for side effects because you aren't using it to create an object.

EndangeredMassa
well, he is creating an object, but he's throwing it away :-)
Pointy
I updated the question to show the surrounding source, which originated from the Starter code.
travis
I'm still not understanding. How am I to create something like a Prototype PeriodicalExecuter? The recommended API fails this jslint check. http://www.prototypejs.org/api/periodicalExecuter
ScottJ
These guidelines are for best practices. The Prototype library doesn't adhere to this particular practice. So, you'll have to make do. You can either leave the error or assign the result to a local variable, even though you won't use it.
EndangeredMassa
+1  A: 

Basically JavaScript tends to be a slow beast, so creating a new object just to call a function is quite inefficient. The function is static anyway.

$.fasterTrim(this, options);
ChaosPandion
+11  A: 

JsLint itself gives you the reason:

Constructors are functions that are designed to be used with the new prefix. The new prefix creates a new object based on the function's prototype, and binds that object to the function's implied this parameter. If you neglect to use the new prefix, no new object will be made and this will be bound to the global object. This is a serious mistake.

JSLint enforces the convention that constructor functions be given names with initial uppercase. JSLint does not expect to see a function invocation with an initial uppercase name unless it has the new prefix. JSLint does not expect to see the new prefix used with functions whose names do not start with initial uppercase. This can be controlled with the newcap option.

JSLint does not expect to see the wrapper forms new Number, new String, new Boolean.

JSLint does not expect to see new Object (use {} instead).

JSLint does not expect to see new Array (use [] instead).

Elzo Valugi
A: 

From jQuery fasterTrim source code:

 * Usage: 
 * 
 * $(element).fasterTrim(options);  // returns jQuery object
 * $.fasterTrim.trim(" string ", options);  // returns trimmed string

To answer the question, "Do not use new for side effects" means:

Do not use new for what the constructor will do to its parameters but to create an object, side effects in constructors are baaaad!

Vincent Robert
ha, thanks for pasting my own source for me :-)
travis
+3  A: 

Travis, I am the developer behind the Starter site.

@Pointy hit the nail on the head. The reason the Starter code is written that way is because we do need a new object, we just don't need to store a reference to it at that point.

Simply changing the command from

(new jQuery.fasterTrim(this, options)); 

to

var fT = new jQuery.fasterTrim(this, options);

will appease JSLint as you have found.

The Starter plugin setup follows the jQuery UI pattern of storing a reference to the object in the data set for the element. So this is what is happening:

  1. New object is created (via new)
  2. The instance is attached to the DOM element using jQuery's data :$(el).data('FasterTrim', this)

There is no use for the object that is returned, and thus no var declaration made. I will look into changing the declaration and cleaning up the output to pass JSLint out of the box.

A little more background:

The benefit to storing the object using data is that we can access the object later at any time by calling: $("#your_selector").data('FasterTrim'). However, if your plugin does not need to be accessed mid stream that way (Meaning, it gets set up in a single call and offers no future interaction) then storing a reference is not needed.

Let me know if you need more info.

Doug Neiner
Cool, thanks Doug. Setting a var would just give me another lint error along the lines of `Unused variable: fT` so I'll just keep your Starter code as is.
travis
If it really bothers you (And I might fall into the category of obsessed with JSLint when I use it) you could move the `data` call after the constructor like this: `var fT = new jQuery.fasterTrim(this, options); $(this).data('FasterTrim', fT);` And that would solve the errors me thinks.
Doug Neiner