Я испытываю некоторые причудливые результаты при работе с let и const внутри цикла for. Я был под впечатлениями, что переменная, определенная с let или const, имеет область действия, ограниченную окружающими ее скобками.
Таким образом, в цикле for для каждого let и const будет определена новая область. Однако некоторые из моих переменных внутри цикла for несут область видимости с каждой итерации. Что странно, так это не все переменные внутри цикла for.
Если бы все они были, я бы догадался, что мое предположение о том, как работает функция let и const, было неправильным. Тот факт, что только некоторые из них несут, не имеет для меня смысла.
Я запускаю это в Chrome - Version 60.0.3112.113 (Official Build) (64-разрядная версия)
Я сократил часть моего кода, чтобы сделать его более кратким, чтобы следовать, но ищите "//***"
чтобы увидеть, где мои области переменных не имеют смысла.
for (let i = 0; i < combinedRoles.length; i++)
{
// *** orgs, permObjArray, roleOrgTree, rolePanelId are all carrying scope
const orgs = $sidebar.data("org-tree");
const orgRole = combinedRoles[i];
const roleId = orgRole.roleId;
const permObjArray = orgRole.permObjsArray;
const rolePanelId = "#user-" + user.userId + "-role-" + roleId;
const $selectedRoleRow = $userPanel.find(".role-selection-row.selected");
let $roleSelection = $userPanel.find(rolePanelId);
$roleSelection.data("roleData", orgRole);
// *** roleOrgTree scope is carrying over between "i" iterations
// *** So below when I set the data value for the html element from before.
let roleOrgTree = [];
roleOrgTree = orgs.map(function(org)
{
let stateObj = {checked : false, checkbox_disabled : false, selected : false};
org.a_attr = { "class" : "role-org-tree-anchor" };
org.li_attr = { "class" : "role-org-tree-li" }
currUserOrgPerms = org.anmUserRole.permissions;
if ($.inArray(roleId, org.availableRoleIds) < 0)
{
org.a_attr = { "class" : "role-org-tree-anchor disable-org-tree-anchor role-not-available" };
org.li_attr = { "class" : "role-org-tree-li disable-org-tree-node" }
stateObj.checkbox_disabled = true;
}
org.state = stateObj;
return org;
});
// *** What happening is since roleOrgTree scope is carrying over
// *** it is changing the previous element data object
$roleSelection.data("roleOrgTree", roleOrgTree);
// *** However the scope is not carrying over for permissionsTree
// *** and each html element data object is correct
let permissionsTree = [];
let familyTree = [];
// Creating the permissions tree for this role
//permObjArray.forEach(function(obj) {
permissionsTree = permObjArray.map(function(obj) {
const permFamily = obj.perm_family;
if (familyTree.indexOf(permFamily) < 0)
{
familyTree.push(permFamily);
const familyObj = {
id: permFamily,
text : permFamily,
parent : "#",
li_attr: { "class" : "disable-org-tree-node" },
a_attr : { "class" : "disable-org-tree-anchor hide-checkbox" }
};
permissionsTree.push(familyObj);
}
obj.state = {checked: true, selected: true, checkbox_disabled : true};
obj.li_attr = { "class" : "disable-org-tree-node" };
obj.a_attr = { "class" : "disable-org-tree-anchor" };
return obj;
});
// *** permissionsTree scope is not carrying over so the previous
// *** element ($roleSelection) data object is not getting over written
$roleSelection.data("rolePermTree", permissionsTree);
};
Из моих инструментов разработчика Chrome вы можете видеть, что с правой стороны в разделе "Область" и "Блокировать переменные" уже есть область действия, но они просто не определены. Почему это так?
$sidebar.data("org-tree")
не делает клона данных, он просто возвращает ссылку на него. Поэтому, когда вы позже orgs
и выполните:
org.a_attr = ...;
org.li_attr = ...;
вы изменяете объекты, находящиеся в данных элемента, и это влияет на следующую итерацию цикла.
Вы должны клонировать эти объекты перед их модификацией.
roleOrgTree = orgs.map(function(org)
{
org = Object.assign({}, org);
let stateObj = {checked : false, checkbox_disabled : false, selected : false};
org.a_attr = { "class" : "role-org-tree-anchor" };
org.li_attr = { "class" : "role-org-tree-li" }
currUserOrgPerms = org.anmUserRole.permissions;
if ($.inArray(roleId, org.availableRoleIds) < 0)
{
org.a_attr = { "class" : "role-org-tree-anchor disable-org-tree-anchor role-not-available" };
org.li_attr = { "class" : "role-org-tree-li disable-org-tree-node" }
stateObj.checkbox_disabled = true;
}
org.state = stateObj;
return org;
});
Кстати, нет смысла инициализировать roleOrgTree = []
если вы сразу же переназначаете его из orgs.map()
.
$sidebar.data("org-tree")
объектыorg
, которые сохраняются в$sidebar.data("org-tree")
.