Javascript this.function vs return function?

3

我有点困惑于学习JavaScript的新ES6与ES5语法,特别是在涉及带有方法的函数/类和调用这些方法时,我无法确定什么是“正确的方式”。

例如,看一下这段代码:

function account(amount) {
    let cash = amount;
  this.setCash = function(amt)
  {
    cash = amt;
  }
  this.getCash = function()
  {
    return cash;
  }
}
var person = new account(100);
console.log(person.getCash()); //returns 100
person.setCash(150);
console.log(person.getCash()); //returns 150

按照预期正常工作(当我浏览教程时,这就是我最初看到使用这些方法的方式)。

但是我偶尔会看到这种情况:

function account2(amount) {
    let cash = amount;
    function setCash(amt)
  {
    cash = amt;
  }
  function getCash()
  {
    return cash;
  }
  return{
    getCash,
    setCash
  }
}
var person2 = new account2(50);
console.log(person2.getCash()); //returns 50
person2.setCash(175);
console.log(person2.getCash()); //returns 175

这两种方法都可以正常运行,而且做的和我想的一样。但是第一种方法是旧的方式吗?或者可能不正确的方式?这是我学习JS的最大障碍,因为自从ES6推出以来,就有很多不同的方式来做一些简单的事情,比如在JS中创建带有方法的“类”。

个人认为第一种方式更容易,因为你不必返回函数... 但是例如在工作中,我看到第二种方式被广泛使用?


它们都不会更老。它们同样“老”。而且它们都不是“更好的”,它们只是不同。在你的特定情况下选择适合你的那一个。 - zerkms
3
在 JavaScript 中,并没有一种单一的“标准”方式来完成任何事情。请按照适合你自己的方式进行操作。 - zerkms
3
第二种方法是“错误”的,因为如果函数返回的对象不是account2的实例,使用new来调用account2()没有意义。(它仍然可以得到期望的结果,但会产生误导。) - nnnnnn
1
@msmith1114,不是说它“应该”这样做,但在第二个示例中使用new没有太多意义。 - zerkms
1
是的,根据您的评论,第二种方式“应该”在不使用new的情况下调用。无论哪种方式都不是语法错误(正如您已经展示的那样,它可以工作),但是new会自动创建一个具有特定原型的对象,然后当函数显式地创建并返回另一个对象时,该对象被丢弃。 - nnnnnn
显示剩余3条评论
2个回答

4
如果你从第二个版本中删除了new(稍后会讲到),那么你的两个示例都是创建通过公共get/set方法访问私有数据的对象的完全正确的方式。你选择哪个取决于个人偏好,或者取决于是否想要使用原型方法进一步扩展功能等。
我建议从第二个版本中删除new的原因是,尽管两个示例都可以工作,但第一个是使用new运算符的“正常”用法,而第二个是使用new运算符的“不正确”用法 - 不是语法错误,只是语义上不正确,可能会误导其他人阅读您的代码。
那么为什么第二个使用new是语义上不正确的呢?当你说var person = new account(100)时:
1. 创建了一个新对象,其原型为account.prototype。这意味着新对象继承了account.prototype和它的原型等的任何方法和属性。(在您的情况下,您没有在原型上定义任何方法,但是您可以这样做。) 2. 在account()函数内部,this将引用步骤1中创建的对象。这就是为什么你可以使用this.setCash = ...将方法附加到它上面的原因。 3. 默认情况下,新对象从account()返回。如果有显式的return语句返回其他内容,例如在您的account2()函数中,则不会发生此步骤。
因此,在第一个示例中,person instanceof accounttrue,因为默认对象被返回。在第二个示例中,person2 instanceof account2false,因为返回了不同的对象 - 这会误导阅读您代码的人,因为当他们看到person2 = new account2()时,他们可能合理地期望person2将是account2的实例,但事实并非如此。这也有点低效,因为JS引擎费力地为您创建了一个对象,然后您没有使用它。
因此,第二个示例将更“正确”地没有new,提供相同的行为,减少了不必要的自动对象创建:
var person2 = account2(50);

几乎任何你编写的JS函数都可以使用new调用,但约定俗成的是我们将那些旨在使用new被调用的函数称为“构造函数”,通常情况下对函数名进行大写处理,所以应该使用Account()而不是account()。(拼写不会影响行为,只是为了提示代码阅读者。)
请注意,new并不是将对象链接到特定原型的唯一方式:它是老派但完全有效的方式,但您也可以使用Object.create()
顺便说一句,上述行为在ES5或6中并不是新功能,尽管letaccount2中的快捷对象字面量语法确实是新的。

快速问题,为什么 person2 instanceof account2 是假的?我的意思是,person2 可以访问 account2 的所有函数,那么它不应该是它的实例吗?还是说它只是一个副本? - msmith1114
instanceof操作符测试对象在其原型链中是否有指定构造函数的原型属性。person2可以访问什么是无关紧要的,因为它具有不同的原型。它不是account2的副本。它可以访问这些函数,因为返回的对象具有对它们的引用。这些函数可以访问局部cash变量,因为存在闭包(这也是为什么account版本中的函数可以访问其cash变量的原因)。 - nnnnnn
闭包和实例是两个不同的概念,尽管它们可以一起使用。 - nnnnnn
那么第二种方式...并不是一种正常的声明大型函数/类的方式(没有使用ES6的类方式)。本质上,返回的函数是具有访问私有变量的闭包吗? - msmith1114
我不会说这不正常。这很好。有些人更喜欢它,并且您仍然可以使用 Object.create() 来设置新对象的原型等。-如果你谷歌一下,你可以找到一些认为工厂函数比使用 new 的构造函数更好的文章,反之亦然,所以... - nnnnnn

2

使用new关键字创建实例时,隐式返回this,而当将函数分配给变量而不使用new时,需要显式使用return


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