What side effects does the keyword 'new' have in JavaScript? - javascript

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.

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).

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:
New object is created (via new)
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.

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.

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.

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);

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!

Related

How exactly stream.Transform works in Node?

Below is a code snippet I found online on a blog which entails a simple example in using the stream Transform class to alter data streams and output the altered result. There are some things about this that I don't really understand.
var stream = require('stream');
var util = require('util');
// node v0.10+ use native Transform, else polyfill
var Transform = stream.Transform ||
require('readable-stream').Transform;
Why does the program need to check if the this var points to an instance of the Upper constructor? The Upper constructor is being used to construct the upper object below, so what is the reason to check for this? Also, I tried logging options, but it returns null/undefined, so what's the point of that parameter?
function Upper(options) {
// allow use without new
if (!(this instanceof Upper)) {
return new Upper(options);
}
I assume that this Transform.call method is being made to explicitly set the this variable? But why does the program do that, seeing as how Transform is never being called anyway.
// init Transform
Transform.call(this, options);
}
After googling the util package, I know that it is being used here to allow Upper to inherit Transform's prototypal methods. Is that right?
util.inherits(Upper, Transform);
The function below is what really confuses me. I understand that the program is setting a method on Upper's prototype which is used to transform data being input into it. But, I don't see where this function is being called at all!
Upper.prototype._transform = function (chunk, enc, cb) {
var upperChunk = chunk.toString().toUpperCase();
this.push(upperChunk);
cb();
};
// try it out - from the original code
var upper = new Upper();
upper.pipe(process.stdout); // output to stdout
After running the code through a debugger, I can see that upper.write calls the aforementioned Upper.prototype._transform method, but why does this happen? upper is an instance of the Upper constructor, and write is a method that doesn't seem to have any relation to the _transform method being applied to the prototype of Upper.
upper.write('hello world\n'); // input line 1
upper.write('another line'); // input line 2
upper.end(); // finish
First, if you haven't already, take a look at the Transform stream implementer's documentation here.
Q: Why does the program need to check if the this var points to an instance of the Upper constructor? The Upper constructor is being used to construct the upper object below, so what is the reason to check for this?
A: It needs to check because anyone can call Upper() without new. So if it's detected that a user called the constructor without new, out of convenience (and to make things work correctly), new is implicitly called on the user's behalf.
Q: Also, I tried logging options, but it returns null/undefined, so what's the point of that parameter?
A: options is just a constructor/function parameter. If you don't pass anything to the constructor, then obviously it will be undefined (or whatever value you pass to it). You can have as many parameters as you want/need, just like any ordinary function. In the case of Upper() however, configuration isn't really needed due to the simplicity of the transform (just converting all input to uppercase).
Q: I assume that this Transform.call method is being made to explicitly set the this variable? But why does the program do that, seeing as how Transform is never being called anyway.
A: No, the Transform.call() allows the inherited "class" to perform its own initialization, such as setting up internal state variables. You can think of it as calling the super() in ES6 classes.
Q: After googling the util package, I know that it is being used here to allow Upper to inherit Transform's prototypal methods. Is that right?
A: Yes, that is correct. However, these days you can also use ES6 classes to do real inheritance. The node.js stream implementers documentation shows examples of both inheritance methods.
Q: The function below is what really confuses me. I understand that the program is setting a method on Upper's prototype which is used to transform data being input into it. But, I don't see where this function is being called at all!
A: This function is called internally by node when it has data for you to process. Think of the method as being part of an interface (or a "pure virtual function" if you are familiar with C++) that you are required to implement in your custom Transform.
Q: After running the code through a debugger, I can see that upper.write calls the aforementioned Upper.prototype._transform method, but why does this happen? upper is an instance of the Upper constructor, and write is a method that doesn't seem to have any relation to the _transform method being applied to the prototype of Upper.
A: As noted in the Transform documentation, Transform streams are merely simplified Duplex streams (meaning they accept input and produce output). When you call .write() you are writing to the Writable (input) side of the Transform stream. This is what triggers the call to ._transform() with the data you just passed to .write(). When you call .push() you are writing to the Readable (output) side of the Transform stream. That data is what seen when you either call .read() on the Transform stream or you attach a 'data' event handler.

