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

我正在研究 三个,注意到函数的定义是这样的:

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. 它分配自执行函数的结果。
  2. 它在这个函数中定义了一个局部变量。
  3. 它返回包含使用本地变量的逻辑的 真的函数。

所以主要的区别在于,在第一个变体中,在初始化时,bar 只被赋值一次,而第二个变体在每次调用时都会创建这个临时变量。

对于为什么使用这种方法,我最好的猜测是它限制了 bar 的数量(只有一个) ,从而节省了内存管理开销。

我的问题是:

  1. 这个假设正确吗?
  2. 这个图案有名字吗?
  3. 为什么用这个?
7381 次浏览

It limits the object initialization costs and additionally ensures that all function invocations use the same object. This allows, for example, state to be stored in the object for future invocations to use.

While it's possible that it does limit memory usage, usually the GC will collect unused objects anyways, so this pattern is not likely to help much.

This pattern is a specific form of closure.

I'm not sure if this pattern has a more correct name, but this looks like a module to me, and the reason it is used is to both encapsulate and to maintain state.

The closure (identified by a function within a function) ensures that the inner function has access to the variables within the outer function.

In the example you gave, the inner function is returned (and assigned to foo) by executing the outer function which means tmpObject continues to live within the closure and multiple calls to the inner function foo() will operate on the same instance of tmpObject.

Your assumptions are almost correct. Let's review those first.

  1. It assigns the return of a self-executing function

This is called an Immediately-invoked function expression or IIFE

  1. It defines a local variable within this function

This is the way of having private object fields in JavaScript as it does not provide the private keyword or functionality otherwise.

  1. It returns the actual function containing logic that makes use of the local variable.

Again, the main point is that this local variable is private.

Is there a name for this pattern?

AFAIK you can call this pattern Module Pattern. Quoting:

The Module pattern encapsulates "privacy", state and organization using closures. It provides a way of wrapping a mix of public and private methods and variables, protecting pieces from leaking into the global scope and accidentally colliding with another developer's interface. With this pattern, only a public API is returned, keeping everything else within the closure private.

Comparing those two examples, my best guesses about why the first one is used are:

  1. It is implementing the Singleton design pattern.
  2. One can control the way an object of a specific type can be created using the first example. One close match with this point can be static factory methods as described in Effective Java.
  3. It's efficient if you need the same object state every time.

But if you just need the vanilla object every time, then this pattern will probably not add any value.

In the example provided, the first snippet will use the same instance of tmpObject for every call to the function foo(), where as in the second snippet, tmpObject will be a new instance every time.

One reason the first snippet may have been used, is that the variable tmpObject can be shared between calls to foo(), without its value being leaked into the scope that foo() is declared in.

The non immediately executed function version of the first snippet would actually look like this:

var tmpObject = new Bar();


function foo(){
// Use tmpObject.
}

Note however that this version has tmpObject in the same scope as foo(), so it could be manipulated later.

A better way to achieve the same functionality would be to use a separate module:

Module 'foo.js':

var tmpObject = new Bar();


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

Module 2:

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

A comparison between the performance of an IEF and a named foo creator function: http://jsperf.com/ief-vs-named-function

The key difference between your code and the Three.js code is that in the Three.js code the variable tmpObject is only initialised once, and then shared by every invocation of the returned function.

This would be useful for keeping some state between calls, similar to how static variables are used in C-like languages.

tmpObject is a private variable only visible to the inner function.

It changes the memory usage, but its not designed to save memory.

I'd like to contribute to this interesting thread by extending to the concept of the revealing module pattern, which ensures that all methods and variables are kept private until they are explicitly exposed.

enter image description here

In the latter case, the addition method would be called as Calculator.add();