对于 Adobe Photoshop 中的脚本,有一个带有选择和控件的对话框:
var dlg = new Window('dialog{text: "Выбор размеров", bounds: [' + fBounds(150,200,370,150) + '], \
panel_s: Panel{text: "Стандартные:", bounds: [' + fBounds(5,5,203,85) + '], \
checkbox_16: Checkbox{bounds: [' + fBounds(5,13,55,14) + '], text: "16 x 16"}, \
checkbox_24: Checkbox{bounds: [' + fBounds(5,33,55,14) + '], text: "24 x 24"}, \
checkbox_32: Checkbox{bounds: [' + fBounds(5,53,55,14) + '], text: "32 x 32"}, \
checkbox_48: Checkbox{bounds: [' + fBounds(67,13,55,14) + '], text: "48 x 48"}, \
checkbox_64: Checkbox{bounds: [' + fBounds(67,33,55,14) + '], text: "64 x 64"}, \
checkbox_96: Checkbox{bounds: [' + fBounds(67,53,55,14) + '], text: "96 x 96"}, \
checkbox_128: Checkbox{bounds: [' + fBounds(129,13,65,14) + '], text: "128 x 128"}, \
checkbox_256: Checkbox{bounds: [' + fBounds(129,33,65,14) + '], text: "256 x 256"}, \
checkbox_512: Checkbox{bounds: [' + fBounds(129,53,65,14) + '], text: "512 x 512"} \
}, \
panel_o: Panel{text: "Другие:", bounds: [' + fBounds(206,5,69,64) + '],\
checkbox_19: Checkbox{bounds: [' + fBounds(5,13,55,14) + '], text: "19 x 19"}, \
checkbox_38: Checkbox{bounds: [' + fBounds(5,33,55,14) + '], text: "38 x 38"} \
}, \
panel_u: Panel{text: "Свои:", bounds: [' + fBounds(273,5,92,85) + '],\
checkbox_u1: Checkbox{bounds: [' + fBounds(5,13,14,14) + ']}, \
static_u1: StaticText{bounds: [' + fBounds(21,13,31,14) + '], text: ". . . x", justify: "right"}, \
edittext_u1: EditText{bounds: [' + fBounds(53,11,30,19) + '], text: ". . .", properties: {multiline: false}}, \
\
checkbox_u2: Checkbox{bounds: [' + fBounds(5,33,14,14) + ']}, \
static_u2: StaticText{bounds: [' + fBounds(21,33,31,14) + '], text: ". . . x", justify: "right"}, \
edittext_u2: EditText{bounds: [' + fBounds(53,31,30,19) + '], text: ". . .", properties: {multiline: false}}, \
\
checkbox_u3: Checkbox{bounds: [' + fBounds(5,53,14,14) + ']}, \
static_u3: StaticText{bounds: [' + fBounds(21,53,31,14) + '], text: ". . . x", justify: "right"}, \
edittext_u3: EditText{bounds: [' + fBounds(53,51,30,19) + '], text: ". . .", properties: {multiline: false}} \
}, \
button_all: Button{bounds: [' + fBounds(208,70,64,19) + '], text: "Все"}, \
static_save: StaticText{bounds: [' + fBounds(5,99,75,14) + '], text: "Сохранить в:"}, \
drop_save: DropDownList{bounds: [' + fBounds(78,95,287,23) + '], properties: {items: ["папку рядом с исходным файлом", "-", "Выбрать папку..."]}, helpTip:"Ooops!!!"}, \
progress_save: Progressbar{bounds: [' + fBounds(0,0,370,4) + '], value:50}, \
button_run: Button{bounds: [' + fBounds(4,122,70,22) + '], text: "Создать"} \
};'
);
// -- Выбор всех значений
dlg.show();
有一个按钮处理程序可以选择所有复选框:
// -- Выбор всех значений
dlg.button_all.addEventListener('click', function() {
alert(dlg.panel_s.children + '\r\n' + dlg.panel_s.children.length);
// Коллекция (9 элементов) и количество (9) отображаются верно
alert(dlg.panel_o.children + '\r\n' + dlg.panel_o.children.length);
// Коллекция (2 элемента) и количество (2) отображаются верно
// Объединяем обе коллекции и три отдельных элемента
var aPanel = [].concat(
dlg.panel_s.children,
dlg.panel_o.children,
dlg.panel_u.checkbox_u1,
dlg.panel_u.checkbox_u2,
dlg.panel_u.checkbox_u3
);
alert(aPanel + '\r\n' + aPanel.length);
// Массив отображается верно (14 элементов), но количество не совпадает (5) !
});
从处理程序代码中的注释可以看出问题出在哪里,问题如下... Array.prototype.concat()方法,根据文档,应该连接数组,将它们扩展到第一级的嵌套。实际上,根据最后一个弹出窗口(请参阅处理程序代码),这就是发生的情况 - 所有元素都按照它们添加的顺序显示在那里。
但是,在访问时aPanel[0]
,不是第一个元素 ( checkbox_16
),而是返回整个集合dlg.panel_s.children
。因此,数组的长度aPanel
为 5,您只能通过指定集合中的嵌套来获得所需的元素,即 aPanel[0][0]
.
这是一个错误还是棘手的逻辑?使用concat()连接数组的正确方法是什么?
修正案
确实,根据MDN 帮助
первый уровень вложенности
如您所见,只有 about ,这里没有一个字。这是一个很好的例子:
但是,这不会改变您的问题,因为在您的情况下,如果元素
dlg.{foo}.children
是数组,那么它们的展开仍然会发生那么有什么关系呢?
我不会折磨你,最后告诉你问题是什么。再次,注意这一行:
我在说什么?您指定的元素不是数组!是的,它们是集合,类似于数组,但规范仍然很严格。
让我们看看该方法如何处理
concat
参数object,就像您的元素一样,它本质上是一个集合,而不是一个数组:如您所见,
concat
我不知道它是集合还是常规对象。对他来说,唯一重要的是,这个构造不是数组。PS - 为了能够检查一个对象是否是一个数组,我建议你看看Array.isArray()函数
该怎么办?
最好的选择是不要偷懒并手动添加所有内容:
另一种变体
您可以在原型级别定义您的方法,这会将数组和集合扩展到第一级:
升级版:
非常感谢@Grundy让我注意到以下几点:
让我们看看不是MDN 帮助,而是ECMAScript 规范。让我们注意这些行:
或俄语:
也就是说,该元素是否会显式添加到结果数组中,或者是否将其先前扩展为集合,是执行某个IsConcatSpreadable(O)函数的结果。让我们来看看它是什么,和它一起吃什么:
或俄语:
也就是说,检查一个对象是否是一个数组是最后的。在此之前,检查对象是否具有属性
Symbol.isConcatSpreadable
,如果有,则其布尔值将指示它是否会在何时展开concat
。现在让我们将其付诸实践:
像发条一样工作。为了实验,让我们在现有的枚举类型上进行测试。再次回忆一下我们的论点:
如您所见,我们设法使用以下方法
concat
将内部值合并arguments
到一个数组中为了清白,让我提醒您:以这种方式进入对象的内部属性,改变其工作逻辑,是错误的和亵渎的!
为什么?让我们想象一下这种情况:你看到一个数组。它应该如何处理该方法
concat
?没错,根据指定的证书不止一次,组合的时候一定要显露!但是,如果有人按如下方式使用您收到的数组怎么办:我们只是改变了标准类型的行为,这是非常非常错误的!所以尽量避免这种方法!
一切,良心被清除,所以我们可以进一步滥用:)
您的问题的另一种解决方案:
基于IsConcatSpreadable(O)执行结果的操作,您的任务可以通过以下方式解决:
为了清楚起见,还有一个活生生的例子:
希望我的回答能帮助您解决问题!祝你工作顺利!