Mixing datatypes, functions and objects

When you use require and loads a module, you seems capable of create a function with properties or a object that can be invoked as a function.
console.log(require('events').EventEmitter);
//{ [Function: EventEmitter] defaultMaxListeners: 10, listenerCount: [Function] }
I have done this before* using the require module so I can replicate it. But I want to create more manually. I have some questions in this regards:
Is possible replicate this manually, harcoded without require?
Is possible to create any type of property like getters or setters?
Is posible to create one of these 'objects' when you use a constructor?
Thanks in advance.
*Or I remember that, I have a terrible memory
Edited:
To be clear: I'm not talking about prototype. In my example you can see that, for example, defaultMaxListeners dont come from prototype. In code:
EventEmitter.defaultMaxListeners // 10
EventEmitter.prototype.defaultMaxListeners // undefined
EventEmitter() //No error
Is possible replicate this manually, harcoded without require? Is
possible to create any type of property like getters or setters? Is
posible to create one of these 'objects' when you use a constructor?
Yes
In JS, functions are also objects. You can attach properties to them like any other object. Also, in JS, functions can be used as both functions as well as object constructors.
The following example shows what you can do to a function. I'm using Classical OOP terms, since I don't know what they call them in JS.
function SomeConstructor(){
this.instanceProperty = 'foo';
}
// Instance Method
SomeConstructor.prototype.method = function(){
console.log('method');
}
// Static Method
SomeConstructor.staticMethod = function(){
console.log('static');
}
var test = new SomeConstructor();
test.method();
SomeConstructor.staticMethod();

Is it acceptable to add an attribute to a JavaScript function?

Is it acceptable to add an attribute or value to a JavaScript function?
Example:
var f = 1;
function foo (param) {
f++;
}
var fooFunc = foo;
fooFunc.dummy = f;
console.log('fooFunc: ' + fooFunc);
console.log('fooFunc.dummy: ' + fooFunc.dummy);
The above example creates a function (foo), then assigns it to a new variable (fooFunc) and then adds a dummy attribute to fooFunc.
When run, this example prints the text of the function first, and then it prints the expected value (1 in this case). When printing the function, it doesn't show any indication of the dummy value:
fooFunc: function foo(param) {
f++;
}
fooFunc.dummy: 1
JsFiddle here - open the browser's JavaScript console to see the log messages: http://jsfiddle.net/nwinkler/BwvLf/
Why does this work? And where is the dummy attribute stored, and why isn't it printed when I log the function?
Lastly, even if this works, is it a good idea (or an acceptable practice) to use this? I don't want to start an open ended discussion on this, but rather see if there's documented uses of this, or people discouraging this in JavaScript coding guidelines.
Everything except primitives ( null, undefined, number, string, boolean ) in JavaScript are objects. So functions are basically objects.
Objects in JavaScript can have properties and methods, hence functions too.
all functions inherit from Function.prototype and has certain properties ( name, length ) and methods ( .call, .apply ) coming through this chain.
It is sometimes very useful to keep properties attached to the function itself, like cache information, number of invocations etc. There is nothing wrong out in using it this way.
More details : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function
Let's have a look at ECMAScript documentation (Which is the standard JavaScript is based on). Here's the 3rd. version of it:
http://www.ecma-international.org/publications/files/ECMA-ST-ARCH/ECMA-262,%203rd%20edition,%20December%201999.pdf
Go to chapter 15, Native ECMAScript Objects.
15.3 > Function objects.
There's a lot of interesting information there concerning your question, but the first thing worth noticing is that function is an object.
As an object, it has attributes (predefined and that you can assign yourself).
For example, try:
console.log('fooFunc.name: ' + fooFunc.name);
It should display "foo" in your case.
Since it's documented quite well, you can use it as a standard way, though it is not so well-spread and may seem a bit unusual.
Hope this helps.
It is normal object behavior, whether "acceptable" or not.
By using the function keyword you are actually calling the native predefined Function() constructor. Like any object constructor it returns an object after building it. Like any object, the returned object can have properties, including other functions as method properties.
var adder = function(a, b){return a+b};
adder.subtracter = function(a, b){return a-b};
console.log(adder(1,2)); // 3
console.log(adder.subtracter(1,2)); // -1
TIP: if you want to see the adder object and its subtracter method, switch to DOM view from Console view after running the above code in console and then search for "adder". You'll see the object there, and then you can collapse to see what it's made from, including a subtracter object.
Of course, a function object is a special native object, which makes it possible to make calls like this: adder() and actually run some code. The fact that a function object is harder to inspect for custom attached properties, combined with its native special object treats (read built-in restrictive behavior), should give you a hint that, while it's possible, attaching custom properties is not the intended nor a good use of a function object.

