Я знаю, что иногда бывает полезно, чтобы функции возвращали другие функции, чтобы вам не приходилось повторять себя, увеличивать модульность и т.д.
Но какой смысл в этом фрагменте (один из многих) здесь из библиотеки three.js?
Object.assign( Matrix4.prototype, {
...
applyToBufferAttribute: function () {
var v1 = new Vector3();
return function applyToBufferAttribute( attribute ) {
for ( var i = 0, l = attribute.count; i < l; i ++ ) {
v1.x = attribute.getX( i );
v1.y = attribute.getY( i );
v1.z = attribute.getZ( i );
v1.applyMatrix4( this );
attribute.setXYZ( i, v1.x, v1.y, v1.z );
}
return attribute;
};
}(),
...
} );
"Inlined" applyToBufferAttribute
не используется повторно в другом месте.
Возвращаемая функция становится методом, да. Целью обертывания его в IIFE является скрыть переменную v1
, сделав ее тем, что C будет называть "статической переменной": независимо от того, сколько объектов Matrix4
вы создаете, независимо от того, сколько раз вы вызываете applyToBufferAttribute
, будет только один экземпляр v1
, и он не будет доступен, кроме функции applyToBufferAttribute
.
Для этого мы можем только догадываться, но, вероятно, Vector3
затрат на выделение и освобождение для этого объекта Vector3
, предполагая, что applyToBufferAttribute
с некоторой частотой. Учитывая, что three.js является библиотекой WebGL, каждый небольшой оптимизатор помогает.
Вот как вы "спрячьте" переменную во внешнюю область.
v1
больше не виден вне вашего модуля, и вы убедитесь, что никто не будет его нарушать.
Обычно функция возврата является закрытием, которое закрывается над переменной v1
.
Альтернативой было бы сделать полный объект fledge и сделать v1
readonly, но вы часто не потрудитесь сделать такой объект. Таким образом, это быстрый способ инкапсулировать некоторую переменную.
Второй альтернативой будет добавление v1
к возвращаемому объекту.
function applyToBufferAttribute() {
if (!this.v1) {
this.v1 = new Vector3();
}
...
}
Но это также связано с тем, что v1
видимо снаружи и делает код более хрупким.
...
?