What values can a constructor return to avoid returning this?

21,675

Solution 1

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 a Function object F is called, the following steps are taken:

  1. Create a new native ECMAScript object.
  2. Set the [[Class]] property of Result(1) to "Object".
  3. Get the value of the prototype property of F.
  4. If Result(3) is an object, set the [[Prototype]] property of Result(1) to Result(3).
  5. If Result(3) is not an object, set the [[Prototype]] property of Result(1) to the original Object prototype object as described in 15.2.3.1.
  6. Invoke the [[Call]] property of F, providing Result(1) as the this value and providing the argument list passed into [[Construct]] as the argument values.
  7. If Type(Result(6)) is Object then return Result(6).
  8. 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.

Solution 2

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('%')));

Solution 3

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).

Solution 4

Trying to put a few points in simpler words.

In javascript, when you use a new keyword on a function and if,

  1. 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'

  1. 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

  1. 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'

Solution 5

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.

Share:
21,675
Thomas Eding
Author by

Thomas Eding

Updated on January 15, 2020

Comments

  • Thomas Eding
    Thomas Eding over 4 years

    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?

  • Thomas Eding
    Thomas Eding over 14 years
    I'm not taking about that. I know you can do what I claim (I've tried it), but I don't know the definitive cases for which it occurs. In my example, it IS possible to end up with (foo instanceof Foo) === false.
  • Camilo Martin
    Camilo Martin over 11 years
    By the way: this happens because new Number(5) (or even just Number(5), as it is intended to work just the same if called as a function) creates a number object, for example this means that while '' == false, !!new String('') == true.
  • B T
    B T almost 11 years
    Additional note: typeof(null) is "object", however returning null does not trigger step 7 to happen
  • Jo So
    Jo So over 10 years
    @BT: Testing on my node.js installation, it seems like "Type(x) is Object" in the spec as cited above means "x instanceof Object is true", not "typeof(x) === 'object' is true". For example, null instanceof Object evaluates to false (and indeed you can't return null from a constructor), and new String("asdf") instanceof Object evaluates to true (and indeed you can return a String from the constructor...)
  • Camilo Martin
    Camilo Martin almost 10 years
    Two years later and ready to reply to correct my own comment, this works: function One(){return new Number(1)} but this doesn't: function One(){return Number(1)}
  • bcherny
    bcherny over 9 years
    @JoSo I think Type refers to an object's internal [[Class]] property. The best proxy for that value that we have from within JavaScript is Object.prototype.toString.call(x)
  • Guffa
    Guffa over 9 years
    Why the downvote? If you don't explain what it is that you think is wrong, it can't improve the answer.
  • Bergi
    Bergi over 9 years
    @JoSo: No. It means that x is not a primitive value, but an object (including arrays, functions etc). It does have nothing to do with typeof or instanceof.
  • MartianMartian
    MartianMartian over 5 years
    great example! lll
  • MartianMartian
    MartianMartian over 5 years
    just add this: new Person({"stuff":"stuff"}) // {"stuff":"stuff"}
  • MartianMartian
    MartianMartian over 5 years
    but why null doesn't get returned ?
  • Christian C. Salvadó
    Christian C. Salvadó over 5 years
    @Martian2049, because the internal type of a null value is the Null Type, internally, you may think that is "object" since typeof null == 'object', but that's not what the internal Type operation detects. It will return the object created in step 1 just because internally, the null value internal type is Null, not Object.