如果我在JavaScript中有构造函数,我希望能够明确地返回一些东西,以便在团队中工作时一切都清楚。
我读到如果你在JS中使用一个函数作为构造函数,如果你返回任何东西,那么使用new关键字将是一个浪费的努力。但我想知道你是否可以从构造函数返回<div id="tabs_wrap">
<ul> 'Js render list here' </ul>
</div>
<div class="section sc-01" id="title01">
<h3>Title-01</h3>
</div>
<div class="section sc-02" id="title02">
<h3>Title-02</h3>
</div>
<div class="section sc-03" id="title03">
<h3>Title-03</h3>
</div>
<div class="section sc-04" id="title04">
<h3>Title-04</h3>
</div>
<div class="section sc-05" id="title05">
<h3>Title-05</h3>
</div>
并且是安全的,例如:
$('.section h3').text(function() {
$(this).parents().eq(0).attr('id', $(this).text().toLowerCase().replace(/[^\w ]+/g, '').replace(/ +/g, '').substring(0, 14));
});
var secH3 = $('.section h3').each(function() {
$(this).text();
});
var secId = $('.section').each(function() {
$(this).attr('id');
});
$('.section').each(function() {
$('#tabs_wrap ul').append('<li><a></a></li>');
});
$('#tabs_wrap ul > li a').each(function() {
$(this).attr('href', '#' + secH3);
});
这会产生所需的行为吗?
答案 0 :(得分:2)
您可以在构造函数中返回this
,但效果与不返回任何内容相同。
来自MDN docs:
执行代码
new Foo(...)
时,会发生以下情况:
- 创建一个新对象,继承自
Foo.prototype
。- 使用指定的参数调用构造函数Foo 这绑定到新创建的对象。新的Foo相当于新的
Foo()
,即如果没有指定参数列表,则不调用Foo 参数。- 构造函数返回的对象变为 全新表达的结果。如果构造函数 没有显式返回一个对象,在步骤1中创建的对象是 用来代替。 (通常情况下,施工人员不会返回值,但他们会 如果他们想要覆盖普通对象,可以选择这样做 创作过程。)
醇>
答案 1 :(得分:2)
另一种方法可能是:
function DHT (opts) {
var self = this
if (!(self instanceof DHT)) return new DHT(opts)
// ctor body
}
积分转到https://github.com/feross/bittorrent-dht/blob/master/client.js
答案 2 :(得分:2)
我很确定你要找的是命名约定而不是语言功能。这种方法的问题在于你混淆了意图。想象一下,您将这种编码风格作为团队的一部分。如果我在上面,那么在处理代码时,我可能会在头脑中多次使用以下对话框:
var foo - foobar(); // Um wait is this a constructor or a function?
// I guess I'll have to look it up:
function foobar() {
// skip a bunch of code.
return this;
}
// Huh? Why do I need to return this? And what is this supposed to refer to?
// Do I need to always provide a context when calling this function?
// Oh wait that some weird convention I was told about during employee initiation.
// Guess I have to deal with this for now and note to self:
// Brush up my resume, gonna need it soon.
var foo = new foobar();
因此,道德是在使用函数时,程序员没有信息如何调用该函数。
更好的方法是使用命名约定,因为以大写字母开头的每个函数都是构造函数,而小写只是一个普通函数。
这个惯例是众所周知的,并且被许多团队使用:
function FooBar() {}
var foo = new FooBar(); // Capital letter need to use new
var bar = fooBar(); // lowercase means a normal function.
答案 3 :(得分:2)
让我们从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
,但是意识到你要返回的东西的类型与使用{{1}调用函数的事实不匹配}}。因此忽略new
。
现在如果我们试图比JavaScript更聪明并返回类型匹配的东西,即对象呢?
return
在这种情况下,JavaScript认为您有充分的理由覆盖隐式var Dog = function (name) {
this.name = name;
return { foo: 'bar' };
};
var alice = new Dog('Alice');
并实际使用您的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
,它们都不使用预期的原型链。new
的情况下,实际上创建了两个对象:一个由new
创建,另一个由您使用对象文字语法创建。这意味着垃圾收集器的工作量会增加。因此,我认为,您应该避免使用这种技术,并正确使用构造函数或坚持工厂函数。
这与@maboiteaspam's answer中使用的效果相同:
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
的情况下调用此函数,if
语句会自动检测到此问题并使用new
自动运行(至少比上述解决方案更好)最终有两个缺点)。
请注意,在严格模式下,不允许从未在对象上调用的函数访问this
,因此调用不带new
关键字的构造函数会导致错误您尝试访问this
。
答案 4 :(得分:1)
更新:实际上,在严格模式下,this
未定义,因此忘记使用this
的程序员会立即收到错误 - 因此这是他们发现错误的最快方式。因此,简单地使用严格模式可能是最佳解决方案:
"use strict";
function MyConstructor(val){
this.val = val;
}
(或者你可以在函数内部使用严格的&#34;如果你在同一个脚本中有其他代码,你不想在严格的模式下运行。)
以下是一个示例,它更详细地展示了无论是否使用new
,如何使其工作原理相同:
function MyConstructor(val) {
var self = Object.create(MyConstructor.prototype);
self.constructor = MyConstructor;
self.val = val;
return self;
}
var example = new MyConstructor(val);
var example2 = MyConstructor(val); //same result
当然,这有点冗长,所以在实践中,在@ maboiteaspam的回答中使用这种方法可能更简单。
我个人并不担心这个;如果程序员未能使用new
关键字,他们应该注意到错误,因为他们只会返回window
对象(如果在严格模式下则为null)而不是新的对象实例。
但是如果你喜欢一种根本不需要使用new
关键字的风格,那么你可以考虑使用一个用于更多原型用途的库,例如:
或者您可以使用命名约定,使预期用法更清晰,正如@Sukima建议的那样。你可以在制造商的功能前加上&#34; make&#34;或&#34;创建&#34;使其更清晰,例如makeUser()
或createUser()
。或者使用&#34; selfish&#34;上面的图书馆,User.new()
。