Extending core types without modifying prototype

How does one extend core JavaScript types (String, Date, etc.) without modifying their prototypes? For example, suppose I wanted to make a derived string class with some convenience methods:
function MyString() { }
MyString.prototype = new String();
MyString.prototype.reverse = function() {
return this.split('').reverse().join('');
};
var s = new MyString("Foobar"); // Hmm, where do we use the argument?
s.reverse();
// Chrome - TypeError: String.prototype.toString is not generic
// Firefox - TypeError: String.prototype.toString called on incompatible Object
The error seems to originate from String base methods, probably "split" in this case, since its methods are being applied to some non-string object. But if we can't apply the to non-string objects then can we really reuse them automatically?
[Edit]
Obviously my attempt is flawed in many ways but I think it demonstrates my intent. After some thinking, it seems that we can't reuse any of the String prototype object's functions without explicitly calling them on a String.
Is it possible to extend core types as such?
2 years later: mutating anything in global scope is a terrible idea
Original:
There being something "wrong" with extending native prototypes is FUD in ES5 browsers.
Object.defineProperty(String.prototype, "my_method", {
value: function _my_method() { ... },
configurable: true,
enumerable: false,
writeable: true
});
However if you have to support ES3 browsers then there are problems with people using for ... in loops on strings.
My opinion is that you can change native prototypes and should stop using any poorly written code that breaks
Update: Even this code does not fully extend the native String type (the length property does not work).
Imo it's probably not worth it to follow this approach. There are too many things to consider and you have to invest too much time to ensure that it fully works (if it does at all). #Raynos provides another interesting approach.
Nevertheless here is the idea:
It seems that you cannot call String.prototype.toString on anything else than a real string. You could override this method:
// constructor
function MyString(s) {
String.call(this, s); // call the "parent" constructor
this.s_ = s;
}
// create a new empty prototype to *not* override the original one
tmp = function(){};
tmp.prototype = String.prototype;
MyString.prototype = new tmp();
MyString.prototype.constructor = MyString;
// new method
MyString.prototype.reverse = function() {
return this.split('').reverse().join('');
};
// override
MyString.prototype.toString = function() {
return this.s_;
};
MyString.prototype.valueOf = function() {
return this.s_;
};
var s = new MyString("Foobar");
alert(s.reverse());
As you see, I also had to override valueOf to make it work.
But: I don't know whether these are the only methods you have to override and for other built-in types you might have to override other methods. A good start would be to take the ECMAScript specification and have a look at the specification of the methods.
E.g. the second step in the String.prototype.split algorithm is:
Let S be the result of calling ToString, giving it the this value as its argument.
If an object is passed to ToString, then it basically calls the toString method of this object. And that is why it works when we override toString.
Update: What does not work is s.length. So although you might be able to make the methods work, other properties seem to be more tricky.
First of all, in this code:
MyString.prototype = String.prototype;
MyString.prototype.reverse = function() {
this.split('').reverse().join('');
};
the variables MyString.prototype and String.prototype are both referencing the same object! Assigning to one is assigning to the other. When you dropped a reverse method into MyString.prototype you were also writing it to String.prototype. So try this:
MyString.prototype = String.prototype;
MyString.prototype.charAt = function () {alert("Haha");}
var s = new MyString();
s.charAt(4);
"dog".charAt(3);
The last two lines both alert because their prototypes are the same object. You really did extend String.prototype.
Now about your error. You called reverse on your MyString object. Where is this method defined? In the prototype, which is the same as String.prototype. You overwrote reverse. What is the first thing it does? It calls split on the target object. Now the thing is, in order for String.prototype.split to work it has to call String.prototype.toString. For example:
var s = new MyString();
if (s.split("")) {alert("Hi");}
This code generates an error:
TypeError: String.prototype.toString is not generic
What this means is that String.prototype.toString uses the internal representation of a string to do its thing (namely returning its internal primitive string), and cannot be applied to arbitrary target objects that share the string prototype. So when you called split, the implementation of split said "oh my target is not a string, let me call toString," but then toString said "my target is not a string and I'm not generic" so it threw the TypeError.
If you want to learn more about generics in JavaScript, you can see this MDN section on Array and String generics.
As for getting this to work without the error, see Alxandr's answer.
As for extending the exact built-in types like String and Date and so on without changing their prototypes, you really don't, without creating wrappers or delegates or subclasses. But then this won't allow the syntax like
d1.itervalTo(d2)
where d1 and d2 are instances of the built-in Date class whose prototype you did not extend. :-) JavaScript uses prototype chains for this kind of method call syntax. It just does. Excellent question though... but is this what you had in mind?
You got only one part wrong here. MyString.prototype shouldn't be String.prototype, it should be like this:
function MyString(s) { }
MyString.prototype = new String();
MyString.prototype.reverse = function() {
this.split('').reverse().join('');
};
var s = new MyString("Foobar");
s.reverse();
[Edit]
To answer your question in a better way, no it should not be possible.
If you take a look at this: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/constructor it explains that you can't change the type on bools, ints and strings, thus they cannot be "subclassed".
I think the basic answer is you probably can't. What you can do is what Sugar.js does - create an object-like object and extend from that:
http://sugarjs.com/
Sugar.js is all about native object extensions, and they do not extend Object.prototype.

