JS Array.map gotcha

Thursday, November 15th, 2012

I was working on a project today and was seeing weird sort behavior and couldn’t figure out what was going on for a while. I finally discovered that JavaScript Array.map wasn’t returning the values I expected. In particular:

> "11.4.402.265".split('.').map(parseInt)
[11, NaN, NaN, 2]

I was a little worried that Mozilla was broken, so I asked the JS experts in IRC and got this interesting diagnosis from Jeff Walden (Waldo):

parseInt takes a second parameter that’s a radix; map calls its function with (value, index, thisArray)

This magic behavior of Array.map can be useful if you want to do even-odd behavior or other tasks, but it happened to be my personal footgun today. Be careful! My code now interposes its own function:

a.split('.').map(function(i) { return parseInt(i); });

I’m not sure I really want to know why parseInt(11, 0) returns 11.

Running Extension Code In Another Process

Friday, December 3rd, 2010

In order to support running Jetpack-style extensions in another process, Firefox 4 has support for running arbitrary JavaScript code in a separate process. Although this code was designed primarily to support the Jetpack SDK, Firefox and extensions can use this support to run arbitrary code in a separate process.

Running code in a separate process has advantages similar to running code in a separate thread. The running code will not block the main Firefox user interface. An added advantage is crash protection: if the code causes a crash, it will not take down the entire browser. There may also be some performance benefits from separating the garbage collection heaps and avoiding XPCOM overhead.

The basic steps to start a subprocess and run code in it are as follows:

var process = Components.classes["@mozilla.org/jetpack/service;1"].
  getService(Components.interfaces.nsIJetpackService).createJetpack();
process.evalScript("Put your JS here");
// When you are done with the process, you should explicitly destroy it.
process.destroy();

Of course, running a script in another process isn’t that useful unless you can communicate with it. This is accomplished by passing messages back and forth. To send a message to the remote process, use process.sendMessage:

process.sendMessage("messageName", param...)

To receive messages from the remote process, register a receiver function:

process.registerReceiver("messageName, function(messageName, argument...) { ... });

The remote process has access to a similar set of global functions, as well as the ability to create sandboxes and use ctypes. For more information about the full capabilities, see the Mozilla Developer Center documentation. Note that code running in a jetpack-style process does not have access to XPCOM, because XPCOM is not started in the jetpack process; it runs code using only the JavaScript engine.

If an extension is using ctypes to work with third-party code or OS libraries, I strongly encourage that extension to consider running the code in a separate process for crash protection. If an extension has long-running or computationally expensive tasks, it might make sense to move those into a separate process as well. If nothing else, it will make it much easier to measure the CPU and memory usage of that code separate from the rest of Firefox.

Wordmaps without Java

Friday, December 12th, 2008

Word maps generated by wordle.net have been making the rounds. They are very cool representations of the frequency that various words appear in a hunk of text (such as a blog feed). Unfortunately, the code to generate these word maps is not open source, and it requires Java.

So I decided to take on Johnath’s challenge and produce something similar using HTML canvas and JavaScript:

Wordmap of BSBlog

You can take it for a spin too, but only if you have Firefox 3.1. Try it out!. I’m currently using some features that are specific to Firefox 3.1, such as JavaScript 1.8 and Canvas.measureText. I think I can backport this code to support Firefox 3 by checking for .mozMeasureText and .mozTextStyle. I don’t know whether Safari currently supports text drawing or measurement in their canvas implementation. If they do, this can probably be made to work there as well.

If you’re interested in the code, a Mercurial repository is available on hg.mozilla.org. There are a couple improvement possibilities noted in the README file. Some other possibilities that I’m just thinking of now:

  • Produce an image map to make all the terms link to the relevant post(s).
  • Produce SVG output to make the output scalable.

JSON serialization of interconnected object graphs

Thursday, August 21st, 2008

In it’s basic form, JSON cannot serialize cyclic graphs of objects, or graphs where multiple paths can lead to the same object. In a project I’m working on, I wanted to move such a graph of highly-interconnected objects from JS to python. So I have invented a format built on top of JSON that can be used to serialize/deserialize such graphs.

Basically, the JSON comes across as a large list:

[
  /* list[0] is the base object at the root of the eventual object graph. */
  {
    /* string, number, true/false, and null properties are serialized directly */
    "stringprop": "stringvalue",
    "numprop": 3.1415,
    /* but lists and objects are not serialized directly. Instead, they are represented by an index
       into the base list. "sharp" is a nod to JS sharp variables, from which this was originally inspired */
    "complexprop": {"sharp": 1}
  },
  /* list[1] is referenced from list[0].complexprop. It also references itself, see below */
  [
    "simplestring",
    3,
    {"sharp": 1}
  ]
]

You can find JS for serializing these types of graphs here, and python for deserializing them here.

It turns out that I probably don’t actually need this code: I’ve found a simpler solution for my particular problem, but I wanted to share this solution in case other people might find it useful.

String Formatting in JavaScript

Tuesday, July 15th, 2008

I am a relative newcomer to python, and have been blown away by the flexibility of some operations in Python. The string-formatting operator, %, is really wonderful and flexible. This is my attempt at implementing something similar in JavaScript.

Obviously, you can’t create a new operator in JavaScript, and in addition you can’t use % as a JavaScript identifier. So I went for the next-best thing:

String.prototype.format = function string_format(d) {
  // there are two modes of operation... unnamed indices are read in order;
  // named indices using %(name)s. The two styles cannot be mixed.
  // Unnamed indices can be passed as either a single argument to this function,
  // multiple arguments to this function, or as a single array argument
  let curindex = 0;

  if (arguments.length > 1)
    d = arguments;
  
  function r(s, key, type) {
    let v;
    if (key == "") {
      if (curindex == -1)
        throw Error("Cannot mix named and positional indices in string formatting.");

      if (curindex == 0 && (!(d instanceof Object) || !(0 in d)))
        v = d;
      else if (!(curindex in d))
        throw Error("Insufficient number of items in format, requesting item %i".format(curindex));
      else
        v = d[curindex];

      ++curindex;
    }
    else {
      key = key.slice(1, -1);
      if (curindex > 0)
        throw Error("Cannot mix named and positional indices in string formatting.");
      curindex = -1;
      
      if (!(key in d))
        throw Error("Key '%s' not present during string substitution.".format(key));
      v = d[key];
    }
    switch (type) {
    case "s":
      return v.toString();
    case "r":
      return v.toSource();
    case "i":
      return parseInt(v);
    case "f":
      return Number(v);
    case "%":
      return "%";
    default:
      throw Error("Unexpected format character '%s'.".format(type));
    }
  }
  return this.replace(/%(\([^)]+\))?(.)/g, r);
};
String.prototype.ø = String.prototype.format;

