What "Hidden Features" of JavaScript do you think every programmer should know?
After having seen the excellent quality of the answers to the following questions I thought it was time to ask it for JavaScript.
- Hidden Features of HTML
- Hidden Features of CSS
- Hidden Features of PHP
- Hidden Features of ASP.NET
- Hidden Features of C#
- Hidden Features of Java
- Hidden Features of Python
Even though JavaScript is arguably the most important Client Side language right now (just ask Google) it's surprising how little most web developers appreciate how powerful it really is.
-
1Didn't you mean "Having seen the rep. points and views this other question attracted, I thought I'd ask almost exactly the same question to boost my own"? ;-)Bobby Jack– Bobby Jack09/14/2008 18:22:24Commented Sep 14, 2008 at 18:22
-
1Sure, pessimist. :) I'd considered making this a community question. Also, after you get a certain number of points it's all diminishing returns.Allain Lalonde– Allain Lalonde09/14/2008 18:37:39Commented Sep 14, 2008 at 18:37
-
1Fair enough - it doesn't look as if you 'need' the rep! I guess I just have a big issue with the C# one - doesn't exactly seem to me like the type of question for which this site was intended.Bobby Jack– Bobby Jack09/14/2008 18:41:13Commented Sep 14, 2008 at 18:41
-
3Yeah, maybe not, but I found the knowledge in the answers great. I think you'd be hard pressed to expose an average C# programmer to all of it in one place if not for SO. It'd take years of playing with it to come up with the same hard won list.Allain Lalonde– Allain Lalonde09/14/2008 18:54:01Commented Sep 14, 2008 at 18:54
-
7I've been writing JavaScript professionally for 10 years now and I learned a thing or three from this thread. Thanks, Alan!Andrew Hedges– Andrew Hedges09/20/2008 07:39:58Commented Sep 20, 2008 at 7:39
99 Answers 99
You don't need to define any parameters for a function. You can just use the function's arguments
array-like object.
function sum() {
var retval = 0;
for (var i = 0, len = arguments.length; i < len; ++i) {
retval += arguments[i];
}
return retval;
}
sum(1, 2, 3) // returns 6
-
3WHOA! Really?! I honestly had no idea. This site really needs a "favorite answers" feature. I'd add this one for sure.Joshua Carmody– Joshua Carmody09/19/2008 20:36:00Commented Sep 19, 2008 at 20:36
-
51It's also worth noting that accessing the Arguments object is relatively expensive -- the best examples are in Safari, Firefox, and Chrome nightlies where merely referencing the
arguments
object makes calling a function much slower -- eg. if(false) arguments; will hurt perf.olliej– olliej02/18/2009 03:20:46Commented Feb 18, 2009 at 3:20 -
48In the same vein, arguments has a "callee" property which is the current function itself. This allows to do recursion with anonymous functions, cool!Vincent Robert– Vincent Robert04/02/2009 20:01:14Commented Apr 2, 2009 at 20:01
-
4@Nathan "f(x,y,z)" looks better than "f([x,y,z])".Mark Cidade– Mark Cidade09/28/2009 12:01:36Commented Sep 28, 2009 at 12:01
-
16@Vincent Robert: please note that
arguments.callee
is being deprecated.ken– ken12/29/2010 21:50:04Commented Dec 29, 2010 at 21:50
I could quote most of Douglas Crockford's excellent book JavaScript: The Good Parts.
But I'll take just one for you, always use ===
and !==
instead of ==
and !=
alert('' == '0'); //false
alert(0 == ''); // true
alert(0 =='0'); // true
==
is not transitive. If you use ===
it would give false for
all of these statements as expected.
-
29It's a shame that so many people think Crockford is all-knowing. Granted, the guy is right on the mark with most of his criticisms, but I stop short of giving his stuff a blanket endorsement like so many devs do...Jason Bunting– Jason Bunting09/14/2008 21:58:22Commented Sep 14, 2008 at 21:58
-
21I second Jason's warning. The book in itself is very interesting, and it does give a lot of good advice, but DC is far too convinced that his way of doing things is the only correct way, everything else is "defective". If you'd like some examples, look at his responses on the JSLint Yahoo Group.Zilk– Zilk10/28/2008 21:21:28Commented Oct 28, 2008 at 21:21
-
30Use === instead of == is good advice if you are confused by dynamic typing and just want it to be "really" equals. Those of us who understand dynamic typing may continue to use == for situations where we know we want to cast, as in 0 == '' or 0 == '0'.thomasrutter– thomasrutter04/01/2009 05:15:29Commented Apr 1, 2009 at 5:15
-
20Well == and === are not about dynamic typing. == does type coersion, which is a different beast. If you know, that you want to cast to string/number/etc, then you shold do that explicitly.Rene Saarsoo– Rene Saarsoo06/05/2009 18:39:29Commented Jun 5, 2009 at 18:39
-
15I think the scariest part of
==
is'\n\t\r ' == 0
=>true
... :Dsharat87– sharat8710/18/2009 09:19:30Commented Oct 18, 2009 at 9:19
Functions are first class citizens in JavaScript:
var passFunAndApply = function (fn,x,y,z) { return fn(x,y,z); };
var sum = function(x,y,z) {
return x+y+z;
};
alert( passFunAndApply(sum,3,4,5) ); // 12
Functional programming techniques can be used to write elegant javascript.
Particularly, functions can be passed as parameters, e.g. Array.filter() accepts a callback:
[1, 2, -1].filter(function(element, index, array) { return element > 0 });
// -> [1,2]
You can also declare a "private" function that only exists within the scope of a specific function:
function PrintName() {
var privateFunction = function() { return "Steve"; };
return privateFunction();
}
-
3There are three ways to make functions in javascript: function sum(x, y, z){ return (x+y+z); } and var sum = new Function("x", "y", "z", "return (x+y+z);"); are the other ways.Marius– Marius09/14/2008 19:35:29Commented Sep 14, 2008 at 19:35
-
6The concept of functions-as-data definitely wins big points in my book.Jason Bunting– Jason Bunting09/14/2008 21:52:21Commented Sep 14, 2008 at 21:52
-
I just updated the sample to show how to use a "private" function that exists only within the scope of a specific function.Chris Pietschmann– Chris Pietschmann10/10/2008 14:25:51Commented Oct 10, 2008 at 14:25
-
new Function()
is as evil aseval
. Do Not Use.Nicolás– Nicolás01/04/2010 05:56:11Commented Jan 4, 2010 at 5:56 -
11not sure this is a hidden feature... more like a core feature.Claudiu– Claudiu06/24/2010 14:33:52Commented Jun 24, 2010 at 14:33
You can use the in operator to check if a key exists in an object:
var x = 1;
var y = 3;
var list = {0:0, 1:0, 2:0};
x in list; //true
y in list; //false
1 in list; //true
y in {3:0, 4:0, 5:0}; //true
If you find the object literals too ugly you can combine it with the parameterless function tip:
function list()
{ var x = {};
for(var i=0; i < arguments.length; ++i) x[arguments[i]] = 0;
return x
}
5 in list(1,2,3,4,5) //true
-
22Not so clever, that checks if a key is present, not if a value is. x in list; only works because x[1] != null, not because the value 1 is there.Armin Ronacher– Armin Ronacher09/21/2008 22:16:58Commented Sep 21, 2008 at 22:16
-
1I haven't used the technique ina while so I forgot that I actually used object literals before. Thanks for the correction.Mark Cidade– Mark Cidade09/22/2008 17:03:39Commented Sep 22, 2008 at 17:03
-
34Also, be careful: the in operator also tests the prototype chain! If someone has put a property called '5' on the Object.prototype, the second example would return true even if you called '5 in list(1, 2, 3, 4)'... You'd better use the hasOwnProperty method: list(1, 2, 3, 4).hasOwnProperty(5) will return false, even if Object.prototype has a property '5'.Martijn– Martijn06/22/2009 08:24:18Commented Jun 22, 2009 at 8:24
-
3For the very most general solution, one that can test whether an Object has its own property, even if it is named "hasOwnProperty", you have to go all the way out to: Object.prototype.hasOwnProperty.call(object, name);Kris Kowal– Kris Kowal09/12/2009 22:52:46Commented Sep 12, 2009 at 22:52
-
1@Kris, not unless someone overwrites Object.prototype.hasOwnProperty ;)Nick– Nick07/27/2010 19:51:35Commented Jul 27, 2010 at 19:51
Assigning default values to variables
You can use the logical or operator ||
in an assignment expression to provide a default value:
var a = b || c;
The a
variable will get the value of c
only if b
is falsy (if is null
, false
, undefined
, 0
, empty string
, or NaN
), otherwise a
will get the value of b
.
This is often useful in functions, when you want to give a default value to an argument in case isn't supplied:
function example(arg1) {
arg1 || (arg1 = 'default value');
}
Example IE fallback in event handlers:
function onClick(e) {
e || (e = window.event);
}
The following language features have been with us for a long time, all JavaScript implementations support them, but they weren't part of the specification until ECMAScript 5th Edition:
The debugger
statement
Described in: § 12.15 The debugger statement
This statement allows you to put breakpoints programmatically in your code just by:
// ...
debugger;
// ...
If a debugger is present or active, it will cause it to break immediately, right on that line.
Otherwise, if the debugger is not present or active this statement has no observable effect.
Multiline String literals
Described in: § 7.8.4 String Literals
var str = "This is a \
really, really \
long line!";
You have to be careful because the character next to the \
must be a line terminator, if you have a space after the \
for example, the code will look exactly the same, but it will raise a SyntaxError
.
-
28Not if it's null, if it's considered false. a = 0 || 42; will give you 42. This is comparable with Python's or, not C#'s ?? operator. If you want the C# behavior, do a = (b === null) ? c : b;Armin Ronacher– Armin Ronacher09/21/2008 22:18:34Commented Sep 21, 2008 at 22:18
-
It also works in Visual Studio as well, if you develop on ASP.NET :)chakrit– chakrit03/23/2010 13:13:10Commented Mar 23, 2010 at 13:13
-
2I wish there was proper || for undefined only. I was bitten by this today for 0, since I wanted to create emulation of overloaded method, so that the last argument was optional and a default value would be used instead.egaga– egaga04/15/2010 03:47:17Commented Apr 15, 2010 at 3:47
-
+1 this trick is utilized by the default Google Analytics snippet. ` var _gaq = _gaq || [];`; it prevents overzealous users from overwriting their own work.Yahel– Yahel11/11/2010 00:29:03Commented Nov 11, 2010 at 0:29
-
2I didn't know about the multiline string literal technique. That's fantastic, thanks.Charlie Flowers– Charlie Flowers11/26/2010 02:33:01Commented Nov 26, 2010 at 2:33
JavaScript does not have block scope (but it has closure so let's call it even?).
var x = 1;
{
var x = 2;
}
alert(x); // outputs 2
-
3That is a good one. It is a really important difference from most C like languages.Martin Clarke– Martin Clarke09/14/2008 19:02:02Commented Sep 14, 2008 at 19:02
-
9You can always do "var tmp = function() { /* block scope */ }();". The syntax is ugly, but it works.Joeri Sebrechts– Joeri Sebrechts09/30/2008 11:03:36Commented Sep 30, 2008 at 11:03
-
3Or you can use "let" if it's Firefox only: stackoverflow.com/questions/61088/…Eugene Yokota– Eugene Yokota10/01/2008 00:42:08Commented Oct 1, 2008 at 0:42
-
10or just: (function() { var x = 2; })(); alert(typeof x); //undefinedPim Jager– Pim Jager01/27/2009 23:17:07Commented Jan 27, 2009 at 23:17
-
@Pim: JSLint says: "Move the invocation into the parens that contain the function.". Along with "Expected exactly one space between 'function' and '('.".Hello71– Hello7101/10/2011 03:11:55Commented Jan 10, 2011 at 3:11
You can access object properties with []
instead of .
This allows you look up a property matching a variable.
obj = {a:"test"};
var propname = "a";
var b = obj[propname]; // "test"
You can also use this to get/set object properties whose name is not a legal identifier.
obj["class"] = "test"; // class is a reserved word; obj.class would be illegal.
obj["two words"] = "test2"; // using dot operator not possible with the space.
Some people don't know this and end up using eval() like this, which is a really bad idea:
var propname = "a";
var a = eval("obj." + propname);
This is harder to read, harder to find errors in (can't use jslint), slower to execute, and can lead to XSS exploits.
-
eval is evil, though rarely necessaryDoug Domeny– Doug Domeny06/25/2009 14:27:16Commented Jun 25, 2009 at 14:27
-
I never use eval and remember when I discovered this. It made me very happy.user55776– user5577607/12/2009 21:55:49Commented Jul 12, 2009 at 21:55
-
In summary, object properties can be accessed through both dot and subscript notationRuss Cam– Russ Cam04/05/2010 19:53:28Commented Apr 5, 2010 at 19:53
-
9It's interesting to note that dot-referencing is actually syntax sugar for the bracketref.
foo.bar
, according to the spec anyway, behaves just likefoo["bar"]
. also note that everything is a string property. even when you do array access,array[4]
, the 4 is converted to a string (again, at least according to ECMAScript v3 spec)Claudiu– Claudiu06/24/2010 14:40:09Commented Jun 24, 2010 at 14:40 -
I guess every JS programmer should know this.Cem Kalyoncu– Cem Kalyoncu06/09/2011 21:03:14Commented Jun 9, 2011 at 21:03
If you're Googling for a decent JavaScript reference on a given topic, include the "mdc" keyword in your query and your first results will be from the Mozilla Developer Center. I don't carry any offline references or books with me. I always use the "mdc" keyword trick to directly get to what I'm looking for. For example:
Google: javascript array sort mdc
(in most cases you may omit "javascript")
Update: Mozilla Developer Center has been renamed to Mozilla Developer Network. The "mdc" keyword trick still works, but soon enough we may have to start using "mdn" instead.
-
50Wow, great resource. Instantly better than crappy w3schools...DisgruntledGoat– DisgruntledGoat09/22/2009 23:31:13Commented Sep 22, 2009 at 23:31
-
11You don't even need to Google it, if you're on Firefox: just type "array mdc" into the address bar and hit Enter.Sasha Chedygov– Sasha Chedygov04/10/2010 04:00:46Commented Apr 10, 2010 at 4:00
-
2the best part is how this stack overflow question is on the first page of results :)Jiaaro– Jiaaro05/26/2010 13:05:11Commented May 26, 2010 at 13:05
-
5A propo this: promotejs.com , a grassroots SEO initiative to drive MDC results further up in Google search results.Yahel– Yahel11/11/2010 00:30:45Commented Nov 11, 2010 at 0:30
-
3Now is the MDN doc center, so the 'mdc' keyword is still valid :)Aleadam– Aleadam03/14/2011 21:14:09Commented Mar 14, 2011 at 21:14
Maybe a little obvious to some...
Install Firebug and use console.log("hello"). So much better than using random alert();'s which I remember doing a lot a few years ago.
-
12Just don't forget to remove the console statements before releasing your code to others who may not have Firebug installed.Chris Noe– Chris Noe09/22/2008 19:49:22Commented Sep 22, 2008 at 19:49
-
4Even better, precede log statements with ';;;' and then minify takes care of it for you. (At least, the Perl module I use has that feature, and claims it's commonplace.)Kev– Kev11/10/2008 13:46:35Commented Nov 10, 2008 at 13:46
-
10Josh: That won't work as console is not defined. You could check typeof console !== "undefined" or window.console.Eli Grey– Eli Grey08/13/2009 03:03:03Commented Aug 13, 2009 at 3:03
-
23Always include: if (typeof('console') == 'undefined') { console = { log: function() { } }; } then you can continue to use console.log, and it just does nothing.gregmac– gregmac09/02/2009 04:37:38Commented Sep 2, 2009 at 4:37
-
1window.LOG = (typeof(console) != 'undefined') ? console.log : function() { ; } // Lets you use parameters too.MiffTheFox– MiffTheFox09/22/2009 19:12:03Commented Sep 22, 2009 at 19:12
Private Methods
An object can have private methods.
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
// A private method only visible from within this constructor
function calcFullName() {
return firstName + " " + lastName;
}
// A public method available to everyone
this.sayHello = function () {
alert(calcFullName());
}
}
//Usage:
var person1 = new Person("Bob", "Loblaw");
person1.sayHello();
// This fails since the method is not visible from this scope
alert(person1.calcFullName());
-
16That's not really a private function - it's more a function variable in a local scope.Keith– Keith09/15/2008 16:28:00Commented Sep 15, 2008 at 16:28
-
6True but by all operational definitions I can think of that's a method. It's a block of code with a name that has access to instance state and can only be seen by that instance. What's your definition of a private method?Allain Lalonde– Allain Lalonde09/17/2008 22:44:49Commented Sep 17, 2008 at 22:44
-
14@Zach, exactly! It's easy, after spending years working with class-based OO languages, to forget that they are merely one implementation of OO concepts. Of course, the various libraries that attempt to cram quasi-class-based OO into JS don't help either...Shog9– Shog909/20/2008 22:23:15Commented Sep 20, 2008 at 22:23
-
5Just wondering, does person1 have a Law Blog? ;-)travis– travis09/23/2008 16:11:15Commented Sep 23, 2008 at 16:11
-
4+1 for the arrested development referenceDom M.– Dom M.02/28/2010 02:19:09Commented Feb 28, 2010 at 2:19
Also mentioned in Crockford's "Javascript: The Good Parts":
parseInt()
is dangerous. If you pass it a string without informing it of the proper base it may return unexpected numbers. For example parseInt('010')
returns 8, not 10. Passing a base to parseInt makes it work correctly:
parseInt('010') // returns 8! (in FF3)
parseInt('010', 10); // returns 10 because we've informed it which base to work with.
-
13When doing code reviews, always look for this one. Leaving off the ", 10" is a common mistake that goes unnoticed in most testing.Doug Domeny– Doug Domeny06/25/2009 14:31:04Commented Jun 25, 2009 at 14:31
-
I got burned by the radix issue years ago and have never forgotten something so counter-intuitive as such. A great thing to point out since it'll make you wonder for a while.JamesEggers– JamesEggers09/22/2009 20:32:04Commented Sep 22, 2009 at 20:32
-
4Why not use
Math.floor
orNumber
?10 === Math.floor("010"); 10 === Number("010");
floats:42 === Math.floor("42.69"); 42.69 === Number("42.69");
just somebody– just somebody12/16/2009 16:30:58Commented Dec 16, 2009 at 16:30 -
1@Infinity If not a posted answer already, you should. I had no idea it just as simple as this to override built-in function behavior. Of course, it should make one look a bit more closely at any code packages they borrow from other sites. That harmless
parseInt
function could easily be made to do something not so harmless.bob-the-destroyer– bob-the-destroyer06/21/2010 02:22:52Commented Jun 21, 2010 at 2:22 -
6@Infinity: what about redefining the fn to highlight the 'coding error' ?
__parseInt = parseInt; parseInt = function (str, base) { if (!base) throw new Error(69, "All your base belong to us"); return __parseInt(str, base); }
JBRWilkinson– JBRWilkinson07/26/2010 09:51:29Commented Jul 26, 2010 at 9:51
Functions are objects and therefore can have properties.
fn = function(x) { // ... } fn.foo = 1; fn.next = function(y) { // }
-
13This is a very useful tip. For example, you can set default values as a property of the function. For example: myfunc.delay=100; Then users can change the default value and all function calls will use the new default value. For example: myfunc.delay = 200; myfunc();BarelyFitz– BarelyFitz06/01/2009 00:23:30Commented Jun 1, 2009 at 0:23
-
-
Looks sloppy, Why use this instead of a variable?instantsetsuna– instantsetsuna12/08/2010 10:20:31Commented Dec 8, 2010 at 10:20
-
1@instantsetsuna: Why have another separate variable? As usual this boils down to "use it when appropriate/useful" ;-)VolkerK– VolkerK12/10/2010 09:04:20Commented Dec 10, 2010 at 9:04
I'd have to say self-executing functions.
(function() { alert("hi there");})();
Because Javascript doesn't have block scope, you can use a self-executing function if you want to define local variables:
(function() {
var myvar = 2;
alert(myvar);
})();
Here, myvar
is does not interfere with or pollute the global scope, and disappears when the function terminates.
-
2What is this useful for? You get the same results from putting the alert outside the function.PotatoEngineer– PotatoEngineer03/20/2009 15:39:09Commented Mar 20, 2009 at 15:39
-
7It's not about the alert, it's about defining and executing a function all at once. You could have that self-executing function return a value and pass the function as a param to another function.ScottKoon– ScottKoon03/31/2009 19:08:19Commented Mar 31, 2009 at 19:08
-
5@Paul it's good for encapsulation.Mike Robinson– Mike Robinson05/18/2009 14:50:35Commented May 18, 2009 at 14:50
-
22It's also good for block scoping.Jim Hunziker– Jim Hunziker05/23/2009 19:41:16Commented May 23, 2009 at 19:41
-
24Yeah, I enclose all my
.js
files in an anonymous self-executing function and attach anything I want globally accessible within it to thewindow
object. Prevents global namespace pollution.cdmckay– cdmckay11/05/2009 20:11:10Commented Nov 5, 2009 at 20:11
Know how many parameters are expected by a function
function add_nums(num1, num2, num3 ){
return num1 + num2 + num3;
}
add_nums.length // 3 is the number of parameters expected.
Know how many parameters are received by the function
function add_many_nums(){
return arguments.length;
}
add_many_nums(2,1,122,12,21,89); //returns 6
-
23Never knew about the first part. Nice!mcjabberz– mcjabberz09/17/2009 19:48:15Commented Sep 17, 2009 at 19:48
-
1Similarly you can find out how many arguments a function is expecting with
function.length
.Xavi– Xavi07/27/2010 15:18:01Commented Jul 27, 2010 at 15:18 -
6@Xavi which is 1st part of the answerpramodc84– pramodc8408/06/2010 03:49:49Commented Aug 6, 2010 at 3:49
Here are some interesting things:
- Comparing
NaN
with anything (evenNaN
) is always false, that includes==
,<
and>
. NaN
Stands for Not a Number but if you ask for the type it actually returns a number.Array.sort
can take a comparator function and is called by a quicksort-like driver (depends on implementation).- Regular expression "constants" can maintain state, like the last thing they matched.
- Some versions of JavaScript allow you to access
0ドル
,1ドル
,2ドル
members on a regex. null
is unlike anything else. It is neither an object, a boolean, a number, a string, norundefined
. It's a bit like an "alternate"undefined
. (Note:typeof null == "object"
)- In the outermost context,
this
yields the otherwise unnameable [Global] object. - Declaring a variable with
var
, instead of just relying on automatic declaration of the variable gives the runtime a real chance of optimizing access to that variable - The
with
construct will destroy such optimzations - Variable names can contain Unicode characters.
- JavaScript regular expressions are not actually regular. They are based on Perl's regexs, and it is possible to construct expressions with lookaheads that take a very, very long time to evaluate.
- Blocks can be labeled and used as the targets of
break
. Loops can be labeled and used as the target ofcontinue
. - Arrays are not sparse. Setting the 1000th element of an otherwise empty array should fill it with
undefined
. (depends on implementation) if (new Boolean(false)) {...}
will execute the{...}
block- Javascript's regular expression engine's are implementation specific: e.g. it is possible to write "non-portable" regular expressions.
[updated a little in response to good comments; please see comments]
-
5null is actually an (special) object.
typeof null
returns "object".Ateş Göral– Ateş Göral10/01/2008 04:35:16Commented Oct 1, 2008 at 4:35 -
4You can also get the [Global] object from anywhere like this: var glb = function () { return this; }();Zilk– Zilk10/28/2008 21:35:46Commented Oct 28, 2008 at 21:35
-
2The global object in javascript in a browser is the window object. When in the global scope doing: window.a == a;Pim Jager– Pim Jager01/27/2009 23:21:35Commented Jan 27, 2009 at 23:21
-
8"Arrays are not sparse" depends on the implementation. If you set the value of a[1000] and look at a[999], then yes, it is
undefined
, but that is just the default value you get when looking for an index that doesn't exist. If you checked a[2000], that would also beundefined
, but that doesn't mean you've allocated memory for it yet. In IE8, some arrays are dense, and some are sparse, depending on how the JScript engine felt at the time. Read more here: blogs.msdn.com/jscript/archive/2008/04/08/…Chris Nielsen– Chris Nielsen09/19/2009 18:50:21Commented Sep 19, 2009 at 18:50 -
2@Ates and @SF: typeof returns "object" for a range of different types. But once you know how it works and what types identify as "object", it is at least reliable and consistent in its implementation.thomasrutter– thomasrutter03/18/2010 16:00:17Commented Mar 18, 2010 at 16:00
I know I'm late to the party, but I just can't believe the +
operator's usefulness hasn't been mentioned beyond "convert anything to a number". Maybe that's how well hidden a feature it is?
// Quick hex to dec conversion:
+"0xFF"; // -> 255
// Get a timestamp for now, the equivalent of `new Date().getTime()`:
+new Date();
// Safer parsing than parseFloat()/parseInt()
parseInt("1,000"); // -> 1, not 1000
+"1,000"; // -> NaN, much better for testing user input
parseInt("010"); // -> 8, because of the octal literal prefix
+"010"; // -> 10, `Number()` doesn't parse octal literals
// A use case for this would be rare, but still useful in cases
// for shortening something like if (someVar === null) someVar = 0;
+null; // -> 0;
// Boolean to integer
+true; // -> 1;
+false; // -> 0;
// Other useful tidbits:
+"1e10"; // -> 10000000000
+"1e-4"; // -> 0.0001
+"-12"; // -> -12
Of course, you can do all this using Number()
instead, but the +
operator is so much prettier!
You can also define a numeric return value for an object by overriding the prototype's valueOf()
method. Any number conversion performed on that object will not result in NaN
, but the return value of the valueOf()
method:
var rnd = {
"valueOf": function () { return Math.floor(Math.random()*1000); }
};
+rnd; // -> 442;
+rnd; // -> 727;
+rnd; // -> 718;
-
You can do simply
0xFF
etc., no need for+"0xFF"
.user492203– user49220301/14/2011 10:21:06Commented Jan 14, 2011 at 10:21 -
9@Nyuszika7H: you're kind of missing the point, which is coercing other primitives and objects to numbers. Of course you can just write
0xFF
, much the same way you can write1
instead of+true
. I'm suggesting that you can use+("0x"+somevar)
as an alternative toparseInt(somevar, 16)
, if you want to.Andy E– Andy E01/14/2011 10:49:15Commented Jan 14, 2011 at 10:49
"Extension methods in JavaScript" via the prototype property.
Array.prototype.contains = function(value) {
for (var i = 0; i < this.length; i++) {
if (this[i] == value) return true;
}
return false;
}
This will add a contains
method to all Array
objects. You can call this method using this syntax
var stringArray = ["foo", "bar", "foobar"];
stringArray.contains("foobar");
-
18This is generally considered a bad idea, because other code (not yours) may make assumptions about the Array object.Chris Noe– Chris Noe09/22/2008 19:45:48Commented Sep 22, 2008 at 19:45
-
39It's also generally considered a bad idea to make assumptions about the Array object. :(eyelidlessness– eyelidlessness10/07/2008 23:47:13Commented Oct 7, 2008 at 23:47
-
Uhmmmm.. javascript 1.6 array extras? indexOf? ringing any bells?Breton– Breton01/29/2009 01:07:20Commented Jan 29, 2009 at 1:07
-
2@Breton: It's not something specific to the Array class, it's just an example. I use this to extend the new Date().toString(); method, allowing to use a mask string. Any object can be extended, and all it's instances get the new method.Esteban Küber– Esteban Küber06/30/2009 16:42:50Commented Jun 30, 2009 at 16:42
-
1@Mathias: this is not about the DOM.dolmen– dolmen03/28/2011 21:59:52Commented Mar 28, 2011 at 21:59
To properly remove a property from an object, you should delete the property instead of just setting it to undefined:
var obj = { prop1: 42, prop2: 43 };
obj.prop2 = undefined;
for (var key in obj) {
...
The property prop2 will still be part of the iteration. If you want to completely get rid of prop2, you should instead do:
delete obj.prop2;
The property prop2 will no longer will make an appearance when you're iterating through the properties.
-
3Note that the delete statement is not without its browser-specific quirks. For instance this will fail with a big error if you try it in IE and the object is not a native JS object (even when deleting a property you added yourself). It's also not intended for deleting a variable, as in delete myvar; but I think that does work in some browsers. The code in the above answer seems pretty safe though.thomasrutter– thomasrutter04/10/2010 03:37:37Commented Apr 10, 2010 at 3:37
-
by the way, undefined can be a variable, too! Try var undefined="something"Johann Philipp Strathausen– Johann Philipp Strathausen02/12/2012 21:01:18Commented Feb 12, 2012 at 21:01
with
.
It's rarely used, and frankly, rarely useful... But, in limited circumstances, it does have its uses.
For instance: object literals are quite handy for quickly setting up properties on a new object. But what if you need to change half of the properties on an existing object?
var user =
{
fname: 'Rocket',
mname: 'Aloysus',
lname: 'Squirrel',
city: 'Fresno',
state: 'California'
};
// ...
with (user)
{
mname = 'J';
city = 'Frostbite Falls';
state = 'Minnesota';
}
Alan Storm points out that this can be somewhat dangerous: if the object used as context doesn't have one of the properties being assigned to, it will be resolved in the outer scope, possibly creating or overwriting a global variable. This is especially dangerous if you're used to writing code to work with objects where properties with default or empty values are left undefined:
var user =
{
fname: "John",
// mname definition skipped - no middle name
lname: "Doe"
};
with (user)
{
mname = "Q"; // creates / modifies global variable "mname"
}
Therefore, it is probably a good idea to avoid the use of the with
statement for such assignment.
See also: Are there legitimate uses for JavaScript’s "with" statement?
-
29Conventional wisdom the with statment is to be avoided. If the user object didn't have one of the properties you mentioned, the variable outside the with block's pseudo-scope would be modified. That way lies bugs. More info at yuiblog.com/blog/2006/04/11/with-statement-considered-harmfulAlana Storm– Alana Storm09/14/2008 07:54:50Commented Sep 14, 2008 at 7:54
-
1Shog, the objections aren't about misspelled variables, they're about looking at a block of code, and being able to say with certainty what any particular line in that block does. Because Javascript objects are so dynamic, you can't say with certainly what properties/members it has at any moment.Alana Storm– Alana Storm09/14/2008 16:56:27Commented Sep 14, 2008 at 16:56
-
2Amen - if I saw the "with" statement in any JS I found, I would eliminate it and question the developer that wrote it to make sure he knew why it was not a Good Thing to use it..."hidden feature?" More like "abhorrent feature."Jason Bunting– Jason Bunting09/14/2008 21:55:44Commented Sep 14, 2008 at 21:55
-
1consider a more complex chain a.b.c.d "with (a.b.c) {d.foo = bar;} is powerful and not inherently error prone. The key is to curtail the root one level up. And misspelling a variable name? You're introducing a bug if you do that wherever you do it, regardless of "with".annakata– annakata01/20/2009 11:33:23Commented Jan 20, 2009 at 11:33
-
4Douglas Crockford recently said "with" is one of the worst parts of JavaScript in a .NET Rocks! podcast.core– core03/14/2009 04:09:44Commented Mar 14, 2009 at 4:09
Methods (or functions) can be called on object that are not of the type they were designed to work with. This is great to call native (fast) methods on custom objects.
var listNodes = document.getElementsByTagName('a');
listNodes.sort(function(a, b){ ... });
This code crashes because listNodes
is not an Array
Array.prototype.sort.apply(listNodes, [function(a, b){ ... }]);
This code works because listNodes
defines enough array-like properties (length, [] operator) to be used by sort()
.
Prototypal inheritance (popularized by Douglas Crockford) completely revolutionizes the way you think about loads of things in Javascript.
Object.beget = (function(Function){
return function(Object){
Function.prototype = Object;
return new Function;
}
})(function(){});
It's a killer! Pity how almost no one uses it.
It allows you to "beget" new instances of any object, extend them, while maintaining a (live) prototypical inheritance link to their other properties. Example:
var A = {
foo : 'greetings'
};
var B = Object.beget(A);
alert(B.foo); // 'greetings'
// changes and additionns to A are reflected in B
A.foo = 'hello';
alert(B.foo); // 'hello'
A.bar = 'world';
alert(B.bar); // 'world'
// ...but not the other way around
B.foo = 'wazzap';
alert(A.foo); // 'hello'
B.bar = 'universe';
alert(A.bar); // 'world'
Some would call this a matter of taste, but:
aWizz = wizz || "default";
// same as: if (wizz) { aWizz = wizz; } else { aWizz = "default"; }
The trinary operator can be chained to act like Scheme's (cond ...):
(cond (predicate (action ...))
(predicate2 (action2 ...))
(#t default ))
can be written as...
predicate ? action( ... ) :
predicate2 ? action2( ... ) :
default;
This is very "functional", as it branches your code without side effects. So instead of:
if (predicate) {
foo = "one";
} else if (predicate2) {
foo = "two";
} else {
foo = "default";
}
You can write:
foo = predicate ? "one" :
predicate2 ? "two" :
"default";
Works nice with recursion, too :)
-
I like the predicate syntax you give. I've never thought of chaining like that. neat.Allain Lalonde– Allain Lalonde09/23/2008 22:08:52Commented Sep 23, 2008 at 22:08
-
2Uh... JavaScript does have a switch() statement. :-)staticsan– staticsan06/22/2009 00:54:32Commented Jun 22, 2009 at 0:54
-
I'm not a big fan of switch statements - they're an artifact of C, not functional programming. In my example, a switch statement would still need three separate statements, all starting with "foo =" - obvious unecessary repetition.Andrey Fedorov– Andrey Fedorov06/22/2009 07:14:16Commented Jun 22, 2009 at 7:14
-
14I, for one, welcome the ternary operator.thomasrutter– thomasrutter03/18/2010 16:11:14Commented Mar 18, 2010 at 16:11
-
8On re-reading, I'd like to point out that this isn't "making code look like another language", but actually simplifying the semantic meaning of the code: when you're trying to say "set foo to one of three things", that's a statement that should begin with "foo = ...", not "if".Andrey Fedorov– Andrey Fedorov03/22/2010 19:59:39Commented Mar 22, 2010 at 19:59
Numbers are also objects. So you can do cool stuff like:
// convert to base 2
(5).toString(2) // returns "101"
// provide built in iteration
Number.prototype.times = function(funct){
if(typeof funct === 'function') {
for(var i = 0;i < Math.floor(this);i++) {
funct(i);
}
}
return this;
}
(5).times(function(i){
string += i+" ";
});
// string now equals "0 1 2 3 4 "
var x = 1000;
x.times(function(i){
document.body.innerHTML += '<p>paragraph #'+i+'</p>';
});
// adds 1000 parapraphs to the document
-
OMG! I didn't know about toString(radix)...Ateş Göral– Ateş Göral01/08/2010 16:56:03Commented Jan 8, 2010 at 16:56
-
1That implementation of
times
is not efficient:Math.floor
is called every time instead of just once.dolmen– dolmen03/29/2011 07:55:06Commented Mar 29, 2011 at 7:55
How about closures in JavaScript (similar to anonymous methods in C# v2.0+). You can create a function that creates a function or "expression".
Example of closures:
//Takes a function that filters numbers and calls the function on
//it to build up a list of numbers that satisfy the function.
function filter(filterFunction, numbers)
{
var filteredNumbers = [];
for (var index = 0; index < numbers.length; index++)
{
if (filterFunction(numbers[index]) == true)
{
filteredNumbers.push(numbers[index]);
}
}
return filteredNumbers;
}
//Creates a function (closure) that will remember the value "lowerBound"
//that gets passed in and keep a copy of it.
function buildGreaterThanFunction(lowerBound)
{
return function (numberToCheck) {
return (numberToCheck > lowerBound) ? true : false;
};
}
var numbers = [1, 15, 20, 4, 11, 9, 77, 102, 6];
var greaterThan7 = buildGreaterThanFunction(7);
var greaterThan15 = buildGreaterThanFunction(15);
numbers = filter(greaterThan7, numbers);
alert('Greater Than 7: ' + numbers);
numbers = filter(greaterThan15, numbers);
alert('Greater Than 15: ' + numbers);
-
1i'm unsure, but can return (numberToCheck > lowerBound) ? true : false; simply become return (numberToCheck > lowerBound); just trying to increase my understanding...davidsleeps– davidsleeps06/10/2009 04:15:30Commented Jun 10, 2009 at 4:15
-
4I'd say anonymous functions in C# are equivalent of closures, not the other way around :)vava– vava08/23/2009 09:23:50Commented Aug 23, 2009 at 9:23
-
11Closures and anonymous functions are separate, distinct concepts. That functions can be created without being named is having anonymous functions. That a variable in the 'creating' scope is linked with the created function is a closure. In short, a closure is more like a hidden global variable.slebetman– slebetman01/11/2010 13:52:21Commented Jan 11, 2010 at 13:52
-
1That's true. Only when anonymous methods make use of a variable from the creating scope is it similar to a closure. I've updated the english on the answer. It still leaves something to be desired, but I'm at a lost for the correct english.Tyler– Tyler01/29/2010 18:01:55Commented Jan 29, 2010 at 18:01
-
2I don't think this is the best or easiest to understand example of what a closure is. Just saying. The point of a closure is that even when a bunch of variables appear to 'go out of scope' they can still remain available to a function that was originally defined within that scope. In the above example, that means the lowerBound variable is still accessible by that inner, anonymous function even when the outer function, buildGreaterThanFunction, terminates.thomasrutter– thomasrutter03/18/2010 16:08:12Commented Mar 18, 2010 at 16:08
You can also extend (inherit) classes and override properties/methods using the prototype chain spoon16 alluded to.
In the following example we create a class Pet and define some properties. We also override the .toString() method inherited from Object.
After this we create a Dog class which extends Pet and overrides the .toString() method again changing it's behavior (polymorphism). In addition we add some other properties to the child class.
After this we check the inheritance chain to show off that Dog is still of type Dog, of type Pet, and of type Object.
// Defines a Pet class constructor
function Pet(name)
{
this.getName = function() { return name; };
this.setName = function(newName) { name = newName; };
}
// Adds the Pet.toString() function for all Pet objects
Pet.prototype.toString = function()
{
return 'This pets name is: ' + this.getName();
};
// end of class Pet
// Define Dog class constructor (Dog : Pet)
function Dog(name, breed)
{
// think Dog : base(name)
Pet.call(this, name);
this.getBreed = function() { return breed; };
}
// this makes Dog.prototype inherit from Pet.prototype
Dog.prototype = new Pet();
// Currently Pet.prototype.constructor
// points to Pet. We want our Dog instances'
// constructor to point to Dog.
Dog.prototype.constructor = Dog;
// Now we override Pet.prototype.toString
Dog.prototype.toString = function()
{
return 'This dogs name is: ' + this.getName() +
', and its breed is: ' + this.getBreed();
};
// end of class Dog
var parrotty = new Pet('Parrotty the Parrot');
var dog = new Dog('Buddy', 'Great Dane');
// test the new toString()
alert(parrotty);
alert(dog);
// Testing instanceof (similar to the `is` operator)
alert('Is dog instance of Dog? ' + (dog instanceof Dog)); //true
alert('Is dog instance of Pet? ' + (dog instanceof Pet)); //true
alert('Is dog instance of Object? ' + (dog instanceof Object)); //true
Both answers to this question were codes modified from a great MSDN article by Ray Djajadinata.
You may catch exceptions depending on their type. Quoted from MDC:
try {
myroutine(); // may throw three exceptions
} catch (e if e instanceof TypeError) {
// statements to handle TypeError exceptions
} catch (e if e instanceof RangeError) {
// statements to handle RangeError exceptions
} catch (e if e instanceof EvalError) {
// statements to handle EvalError exceptions
} catch (e) {
// statements to handle any unspecified exceptions
logMyErrors(e); // pass exception object to error handler
}
NOTE: Conditional catch clauses are a Netscape (and hence Mozilla/Firefox) extension that is not part of the ECMAScript specification and hence cannot be relied upon except on particular browsers.
-
29I couldn't help it: catch (me if youCan)Ateş Göral– Ateş Göral01/29/2009 05:24:55Commented Jan 29, 2009 at 5:24
-
6Read the note from the MDC page you cited: conditional catch clauses are a Netscape (and hence Mozilla/Firefox) extension that is not part of the ECMAScript specification and hence cannot be relied upon except on particular browsers.Jason S– Jason S09/22/2009 23:38:01Commented Sep 22, 2009 at 23:38
Off the top of my head...
Functions
arguments.callee refers to the function that hosts the "arguments" variable, so it can be used to recurse anonymous functions:
var recurse = function() {
if (condition) arguments.callee(); //calls recurse() again
}
That's useful if you want to do something like this:
//do something to all array items within an array recursively
myArray.forEach(function(item) {
if (item instanceof Array) item.forEach(arguments.callee)
else {/*...*/}
})
Objects
An interesting thing about object members: they can have any string as their names:
//these are normal object members
var obj = {
a : function() {},
b : function() {}
}
//but we can do this too
var rules = {
".layout .widget" : function(element) {},
"a[href]" : function(element) {}
}
/*
this snippet searches the page for elements that
match the CSS selectors and applies the respective function to them:
*/
for (var item in rules) {
var elements = document.querySelectorAll(rules[item]);
for (var e, i = 0; e = elements[i++];) rules[item](e);
}
Strings
String.split can take regular expressions as parameters:
"hello world with spaces".split(/\s+/g);
//returns an array: ["hello", "world", "with", "spaces"]
String.replace can take a regular expression as a search parameter and a function as a replacement parameter:
var i = 1;
"foo bar baz ".replace(/\s+/g, function() {return i++});
//returns "foo1bar2baz3"
-
The things you mention... Are they implemented in all browsers?cllpse– cllpse09/28/2008 14:58:36Commented Sep 28, 2008 at 14:58
-
4No. I'm pretty sure that Mosaic lacks most of them.jsight– jsight10/01/2008 16:58:24Commented Oct 1, 2008 at 16:58
-
2The javascript features, yes, they are implemented in all major browsers (IE6/7, FF2/3, Opera 9+, Safari2/3 and Chrome). document.querySelectorAll is not supported in all browsers yet (it's the W3C version of JQuery's $(), and Prototype's $$())Leo– Leo10/09/2008 03:33:22Commented Oct 9, 2008 at 3:33
-
6
arguments.callee
is deprecated and will throw and exception in ECMAScript 5.Hello71– Hello7101/10/2011 03:17:55Commented Jan 10, 2011 at 3:17 -
not quite true. An object key cannot (or rather, should not) use the string "hasOwnProperty" as a name, as that would override the built in object method.Breton– Breton03/07/2011 10:02:28Commented Mar 7, 2011 at 10:02
You can use objects instead of switches most of the time.
function getInnerText(o){
return o === null? null : {
string: o,
array: o.map(getInnerText).join(""),
object:getInnerText(o["childNodes"])
}[typeis(o)];
}
Update: if you're concerned about the cases evaluating in advance being inefficient (why are you worried about efficiency this early on in the design of the program??) then you can do something like this:
function getInnerText(o){
return o === null? null : {
string: function() { return o;},
array: function() { return o.map(getInnerText).join(""); },
object: function () { return getInnerText(o["childNodes"]; ) }
}[typeis(o)]();
}
This is more onerous to type (or read) than either a switch or an object, but it preserves the benefits of using an object instead of a switch, detailed in the comments section below. This style also makes it more straightforward to spin this out into a proper "class" once it grows up enough.
update2: with proposed syntax extensions for ES.next, this becomes
let getInnerText = o -> ({
string: o -> o,
array: o -> o.map(getInnerText).join(""),
object: o -> getInnerText(o["childNodes"])
}[ typeis o ] || (->null) )(o);
-
3That's how Python gets by without a switch statement.outis– outis07/23/2009 10:32:42Commented Jul 23, 2009 at 10:32
-
2The problem is it always evaluates all cases.Kornel– Kornel01/02/2011 21:53:48Commented Jan 2, 2011 at 21:53
-
@porneL this is true, but it confers some benefits: It's logically cleaner: The cases are strings that are looked up on a hashtable, not expressions that each have to be evaluated for equality until one returns true. So while more "values" are evaluated, fewer "keys" are evaluated. Objects can be dynamically generated, and modified for later scalability, reflected for printing UI, or generating docs, and even replaced with a dynamic "lookup" function, which is better than having copy/pasted cases. There's no confusion about breaks, fall-throughs, or default values. Can be JSON serialised...Breton– Breton02/02/2011 03:04:56Commented Feb 2, 2011 at 3:04
-
@porneL oh yeah, and again for the scalability thing, an object can even easily be spun out into an external configuration or data file, a somewhat more straightforward change than with a switch statement- But trivial if designed with an object in mind to begin with.Breton– Breton02/02/2011 03:11:16Commented Feb 2, 2011 at 3:11
-
i know this is a late entry, but unless you have some custom type-checking logic, when is an array ever going work with your example?
var arr = []; typeof arr; // object
keeganwatkins– keeganwatkins10/08/2011 04:57:01Commented Oct 8, 2011 at 4:57
Be sure to use the hasOwnProperty method when iterating through an object's properties:
for (p in anObject) {
if (anObject.hasOwnProperty(p)) {
//Do stuff with p here
}
}
This is done so that you will only access the direct properties of anObject, and not use the properties that are down the prototype chain.
Private variables with a Public Interface
It uses a neat little trick with a self-calling function definition. Everything inside the object which is returned is available in the public interface, while everything else is private.
var test = function () {
//private members
var x = 1;
var y = function () {
return x * 2;
};
//public interface
return {
setx : function (newx) {
x = newx;
},
gety : function () {
return y();
}
}
}();
assert(undefined == test.x);
assert(undefined == test.y);
assert(2 == test.gety());
test.setx(5);
assert(10 == test.gety());
-
1this is called the module pattern, as was dubbed that by Eric Miraglia at yuiblog.com/blog/2007/06/12/module-pattern I do think the name is misleading, should be called the Singleton Pattern or something like that. I might also add that public methods can also call other public methods by using 'this' object. I use this pattern all the time in my code to keep things organized and clean.mjc– mjc08/23/2009 21:53:28Commented Aug 23, 2009 at 21:53