一个构造函数可以返回哪些值以避免返回this?

92

在使用 new 关键字调用构造函数时,有什么确切的情况下,JavaScript 中的 return 语句可以返回一个除了 this 之外的值呢?

例如:

function Foo () {
  return something;
}

var foo = new Foo ();

如果我没记错的话,如果something是一个非函数原始值(primitive),那么this将会被返回。否则返回something。这个说法正确吗?

换句话说,something可以取什么值导致(new Foo() instanceof Foo) === false


6个回答

163

准确的情况在内部属性[[Construct]]中描述,该属性由new运算符使用:

来自ECMA-262第3版规范:

13.2.2 [[Construct]]

当调用Function对象F[[Construct]]属性时,执行以下步骤:

  1. 创建一个新的本地ECMAScript对象。
  2. Result(1)[[Class]]属性设置为"Object"
  3. 获取F的原型属性的值。
  4. 如果Result(3)是一个对象,则将Result(1)[[Prototype]]属性设置为Result(3)
  5. 如果Result(3)不是一个对象,则将Result(1)[[Prototype]]属性设置为原始Object原型对象,如15.2.3.1中所述。
  6. 调用F[[Call]]属性,提供Result(1)作为this值,并提供传递给[[Construct]]的参数列表作为参数值。
  7. 如果Type(Result(6))Object,则返回Result(6)
  8. 返回Result(1)

看步骤 7 和 8,只有当Result(6)(从F构造函数返回的值)的类型不是对象时,才会返回新对象。


17
补充说明:typeof(null)的结果是"object",但是返回null并不会触发第七步。 - B T
8
在测试我的node.js安装时,似乎上面引用的规范中的"Type(x)Object"意味着"x instanceof Objecttrue",而不是"typeof(x) === 'object'true"。例如,null instanceof Object的结果为false(而且你确实不能从构造函数中返回null),而new String("asdf") instanceof Object的结果为true(而且你确实可以从构造函数中返回一个字符串...)。 - Jo So
@JoSo 我认为Type指的是对象的内部[[Class]]属性。从JavaScript内部获得该值的最佳代理是Object.prototype.toString.call(x) - bcherny
4
@JoSo的意思是:不是原始值,而是一个对象(包括数组、函数等)。这与 typeofinstanceof 无关。 - Bergi
1
但为什么不会返回 null 呢? - MartianMartian
2
@Martian2049,因为null值的内部类型是Null Type,所以你可能认为它的内部类型是"object",因为typeof null == 'object',但这不是内部Type操作检测到的。它将返回在步骤1中创建的对象,因为在内部,null值的内部类型是Null,而不是Object。 - Christian C. Salvadó

4
具体例子

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


很好的例子!lll - MartianMartian
new Person({"stuff":"stuff"}) // {"stuff":"stuff"} - MartianMartian

3

我没有找到任何关于这个问题的文档,但是我认为你是正确的。例如,你可以从构造函数返回 new Number(5),但不能返回字面值 5(它会被忽略,而返回 this)。


1
顺便说一下:这是因为 new Number(5)(甚至只是 Number(5),因为如果作为函数调用,其预期的工作方式应该完全相同)创建了一个数字对象。例如,这意味着虽然 '' == false,但 !!new String('') == true - Camilo Martin
1
两年后,我准备回复并更正自己的评论,这个可以工作:function One(){return new Number(1)}但是这个不行:function One(){return Number(1)} - Camilo Martin

1
尝试用简单的话来表达几个要点。
在JavaScript中,当您在函数上使用new关键字并且如果:
  1. 函数没有返回任何内容,则会返回一个预期的对象

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

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

  1. 该函数返回任何真值复杂对象[对象、数组、函数等],该复杂对象具有优先权,变量user将保存返回的复杂对象。

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

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

  1. 函数返回任何文字,构造函数优先级最高,它会返回一个预期对象

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

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


1
作为附注,返回值或者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'

正如您所见,.valueOf()在内部使用,并且可以被利用于娱乐和获利。甚至可以创建副作用,例如:
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

我可以想象这一定有某种实际应用。而且它不必明确地是一个“数字”,如果你给任何对象添加“.valueOf”属性,它就可以表现得像一个数字:
({valueOf: function() { return Math.random(); }}) + 1; // 1.6451723610516638

你可以利用这个来创建一个始终返回新 GUID 的对象,例如。

-1
当你使用 new 关键字时,一个对象将被创建。然后调用函数来初始化该对象。
函数无法阻止对象的创建,因为它是在函数被调用之前完成的。

2
我不是在谈论那个。我知道你可以做到我所说的(我已经尝试过),但我不知道它发生的明确情况。在我的例子中,可能会出现(foo instanceof Foo) === false - Thomas Eding
为什么要点踩?如果你不解释哪里有问题,那么回答就无法得到改进。 - Guffa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接