Reputation: 7438
Consider the example module creation, why parenthesis changes this
reference?
As section 11.2.2 in JavaScript specification says:
The production NewExpression : new NewExpression is evaluated as follows:
- Let ref be the result of evaluating NewExpression.
- Let constructor be GetValue(ref).
- If Type(constructor) is not Object, throw a TypeError exception.
- If constructor does not implement the
[[Construct]]
internal method, throw a TypeError exception.- Return the result of calling the
[[Construct]]
internal method on constructor, providing no arguments (that is, an empty list of arguments).
After some investigation there are no differences (are there?) between:
console.log(new (modules.getModule('foo')).method)
console.log(new (modules.getModule('foo')).method())
In both samples method
were executed.
To be more interesting:
console.log(typeof new modules.getModule('foo').method) // function
console.log(typeof new (modules.getModule('foo')).method) // object
What is the source of those differences?
var modules = (function() {
var definitions = {
foo: {
method: function() {
this.thing = 'baz';
}
}
};
return {
getModule: function(name) {
if(name in definitions) {
return definitions[name];
}
}
};
}());
alert('this: ' + new modules.getModule('foo').method()) // undefined
alert('this: ' + new (modules.getModule('foo')).method()) // {this.thing = 'baz'}
Upvotes: 2
Views: 172
Reputation: 137
The variable modules gets the value that is returned by the anonymous function: an object with a method getModule.
In the first case:
console.log(new (modules.getModule('foo')).method)
new is applied to the function method of object foo (which is the result of modules.getModule('foo'). The console should show the function method. In the second case:
console.log(new (modules.getModule('foo')).method())
Now, new is applied to the object foo (which is the result of modules.getModule('foo'). The object foo has a method method. But this time, method is executed. The console should show an object with property baz.
console.log(typeof new modules.getModule('foo').method) // function
Here, you ask the type of the method method of the object foo (the result of modules.getModule('foo')). The type is, obviously, a function.
console.log(typeof (modules.getModule('foo')).method) // object
Here, you ask for the type of the method method which is part of the object foo (which is the result of modules.getModule('foo'))
Upvotes: 0
Reputation: 664538
Parentheses don't change the this
reference of a method call. Parentheses change the NewExpression
that new
evaluates.
If the new
operator is in front of a property chain (an expression followed by accessors), it will evaluate the chain and instantiate the resulting constructor function.
If the new
operator is in front of a call expression (an expression, possibly including accessors, followed by an arguments list), the call will provide the arguments for the new
operation. Any trailing accessors will access properties of the newly instantiated object.
For your examples, that means
new modules.getModule ('foo') .method
new modules.getModule ('foo') .method()
// are evaluated as
(new (modules.getModule)('foo'))…
// on which then .method is accessed or called
new (modules.getModule('foo')).method
new (modules.getModule('foo')).method ()
// are evaluated as
new (( … ).method)() // the empty parentheses are optional for `new`
(modules.getModule('foo')).method
// just evaluates to the `method` function
(modules.getModule('foo').method)
Upvotes: 4