What values can a constructor return to avoid returning this?
What are the exact circumstances for which a return
statement in Javascript can return a value other than this
when a constructor is invoked using the new
keyword?
Example:
function Foo () {
return something;
}
var foo = new Foo开发者_运维知识库 ();
If I'm not mistaken, if something
is a non-function primitive, this
will be returned. Otherwise something
is returned. Is this correct?
In other words, what values can something
take to cause (new Foo () instanceof Foo) === false
?
The exact condition is described on the [[Construct]]
internal property, which is used by the new
operator:
From the ECMA-262 3rd. Edition Specification:
13.2.2
[[Construct]]
When the
[[Construct]]
property for aFunction
objectF
is called, the following steps are taken:
- Create a new native ECMAScript object.
- Set the
[[Class]]
property ofResult(1)
to"Object"
.- Get the value of the prototype property of
F
.- If
Result(3)
is an object, set the[[Prototype]]
property ofResult(1)
toResult(3)
.- If
Result(3)
is not an object, set the[[Prototype]]
property ofResult(1)
to the originalObject
prototype object as described in 15.2.3.1.- Invoke the
[[Call]]
property ofF
, providingResult(1)
as thethis
value and providing the argument list passed into[[Construct]]
as the argument values.- If
Type(Result(6))
isObject
then returnResult(6)
.- Return
Result(1)
.
Look at steps 7 and 8, the new object will be returned only if the
type of Result(6)
(the value returned from the F
constructor
function) is not an Object.
Concrete examples http://jsbin.com/zivivucahi/1/edit?html,js,console,output
/*
ECMA 262 v 5
http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf
"4.3.2
primitive value
member of one of the types Undefined, Null, Boolean, Number, Symbol, or String as defined in clause 6"
*/
var Person = function(x){
return x;
};
console.log(Person.constructor);
console.log(Person.prototype.constructor);
console.log(typeof(Person));
console.log(typeof(Person.prototype));
function log(x){
console.log(x instanceof Person);
console.log(typeof x);
console.log(typeof x.prototype);
}
log(new Person(undefined));
log(new Person(null));
log(new Person(true));
log(new Person(2));
log(new Person(""));
//returns a function not an object
log(new Person(function(){}));
//implementation?
//log(new Person(Symbol('%')));
I couldn't find any documentation on the matter, but I think you're correct. For example, you can return new Number(5)
from a constructor, but not the literal 5
(which is ignored and this
is returned instead).
As a side note, the return value or this
is just part of the equation.
For example, consider this:
function Two() { return new Number(2); }
var two = new Two;
two + 2; // 4
two.valueOf = function() { return 3; }
two + 2; // 5
two.valueOf = function() { return '2'; }
two + 2; // '22'
As you can see, .valueOf()
is internally used and can be exploited for fun and profit. You can even create side effects, for example:
function AutoIncrementingNumber(start) {
var n = new Number, val = start || 0;
n.valueOf = function() { return val++; };
return n;
}
var auto = new AutoIncrementingNumber(42);
auto + 1; // 43
auto + 1; // 44
auto + 1; // 45
I can imagine this must have some sort of practical application. And it doesn't have to be explicitly a Number
either, if you add .valueOf
to any object it can behave as a number:
({valueOf: function() { return Math.random(); }}) + 1; // 1.6451723610516638
You can exploit this to make an object that always returns a new GUID, for instance.
Trying to put a few points in simpler words.
In javascript, when you use a new
keyword on a function and if,
- function does not return anything, it will return an intended object
function User() {
this.name = 'Virat'
}
var user = new User();
console.log(user.name); //=> 'Virat'
- function returns any truthy complex object [object, array, function etc], that complex object takes priority and
user
variable will hold the returned complex object
function User() {
this.name = 'Virat';
return function(){};
}
var user = new User();
console.log(user.name); //=> undefined
console.log(user); //=> function
- function returns any literal, constructor takes priority and it will return an intended object
function User() {
this.name = 'Virat';
return 10;
}
var user = new User();
console.log(user.name); //=> 'Virat'
When you are using the new
keyword, an object is created. Then the function is called to initialise the object.
There is nothing that the function can do to prevent the object being created, as that is done before the function is called.
精彩评论