2

I'm starting to play around with Node.js and specifically with the LessCSS compiler. I saw this call on the source code of the lessc script:

new(less.Parser) ({
    paths: [path.dirname(input)].concat(options.paths),
    optimization: options.optimization,
    filename: input,
    strictImports: options.strictImports,
    dumpLineNumbers: options.dumpLineNumbers
}).parse(data, function (err, tree) {
    //...
});

What I don't understand is how that new(lessParser)({}) call works.

From what I've been reading about Object-oriented Javascript I only found examples of new being called like so: object = new Someting

So the questions are: how does new work in that case? Is it calling less.Parser as the constructor? Also, what are the parenthesis (following the new call) executing/returning?

Thanks!

Víctor López García
  • 1,881
  • 1
  • 12
  • 17

2 Answers2

3

The code you posted is exactly technically (or more or less) the same as doing

var parserOptions = {
    paths: [path.dirname(input)].concat(options.paths),
    optimization: options.optimization,
    filename: input,
    strictImports: options.strictImports,
    dumpLineNumbers: options.dumpLineNumbers
};
var parser = new less.Parser(parserOptions);

parser.parse(data, function (err, tree) {
    //...
});

But with a few shortcuts and with some parenthesis in "unconventional" places.

JavaScript is a loose type language and it is interpreted in tokens. Which means that it is not too limiting on it's syntax, as long as the grammar is respected.

This let things like :

var a = false;
var b = function() { };
var c = false;
new(a || b || c)();

be completely valid, and will create a new instance of b as it is the first one non-false value defined after the tested variable a. (Note that it does not check if b is actually a function. If b was non-false and not a function, the JS engine would throw that it is not a function at run-time.)

Community
  • 1
  • 1
Yanick Rochon
  • 51,409
  • 25
  • 133
  • 214
  • Well, the code Yanick posted is not /exactly/ the same. In the original code, no objects are being instantiated in the global namespace. – IvoC Dec 18 '12 at 04:19
  • @IvoC, how so? I just extracted the parts into separate variables. – Yanick Rochon Dec 18 '12 at 04:22
  • @IvoC Why bother commenting without explaining? – Ian Dec 18 '12 at 04:22
  • @IvoC Haha really? And who says it's the global context? Either way, I guess it's true. But **functionally**, it's the "same" – Ian Dec 18 '12 at 04:24
  • 1
    @Yanick. Sorry hit enter too soon / edited my original comment. I think your answer is largely correct, maybe replace "exactly" by "largely" or "more or less" ? (because in your example code, "parser" and "parserOptions" are being created in current namespace) – IvoC Dec 18 '12 at 04:27
  • 1
    @IvoC, the only difference with my code is that I *declare* three variables and assign them the data, whereas the original code use data and create an instance of `less.Parser` without assigning it to anything. But I shall precise that part of my answer :) It is *technically* correct that is is *not* exactly the same. – Yanick Rochon Dec 18 '12 at 04:27
  • @YanickRochon thanks! IOW, to confirm I understand, the first parenthesis are not "sending parameters in" to `new`, it's evaluating the `less.Parser` token(?) and using that as the function to be called with the options array. – Víctor López García Dec 18 '12 at 04:44
  • @frntk, yes, exactly; `less.Parser` is a token that represent a function constructor, and it sends the options object (not array) :) – Yanick Rochon Dec 18 '12 at 05:08
1

Just a comment really.

The expression new(less.Parser)({…}) is identical to new less.Parser({…}).

The parenthesis are a grouping operator that says "evaluate this expression as a single expression". It is common to use that syntax when the expression in the parenthesis would return a different result without the parenthesis, e.g.

var x, y = 7;

alert( typeof (x || y))  // "number"

alert( typeof  x || y )  // "undefined"

But since they make no difference to the outcome in the OP, they are pointless and possibly harmful as they change a well known pattern into one that might appear to some as if new can be called as a function.

RobG
  • 142,382
  • 31
  • 172
  • 209