【问题标题】:ES6 Let Const Block Scope Is Carrying Over Inside For Loop For Some VariablesES6 让 Const 块作用域在 For 循环内部继承一些变量
【发布时间】:2018-02-28 12:58:58
【问题描述】:

在 for 循环中处理 let 和 const 时,我遇到了一些奇怪的结果。我的印象是用 let 或 const 定义的变量的范围仅限于它周围的括号。

因此,在 for 循环中,将为每个 let 和 const 定义一个新范围。但是,我在 for 循环中的一些变量在每次迭代中都带有作用域。奇怪的是,并不是所有的变量都在for循环中。

如果是所有这些,我猜我对 let 和 const 范围如何工作的假设是错误的。只有其中一些人携带的事实对我来说没有意义。

我在 Chrome 中运行它 - 版本 60.0.3112.113(官方构建)(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's 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's happening is since roleOrgTree's scope is carrying over 
        // *** it is changing the previous element's data object
        $roleSelection.data("roleOrgTree", roleOrgTree);

        // *** However the scope is not carrying over for permissionsTree 
        // *** and each html element's 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's ($roleSelection) data object is not getting over written
        $roleSelection.data("rolePermTree", permissionsTree);
    };

从我的 chrome 开发人员工具中,您可以看到右侧的“范围”和 Block 变量已经具有范围但只是未定义。为什么会这样?

【问题讨论】:

  • 很难理解您描述的问题。你能添加 HTML 并解释它应该做什么以及它正在做什么吗?
  • 您正在修改保存在$sidebar.data("org-tree") 中的org 对象。
  • 它应该是复制模板 html div 以及用户可能拥有的每个角色。因此它将创建模板的克隆并将其放入 DOM 中,然后将一些对象存储在克隆模板的数据对象中以供以后访问。
  • @Barmar,map 函数没有创建新实例?如果是这样的话,为什么权限树也不能承载范围
  • 这看起来不像minimal reproducible example

标签: javascript scope ecmascript-6


【解决方案1】:

$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;
    });

顺便说一句,如果您要立即从 orgs.map() 重新分配它,那么初始化 roleOrgTree = [] 是没有意义的。

【讨论】:

  • roleOrgTree 的初始化是绝望的,我不知道是什么导致了范围携带并尝试了任何东西。
  • 这行得通,我最初只是在映射后创建了一个新的 roleOrgTree 实例,并且效果很好,但我不知道为什么范围会携带。当我在 for 循环的第一行暂停调试器时,事件仍然存在,roleOrgTree 仍然在下一次迭代中定义。我还缺少什么吗?
  • 这似乎是一个调试器工件。如果您尝试在代码中访问该变量,它将是未定义的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-09-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-31
  • 2012-07-23
相关资源
最近更新 更多