让我们先从JavaScript的正常行为开始。如果您没有从构造函数中返回任何内容,它将按预期工作(当然了)。
因此,
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
并使用您自己的
return
。这意味着
alice
现在指向一个对象,该对象具有设置为
'bar'
的
foo
属性。
简而言之:如果您明确调用了return
,它将覆盖隐式的return
,并且实际使用您自己的return
。请保留HTML标记。
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
,也没有使用预期的原型链。
- 在使用
new
时实际上创建了两个对象:一个由 new
创建,另一个由您使用对象字面量语法创建。这意味着垃圾收集器需要更多的工作。
因此,我认为您应该避免使用此技术,而要么正确地使用构造函数,要么坚持使用工厂函数。
这与
@maboiteaspam 的答案 中利用的效果相同:
function DHT (opts) {
var self = this
if (!(self instanceof DHT)) return new DHT(opts)
}
如果你用
new
调用这个函数,
this
会被设置为一个对象,它的
constructor
属性指向
DHT
函数。因此,
self instanceof DHT
返回true,实际的构造函数就会运行。
如果你不使用
new
调用这个函数,
if
语句会检测到这一点,并自动为你运行
new
(这至少比上述解决方案好,在那里你最终会遇到两个缺点)。
请注意,在严格模式下,不允许从没有在对象上调用的函数中访问
this
,因此如果你尝试访问
this
而没有使用
new
关键字调用构造函数,就会立即出现错误。
return this
,并尝试删除冗余和令人困惑的语句。如果那听起来有点刻薄,我很抱歉,但我个人认为可读性很重要,而熟悉度是可读性的一部分。如果没有一个非常好的理由改变众所周知的模式,最好不要这样做。如果您确实要更改,请使用注释明确说明更改。这一切都是基于你的整个团队没有要求return this
模式,如果有的话,请忘记我说的一切。 - Sukimanew
关键字或不使用时都获得一致的行为,请不要使用this
,而是使用其他变量并返回它,例如var self = {}; ... return self
。 - Matt Brownefunction functionNamesLikeThis()
只是一个函数,而function ClassNamesLikeThis()
则是一个构造函数。这与使用下划线表示私有属性this.publicProperty
与this._privateProperty
的约定没有什么不同。许多样式指南建议像Google的https://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml?showone=Naming#Naming一样。 - Sukima