当一个函数的行为像一个类但不使用 class 关键字或“new”关键字(在 Javascript 中)时,它会调用啥?

Posted

技术标签:

【中文标题】当一个函数的行为像一个类但不使用 class 关键字或“new”关键字(在 Javascript 中)时,它会调用啥?【英文标题】:What is it called when a function behaves like a class but doesn't use the class keyword, nor "new" keyword (in Javascript)?当一个函数的行为像一个类但不使用 class 关键字或“new”关键字(在 Javascript 中)时,它会调用什么? 【发布时间】:2019-06-09 01:53:14 【问题描述】:

我查看了suggested 链接,但似乎找不到像类一样的函数的术语(它是构造函数吗?也没有那个关键字!)但没有使用new 关键字,也不是 class

我在我的代码中同时使用了这个示例的模式和类模式,但意识到我不知道如何描述前者。

我认为这部分是因为我最近学习了 JS,看到class 被扔了很多,但查看我的笔记 not-ES5,6,7,2018,2020 等. 似乎找不到 var aCounter = counterFunction() 对我的一生的称呼。

我知道我正在做的事情的结果是什么,如何工作等等,但为什么没有constructor()、没有new、没有class、没有etc.prototype.etc 模式?我知道我正在创建一个对象,调用对象中存在的方法等。我相信我开始闲逛了。

举个例子

const counterFunction = () => 
    let val = 0

    return  
      increment()  val++ , 
      getVal()  return val 
    

这是||可以像这样实例化(?):

let aCounter = counterFunction() // where i'm getting tripped up

并且像

一样工作
aCounter.increment() // 1
aCounter.increment() // 2
aCounter.getVal() // 2 

我知道这是漫无边际的,但帮助!我认为一旦这个词汇拼图被放置到位,它会让事情在里面更加点击!

【问题讨论】:

【参考方案1】:

这只是一个返回对象字面量的函数,它不像一个类(没有原型,并且正如您所指出的,不使用 new 等)。

设置为该对象的属性的函数(您存储在aCounter 中)似乎像类方法一样,因为它们保持对变量val 的引用仍然有效,但这不是因为val以任何方式与实际对象相关联。

相反,这些函数是closures,只要函数本身还活着,它们就会保持对变量的引用。

所以为了回答你的问题,你所描述的并没有特别的名字。它只是一个返回对象的函数。

编辑:

您问为什么此模式中没有constructor() 或相关语法。 javascript 中的对象字面量只是名称和值的映射:

const x =  a: 3, b: "hello" ;

你不需要构造函数,也没有原型,因为它没有使用构造函数实例化。另一方面,类和构造函数是模板,用于稍后创建的对象,而这些对象确实有一个原型和一个构造函数,因为模板包含初始化的逻辑对象。

class A

    constructor() 
    
        this.a = new Date();
        this.b = this.a.toString(); // you cannot do this in an object literal
    


const x = new A();

【讨论】:

【参考方案2】:

问题:

当一个函数表现得像一个类但不使用 class 关键字或“new”关键字(在 Javascript 中)时,它会调用什么?

答案:

它被称为“工厂函数”。

工厂函数通常返回一个类型一致的对象,但不是工厂函数本身的实例。返回的对象很少会继承工厂函数的prototype 属性,并且调用工厂函数不需要在调用函数之前使用new

【讨论】:

【参考方案3】:

您所展示的并没有什么特别之处。它只是一个带有闭包的普通函数。

不过,您可以将其称为design pattern 的类型。

它看起来类似于Revealing Module Pattern,您可以将公共财产和私人财产分开。

下面是一个例子(不是一个好例子):

var counter = function()

  var privateCount = 0;
  var privateHistory = [];
  
  return 
    getVal: function()
      return privateCount;
    ,
    increment: function()
      privateCount++;
      privateHistory.push('+');
      return this.getVal();
    ,
    decrement: function()
      privateCount--;
      privateHistory.push('-');
      return this.getVal();
    ,
    publicHistory: function()
      return privateHistory;
    
  


var aCounter = counter();
console.log(aCounter.increment());
console.log(aCounter.decrement());
console.log(aCounter.publicHistory());

在这里,你不能直接操作我没有暴露给你的私有变量。

只有在我向您公开函数时,您才能操作这些私有变量。在这种情况下,.increment().decrement() 函数。

如您所见,没有class、没有prototype、没有constructor

【讨论】:

【参考方案4】:

我知道你可能会被绊倒,让我们检查你的代码并探索发生了什么:

const counterFunction = () => 
    let val = 0

    return  
      increment()  val++ , 
      getVal()  return val 
    

此时counterFunction是一个指向函数的变量,本质上是一个函数名。 ()=>... 是函数体或函数定义,其中return 语句显示它返回一个具有两个属性方法的未命名对象。


let aCounter = counterFunction() // where i'm getting tripped up

这是调用您之前定义的函数,该函数再次使用两个方法返回对象并将其分配给变量aCounter。如果您对名为 bCounter 的变量再次执行相同的操作,它们将拥有两个独立的对象。


and works like

aCounter.increment() // 1
aCounter.increment() // 2
aCounter.getVal() // 2 

因为对象内部的方法引用了对象作用域之外的变量,但是在函数体内,创建了一个闭包,这样val的状态就可以被保留下来。因为变量在使用中,浏览器的清理过程会跳过它,所以函数还是保存在内存中,相信直到对象被销毁,函数的变量不再使用。

【讨论】:

以上是关于当一个函数的行为像一个类但不使用 class 关键字或“new”关键字(在 Javascript 中)时,它会调用啥?的主要内容,如果未能解决你的问题,请参考以下文章

无法自动装配服务:参数引用类但不存在此类服务

AngularJS ng-class 添加类但在更改时不删除它

向 f.submit 添加一个类但保留默认功能?

寻找类似 C++ STL 的向量类但使用堆栈存储

ValueError:`class_weight`必须包含数据中的所有类。类{1,2,3}存在于数据中,但不存在于`class_weight`中

js中的class