If you are at all familiar with the python string-formatting operator, this should be very similar:

"%s %s".ø("angry", "monkeys"); == "angry monkeys";
"%(key)s: %(value)s".ø({key: 'bananas', value: 'tasty'}) == "bananas: tasty";
"%i - %i".ø([1, 3]) == "1 - 3";
"%r".ø(['α', 'ω'] == '["α", "ω"]';

I know that there are many sprintf-like libraries out there for JavaScript: I just happen to like mine best. Caution: this code requires JavaScript 1.7… if you replace some “let”s with “var”s it may work in older browsers, but I haven’t tested it.

Being able to pass a function as a replacement in String.replace is a very powerful feature!

emacs javascript mode

Tuesday, April 15th, 2008

Dear lazyweb,

I would really really love a JavaScript mode for emacs which indented “for each” correctly:

for each(let o in a) {
  // single indent
  process(o);
}

I’d love it enough to buy a 6-pack for the person who made it happen.

Bound Functions and Function Imports in JavaScript

Wednesday, January 3rd, 2007

After playing with the code in my last post, and asking some apparently silly questions about the ES4 spec, I’ve found some techniques which can be used to implement python-style “import” using current JavaScript.

References to Bound Functions

In python, it is possible to hold a reference to an unbound method, or to a method which is bound to a particular object:

>>>class Foo:
...  def dumpMe(self, arg):
...    print "self: %s\narg: %s" % (self, arg)
...
>>> Foo.dumpMe
<unbound method Foo.dumpMe>
>>> Foo().dumpMe
<bound method Foo.dumpMe of <__main__.Foo instance at 0x2aaaaab33680>>
>>> Foo.dumpMe("something")
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: unbound method dumpMe() must be called with Foo instance as first argument (got str instance instead)
>>> Foo().dumpMe("something")
self: <__main__.Foo instance at 0x2aaaaab33d40>
arg: something

The JavaScript language does not have a built-in syntax to obtain a bound method:

js> function Foo() { }
js> Foo.prototype.dumpMe = function(arg) {
  dump("this: " + this + "\narg: " + arg);
}
js> new Foo().dumpMe
function (arg) {
    print("this: " + this + "\narg: " + arg);
}
js> f = new Foo();
js> f.dumpMe("test")
this: [object Object]
arg: test
js> unbound = new Foo().dumpMe
js> unbound("test")
this: [object BackstagePass @ 0x6214e0 (native @ 0x513fc8)]
arg: test

(The BackstagePass object is the global object in xpcshell).

However, with a little extra code it is possible to emulate bound functions in JavaScript:

js> Function.prototype.bind = function(object) {
  var func = this;
  return function() { return func.apply(object, arguments); }
}
js> boundFunc = f.dumpMe.bind(f);
js> boundFunc("test")
this: [object Object]
arg: test

We can then use bound functions to emulate the from module import x, y, x statement of python:

js> function jsimport(module) {
  // this function has two forms:
  // jsimport(module) is equivalent to python "from module import *"
  // jsimport(module, "name" [, "name2"]) is equivalent to python "from module import name, name2"

  // NOTE: "this" is the global object
  function internal_import(name) {
    if (module[name] instanceof Function) {
      this[name] = module[name].bind(module);
    }
    else {
      this[name] = module[name];
    }
  }

  if (arguments.length == 1) {
    for (name in module) {
      if (module.hasOwnProperty(name)) {
        internal_import(name);
      }
    }
  }
  else {
    for (i = 1; i < arguments.length; ++i) {
      internal_import(arguments[i]);
    }
  }
}

You could use this technique today to hide away the IOService or PrefService a little:

jsimport(Components.classes["@mozilla.org/preferences/pref-service;1"].getService(Components.interfaces.nsIPrefBranch),
         "getCharPref", "getIntPref", "getBoolPref");

if (getBoolPref("dom.window.dump.enabled"))
  // do something dumpy