这个JavaScript模式叫什么?为什么使用它?

我正在学习THREE.js并注意到一个模式,其中的function定义如下:

var foo = ( function () { var bar = new Bar(); return function ( ) { //actual logic using bar from above. //return result; }; }()); 

(例子见这里的 raycast方法)。

这种方法的正常变化看起来像这样:

 var foo = function () { var bar = new Bar(); //actual logic. //return result; }; 

比较第一个版本和正常的版本,第一个版本似乎有所不同:

  1. 它分配自执行function的结果。
  2. 它在这个函数中定义了一个局部variables。
  3. 它返回包含使用局部variables的逻辑的实际函数。

所以主要区别在于,在第一个变体中,在初始化时,条只被分配一次,而第二个变体在每次被调用时创build这个临时variables。

我最好的猜测是为什么使用它,它限制了实例的数量(只有一个),从而节省了内存pipe理开销。

我的问题:

  1. 这个假设是否正确?
  2. 这个模式有没有名字?
  3. 为什么使用?

你的假设几乎是正确的。 我们先来回顾一下。

  1. 它分配自我执行function的返回

这被称为立即调用函数expression式或IIFE

  1. 它在这个函数中定义了一个局部variables

这是在JavaScript中使用私有对象字段的方式,因为它不提供private关键字或function。

  1. 它返回包含使用局部variables的逻辑的实际函数。

再一次,重点是这个局部variables是私人的

这个模式有没有名字?

AFAIK你可以调用这个模式模块模式 。 引用:

模块模式使用闭包封装“隐私”,状态和组织。 它提供了一种包装公有和私有方法和variables混合的方法,防止部分泄漏到全局范围内,并意外地与另一个开发人员的接口相冲突。 有了这个模式,只有一个公共的API被返回,所有其他的封闭在私有。

比较这两个例子,我最好的猜测为什么第一个是使用的是:

  1. 它正在实施Singletondevise模式。
  2. 可以使用第一个示例来控制可以创build特定types的对象的方式。 与此有关的一个近似匹配可以是Effective Java中描述的静态工厂方法 。
  3. 如果您每次都需要相同的对象状态,则效率很高 。

但是如果你每次只需要香草物体,那么这个模式可能不会增加任何价值。

它限制了对象的初始化成本,并确保所有的函数调用都使用相同的对象。 例如,这允许将状态存储在对象中以供将来的调用使用。

虽然它可能会限制内存的使用,但通常GC会收集未使用的对象,所以这种模式不太可能有帮助。

这种模式是一种特定的封闭forms。

我不确定这个模式是否有一个更正确的名字,但是这看起来像一个模块给我,它使用的原因是封装和维护状态。

闭包(由函数内的函数标识)确保内函数可以访问外函数中的variables。

在你给出的例子中,通过执行外部函数返回(并分配给foo )内部函数,这意味着tmpObject继续在闭包内生存,并且多次调用内部函数foo()将对tmpObject的同一个实例进行tmpObject

你的代码和Three.js代码之间的主要区别是在Three.js代码中,variablestmpObject只被初始化一次,然后被每次调用返回的函数共享。

这对保持调用之间的状态非常有用,类似于类似C语言中的staticvariables。

tmpObject是一个只对内部函数可见的私有variables。

它改变了内存使用情况,但不是为了节省内存而devise的。

我想通过扩展到揭示模块模式的概念来为这个有趣的线程作出贡献,这确保了所有的方法和variables在被明确暴露之前保持私有。

在这里输入图像说明

在后一种情况下,添加方法将被称为Calculator.add();

在提供的示例中,第一个片段将对每个对函数foo()的调用使用同一个tmpObject实例,而在第二个片段中,tmpObject将每次都是新实例。

第一个片段可能被使用的一个原因是variablestmpObject可以在对foo()的调用之间共享,而不会将其值泄漏到声明foo()的作用域中。

第一个片段的非立即执行的function版本实际上看起来像这样:

 var tmpObject = new Bar(); function foo(){ // Use tmpObject. } 

但请注意,此版本的tmpObject与foo()的作用域相同,因此稍后可以对其进行操作。

实现相同function的更好方法是使用单独的模块:

模块“foo.js”:

 var tmpObject = new Bar(); module.exports = function foo(){ // Use tmpObject. }; 

模块2:

 var foo = require('./foo'); 

比较一个IEF和一个名为foo创build者函数的性能: http : //jsperf.com/ief-vs-named-function