web-dev-qa-db-fra.com

Quelles valeurs un constructeur peut-il retourner pour éviter de renvoyer cela?

Quelles sont les circonstances exactes pour lesquelles une instruction return en Javascript peut renvoyer une valeur autre que this lorsqu'un constructeur est appelé à l'aide du mot clé new?

Exemple:

function Foo () {
  return something;
}

var foo = new Foo ();

Si je ne me trompe pas, si something est une primitive sans fonction, this sera renvoyé. Sinon, something est renvoyé. Est-ce correct?

IOW, quelles valeurs something peut-il prendre pour causer (new Foo () instanceof Foo) === false?

87
Thomas Eding

La condition exacte est décrite dans la propriété interne [[Construct]], utilisée par l'opérateur new /:

De l'ECMA-262 3ème. Spécifications de l'édition:

13.2.2[[Construct]]

Lorsque la propriété [[Construct]] pour un objet FunctionF est appelées, les mesures suivantes sont prises:

  1. Créez un nouvel objet ECMAScript natif.
  2. Définissez la propriété [[Class]] de Result(1) sur "Object".
  3. Obtient la valeur de la propriété prototype de F.
  4. Si Result(3) est un objet, définissez la propriété [[Prototype]] de Result(1) sur Result(3).
  5. Si Result(3) n'est pas un objet, définissez la propriété [[Prototype]] de Result(1) sur l'objet prototype Object d'origine sur décrit dans 15.2.3.1 .
  6. Appelez la propriété [[Call]] de F, en fournissant Result(1) en tant que valeur this et fournissant la liste d'arguments passée dans [[Construct]] en tant que valeurs d'argument.
  7. Si Type(Result(6)) est Object puis retourne Result(6).
  8. Retourne Result(1).

Regardez les étapes 7 et 8, le nouvel objet ne sera retourné que si le type of Result(6) (la valeur renvoyée par le constructeur F function) est not un objet.

154
CMS

Des exemples concrets 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('%')));
3
philn5d

Je n'ai trouvé aucune documentation à ce sujet, mais je pense que vous avez raison. Par exemple, vous pouvez renvoyer new Number(5) depuis un constructeur, mais pas le 5 littéral (qui est ignoré et this est renvoyé à la place).

2
mkrause

Essayer de mettre quelques points en mots plus simples.

En javascript, lorsque vous utilisez un mot clé new sur une fonction et si,

  1. la fonction ne renvoie rien, elle retournera un objet prévu

function User() {
  this.name = 'Virat'
}

var user = new User();
console.log(user.name); //=> 'Virat'

  1. fonction renvoie tout objettruthycomplex [objet, tableau, fonction, etc.], cet objet complexe est prioritaire et la variable user conservera l'objet complexe renvoyé.

function User() {
  this.name = 'Virat';
  return function(){};
}

var user = new User();
console.log(user.name); //=> undefined
console.log(user); //=> function

  1. la fonction retourne n'importe quel littéral, le constructeur a la priorité et il retournera un objet voulu

function User() {
  this.name = 'Virat';
  return 10;
}

var user = new User();
console.log(user.name); //=> 'Virat'

0
Ravindra Thorat

En remarque, la valeur de retour ou this fait simplement partie de l'équation.

Par exemple, considérons ceci:

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'

Comme vous pouvez le constater, .valueOf() est utilisé en interne et peut être exploité pour le plaisir et pour le profit. Vous pouvez même créer des effets secondaires, par exemple:

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

J'imagine que cela doit avoir certains une sorte d'application pratique. Et il n'est pas nécessaire que ce soit explicitement une Number, si vous ajoutez .valueOf à n'importe quel objet, il peut se comporter comme un nombre:

({valueOf: function() { return Math.random(); }}) + 1; // 1.6451723610516638

Vous pouvez exploiter ceci pour créer un objet qui renvoie toujours un nouveau GUID, par exemple.

0
Camilo Martin