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
?
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 objetFunction
F
est appelées, les mesures suivantes sont prises:
- Créez un nouvel objet ECMAScript natif.
- Définissez la propriété
[[Class]]
deResult(1)
sur"Object"
.- Obtient la valeur de la propriété prototype de
F
.- Si
Result(3)
est un objet, définissez la propriété[[Prototype]]
deResult(1)
surResult(3)
.- Si
Result(3)
n'est pas un objet, définissez la propriété[[Prototype]]
deResult(1)
sur l'objet prototypeObject
d'origine sur décrit dans 15.2.3.1 .- Appelez la propriété
[[Call]]
deF
, en fournissantResult(1)
en tant que valeurthis
et fournissant la liste d'arguments passée dans[[Construct]]
en tant que valeurs d'argument.- Si
Type(Result(6))
estObject
puis retourneResult(6)
.- 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 constructeurF
function) est not un objet.
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('%')));
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).
Essayer de mettre quelques points en mots plus simples.
En javascript, lorsque vous utilisez un mot clé new
sur une fonction et si,
function User() {
this.name = 'Virat'
}
var user = new User();
console.log(user.name); //=> 'Virat'
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
function User() {
this.name = 'Virat';
return 10;
}
var user = new User();
console.log(user.name); //=> 'Virat'
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.