将函数放入 javascript 对象中是一种好习惯吗? [复制]

Posted

技术标签:

【中文标题】将函数放入 javascript 对象中是一种好习惯吗? [复制]【英文标题】:Is it a good practice to put functions in is javascript objects? [duplicate] 【发布时间】:2019-11-20 13:30:55 【问题描述】:

我做了一个构造函数,并打算做大量的对象。

function Cat(name) 
    this.name = name;

    this.meow = function () 
        ...
        ...
    

说,meow() 函数很长。如果我创建了很多猫或者 javascript 会处理它,它会成为内存问题吗?在这种情况下,创建静态函数而不是对象内的函数更好吗?

【问题讨论】:

通常你将函数放在原型中,而不是放在每个实例中。 您是否有意避开modern JS's dedicated support for classes via the class keyword?使用它们会消除这种担忧; JS 解释器应该自动使用任何最有效的解决方案,而不必担心您是否意外地为每个实例创建了一个闭包(碰巧,它基本上是为您创建一个带有每个方法的单个副本的原型)。 meow 函数是否冗长无关紧要。它为每个实例创建一个新的函数对象,如果您有无数个实例,这将成为一个问题。主体的代码大小不会影响用于这些函数对象之一的内存。 @ShadowRanger 不知道你说的“它基本上是用每个方法的一个副本创建一个原型”是什么意思? @Bergi:其他答案中给出的解决方案是手动将函数附加到Cat.prototype,例如Cat.prototype.meow = function() ; 是现代class 语法在幕后自动执行的操作。该函数创建一次,并且单个副本绑定到原型。当您尝试查找 instance.meow 时,Cat 的每个实例都会找到该单个副本。 【参考方案1】:

最好使用原型。

function Cat(name) 
Cat.prototype.meow = function();

大多数现代引擎(包括 chrome 的 V8)会将对象创建优化为可重用路径,而如果使用 this.meow,则在每次实例化时定义自定义隐藏路径。

转为微优化会更好吗?这实际上取决于您的实施和环境。

有关原型提高性能的方式的更详尽说明,请参阅 V8 开发人员 Toon Verwaest 提供的中等解释,Setting up prototypes in V8

【讨论】:

"如果使用 this.meow,那么在每个实例化时都会定义一个自定义隐藏路径" - 这听起来不太对。我是不是误解了你的意思? @Bergi - 我不确定?让我展开,你可以告诉我。使用this.meow附加函数将成为过渡对象的一部分,它使用隐藏类创建一个完整的隐藏路径,该路径在使用new Cat()时被发现并创建。使用原型将为该原型对象创建一个特定的隐藏类,该对象可以重复使用,并且在使用new Cat() 时不需要每次都创建。 所有Cat对象的过渡路径和隐藏类都是一样的,不需要每次调用构造函数时都创建,这就是系统的重点。 @Bergi - 我不相信 Cat 类的所有实现都是一样的。转换路径将与之前对构造函数的调用相同,但是,它与使用this. 附加属性的修改版本不同。我相信每次都需要发现它们,因为它们不是使用构造函数本身添加的,而是在创建对象后执行的函数中添加的。这是使用原型(使用自定义路径进行初始化,而不是每次都需要修改)之间的核心区别。 我们在这里讨论的是相同的代码吗? Cat 类只有一个实现。所有实例化都将遵循相同的隐藏类转换路径(在第一次调用时创建),而构造函数初始化属性 - 属性值是函数还是其他东西绝对无关紧要。不确定“不是在构造函数本身中,而是在创建对象后执行的函数中”是什么意思。这些方法不创建新属性?【参考方案2】:

您可以在 Cat 的原型中添加功能。这样,对 meow 的任何调用都将引用相同的函数。

Cat.prototype.meow = function() ;

【讨论】:

【参考方案3】:

简答:不贵。 长答案:研究函数式编程与面向对象编程。使用 JavaScript 函数式编程将允许您做各种巧妙的事情,例如:

function add(a, b)

   return a + b;


function subtract5(a)

   return a - 5; 


//You can pass functions into functions like:  subtract5(add(3, 3)) = 1;

然后,您还可以使用函数式编程语言通过 find、forEach、map、reduce 等函数让您的生活更轻松,它需要一个条件函数来将其应用于您正在使用的数组...例如:

 function condition(x)
 
  return x.id == 2;
 
 var users = []
 users.push( 
  id:1,
  name:"Bob"
 );
 users.push( 
  id:2,
   name:"Dan"
 )
// users.find(condition).name is equal to Dan
//The condition function can be a lot of things which is why it's so powerful

另一个很好的例子(我在一个有很多内部函数的 javascript 游戏中使用了这种格式,它没有显示任何负面影响 性能)

  var Cat = function(param)
 
    var self = ; 
    self.name = param.name;
    self.age = param.age;
    self.birthday = function()
    
      self.age++;
    
    return self;
  
  var youngCat = new Cat(name: "Ginger", age: 2);
  youngCat.birthday();

【讨论】:

forEach 不是函数式编程。我真的不明白这是如何回答这个问题的,你的 Cat 构造函数仍然存在与 OP 代码相同的问题。 我的“猫”示例没有问题。如上所述,我在 Node.Js 中制作了一个非常强大的 JavaScript 游戏,每个元素(玩家、物品等)都使用了该系统。这是一个 MOBA,所以有很多玩家在同一个领域,我没有看到性能问题。另外,我说的是array.forEach 而不是foreach(...)。这里有一篇文章解释得很好:medium.com/@eliaai/… “很多玩家”是什么意思,几百?是的,我说的是数组方法。仅仅采用回调函数并不能使某些东西发挥作用。 也许我措辞错误。我的意思是显然有一个成本,我只是说它非常小而且不明显,并且不会导致 OP 的计算机崩溃,因为他创建了 10000 只猫。为了回答你的问题,一次有 10 名玩家(MOBA 就像英雄联盟一样,它是 5v5)

以上是关于将函数放入 javascript 对象中是一种好习惯吗? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

将 UICollectionView 和 UITableView 放在 iOS 的 UIScrollView 中是一种好习惯吗?

将 csrf 令牌存储在元标记中是一种好习惯吗?

将嵌入式码头和 GRPC 服务器运行在同一个 JVM 中是一种好习惯吗?

将所有环境(dev uat prod)的 jar 和配置打包在一个 zip 中是一种好习惯吗?

在 javascript 中创建全局 urls 对象以便在模板中轻松反向路由是一种好习惯吗?

在 Room 数据库实体上实现 Parcelable 是一种好习惯吗?