让我们从 JavaScript 的正常行为开始。如果您不从构造函数返回任何内容,它将按预期工作(当然)。
Hence
var Dog = function (name) {
this.name = name;
};
var alice = new Dog('Alice');
结果是一个新对象,其name
属性设置为Alice
.
现在如果你尝试覆盖隐式会发生什么return
通过显式调用声明构造函数吗?
我们来介绍一个return
返回其他内容的语句:
var Dog = function (name) {
this.name = name;
return 23;
};
var alice = new Dog('Alice');
哪个值是alice
现在?也许,你会期望它是23
,但实际上并非如此。它仍然是一个带有name
属性设置为Alice
.
这里的问题是 JavaScript 比你更聪明:它看到你的return
,但意识到您想要返回的内容的类型与使用该函数调用的事实不匹配new
。因此return
被忽略。
现在,如果我们尝试变得比 JavaScript 更聪明并返回类型匹配的东西(即对象)怎么办?
var Dog = function (name) {
this.name = name;
return { foo: 'bar' };
};
var alice = new Dog('Alice');
在这种情况下,JavaScript 认为您有充分的理由覆盖隐式return
并实际使用你的。这意味着alice
现在指向一个带有foo
属性设置为'bar'
.
所以,长话短说:如果你明确地调用
return this;
你最终会遇到最后一个案例。您覆盖隐式返回的对象。但由于您返回的实际上与隐式返回的相同,因此没有区别。
所以:是的,是一样的,但是调用return this;
不需要。
一些开发人员使用此行为来欺骗 JavaScript 始终返回一个新对象,无论您是否调用构造函数new
:
var Dog = function (name) {
return {
name: name
};
};
var alice1 = new Dog('Alice');
var alice2 = Dog('Alice');
两个调用都会产生一个新对象name
属性设置为Alice
,但与前面的例子有一些不同:
- 两个对象都只是对象字面量,其
constructor
属性未设置为Dog
,他们都没有使用预期的原型链。
- 在这种情况下with
new
实际上正在创建两个对象:一个是由new
,另一个由您使用对象字面量语法。这意味着垃圾收集器需要做更多的工作。
因此,我认为您应该避免这种技术,要么正确使用构造函数,要么坚持使用工厂函数。
这与在中使用的效果相同@maboiteaspam 的回答 https://stackoverflow.com/a/30419791/1333873:
function DHT (opts) {
var self = this
if (!(self instanceof DHT)) return new DHT(opts)
// ctor body
}
如果你用以下方式调用这个函数new
, this
被设置为一个对象,其constructor
属性指向DHT
功能。因此self instanceof DHT
返回 true 并且运行实际的构造函数。
如果你调用这个函数时没有new
, the if
语句检测到这一点并运行它new
自动为您提供(这至少比上述解决方案更好,最终会带来两个缺点)。
请注意,严格模式下不允许访问this
来自未在对象上调用的函数,因此调用构造函数时无需new
当您尝试访问时,关键字将导致错误this
.