从JS中的构造函数返回这个

时间:2015-05-24 01:44:39

标签: javascript node.js

如果我在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);
});

这会产生所需的行为吗?

5 个答案:

答案 0 :(得分:2)

您可以在构造函数中返回this,但效果与不返回任何内容相同。

来自MDN docs

  

执行代码new Foo(...)时,会发生以下情况:

     
      
  1. 创建一个新对象,继承自Foo.prototype
  2.   
  3. 使用指定的参数调用构造函数Foo   这绑定到新创建的对象。新的Foo相当于新的   Foo(),即如果没有指定参数列表,则不调用Foo   参数。
  4.   
  5. 构造函数返回的对象变为   全新表达的结果。如果构造函数   没有显式返回一个对象,在步骤1中创建的对象是   用来代替。 (通常情况下,施工人员不会返回值,但他们会   如果他们想要覆盖普通对象,可以选择这样做   创作过程。)
  6.   

答案 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,它们都不使用预期的原型链。
  • with 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()