Следующий простой пример охватывает все основные моменты закрытия JavaScript. * & nbsp;
Вот фабрика, которая производит калькуляторы, которые могут добавлять и умножать:
function make_calculator() {
var n = 0; // this calculator stores a single number n
return {
add: function(a) {
n += a;
return n;
},
multiply: function(a) {
n *= a;
return n;
}
};
}
first_calculator = make_calculator();
second_calculator = make_calculator();
first_calculator.add(3); // returns 3
second_calculator.add(400); // returns 400
first_calculator.multiply(11); // returns 33
second_calculator.multiply(10); // returns 4000
Ключевой момент: каждый вызов make_calculator
создает новую локальную переменную n
, которая по-прежнему может использоваться функциями add
и multiply
этого калькулятора после make_calculator
возвращается.
Если вы знакомы с кадрами стека, эти калькуляторы кажутся странными: как они могут продолжать доступ к n
после возвращения make_calculator
? Ответ заключается в том, чтобы предположить, что JavaScript не использует «фреймы стека», но вместо этого использует «кучевые кадры», которые могут сохраняться после вызова функции, которая заставила их вернуться.
Внутренние функции, такие как add
и multiply
, которые передают переменные, объявленные во внешней функции **, называются замыканиями .
Это почти все, что есть для закрытия.
* Например, он охватывает все точки в статье «Закрытия для чайников», приведенные в , другой ответ , за исключением примера 6, который просто показывает что переменные могут использоваться до того, как они будут объявлены, хороший факт, чтобы знать, но полностью не связан с закрытием. Он также охватывает все точки из принятого ответа , за исключением точек (1), которые копируют свои аргументы в локальные переменные (именованные аргументы функции) и (2) что копирование чисел создает новый номер, но копирование ссылки на объект дает вам другую ссылку на тот же объект. Они также хорошо знают, но снова полностью не связаны с закрытием. Он также очень похож на пример в этого ответа , но немного короче и менее абстрактен. Он не охватывает точку этого ответа или этого комментария , который заключается в том, что JavaScript затрудняет подключение значения current для переменной цикла в вашу внутреннюю функцию: шаг «запирания» может выполняться только с помощью вспомогательной функции, которая включает вашу внутреннюю функцию и вызывается на каждой итерации цикла. (Строго говоря, внутренняя функция обращается к копии переменной вспомогательной функции, а не к чему-либо подключенному.) Опять же, очень полезно при создании закрытий, но не в части того, что такое закрытие или как оно работает. Существует дополнительная путаница из-за того, что замыкания работают по-разному в функциональных языках, таких как ML, где переменные привязаны к значениям, а не к пространству хранения, обеспечивая постоянный поток людей, которые понимают закрытие способом (а именно «подключаемым» способом), который просто неверный для JavaScript, где переменные всегда привязаны к пространству хранения и никогда не относятся к значениям.
** Любая внешняя функция, если несколько вложенных или даже в глобальном контексте, как , этот ответ четко указывает.
Я нашел решение, может быть, оно будет полезно для других.
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import matplotlib.pyplot as plt
import numpy as np
import colorsys
from matplotlib.tri import Triangulation
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
n_angles = 80
n_radii = 20
# An array of radii
# Does not include radius r=0, this is to eliminate duplicate points
radii = np.linspace(0.0, 0.5, n_radii)
# An array of angles
angles = np.linspace(0, 2*np.pi, n_angles, endpoint=False)
# Repeat all angles for each radius
angles = np.repeat(angles[..., np.newaxis], n_radii, axis=1)
# Convert polar (radii, angles) coords to cartesian (x, y) coords
# (0, 0) is added here. There are no duplicate points in the (x, y) plane
x = np.append(0, (radii*np.cos(angles)).flatten())
y = np.append(0, (radii*np.sin(angles)).flatten())
# Pringle surface
z = 1+-np.sqrt(x**2+y**2)*2
print(x.shape, y.shape, angles.shape, radii.shape, z.shape)
# NOTE: This assumes that there is a nice projection of the surface into the x/y-plane!
tri = Triangulation(x, y)
triangle_vertices = np.array([np.array([[x[T[0]], y[T[0]], z[T[0]]],
[x[T[1]], y[T[1]], z[T[1]]],
[x[T[2]], y[T[2]], z[T[2]]]]) for T in tri.triangles])
x2 = np.append(0, (radii*np.cos(angles)).flatten())
y2 = np.append(0, (radii*np.sin(angles)).flatten())
# Pringle surface
z2 = -1+np.sqrt(x**2+y**2)*2
# NOTE: This assumes that there is a nice projection of the surface into the x/y-plane!
tri2 = Triangulation(x2, y2)
triangle_vertices2 = np.array([np.array([[x2[T[0]], y2[T[0]], z2[T[0]]],
[x2[T[1]], y2[T[1]], z2[T[1]]],
[x2[T[2]], y2[T[2]], z2[T[2]]]]) for T in tri2.triangles])
triangle_vertices = np.concatenate([triangle_vertices, triangle_vertices2])
midpoints = np.average(triangle_vertices, axis=1)
def find_color_for_point(pt):
c_x, c_y, c_z = pt
angle = np.arctan2(c_x, c_y)*180/np.pi
if (angle < 0):
angle = angle + 360
if c_z < 0:
l = 0.5 - abs(c_z)/2
#l=0
if c_z == 0:
l = 0.5
if c_z > 0:
l = (1 - (1-c_z)/2)
if c_z > 0.97:
l = (1 - (1-c_z)/2)
col = colorsys.hls_to_rgb(angle/360, l, 1)
return col
facecolors = [find_color_for_point(pt) for pt in midpoints] # smooth gradient
# facecolors = [np.random.random(3) for pt in midpoints] # random colors
coll = Poly3DCollection(
triangle_vertices, facecolors=facecolors, edgecolors=None)
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.add_collection(coll)
ax.set_xlim(-1, 1)
ax.set_ylim(-1, 1)
ax.set_zlim(-1, 1)
ax.elev = 50
plt.show()