What is the point of Ext.apply versus simply setting values on the target?

Using Ext.js or sencha, what is the point of doing the following:
Ext.apply(app.views, {
contactsList: new app.views.ContactsList(),
contactDetail: new app.views.ContactDetail(),
contactForm: new app.views.ContactForm()
});
As opposed to this standard javascript:
app.views.contactsList = new app.views.ContactsList();
app.views.contactDetail = new app.views.ContactDetail();
app.views.contactForm = new app.views.ContactForm();
Is there any difference?
Ext.apply is generally more convenient (and possibly more efficient if there are fewer activation chain lookups required, as in your example, though that's a minor point) . There is also a variant Ext.applyIf that only applies members from the source object that do not exist in the target object, which is even more useful as it saves you from a boatload of manual if() checks. That's really useful, for example, when applying defaults to a config object that may already have user or app-defined properties assigned.
A note to future readers who look at the accepted answer: Ext also has Ext.extend which actually means "inherit from" a class, as opposed to Ext.apply[If] which merely merges an object instance into another, or Ext.override which overrides (without subclassing) a class definition. Lots of options, depending on what you need.
It's mostly there as a convenience method for code that is accepting an object as an argument, and needs to merge it. Merging objects is a common use case in JavaScript, and this type of helper is implemented by most frameworks. ($.extend in jQuery, Object.extend in Prototype, Object.append in MooTools, etc.)
In your case, there is little difference, other than offering a bit more readable code.
You need Ext.apply if you use Ajax requests to get the configurations from the server. Because Ajax responses are received later on, after the window is rendered. The second part of your code won't work.

Categories