Javascript “vars退货警报”;“长度”;或;项目「;
我有一个16x16表,我向所有td分配了一个lambda函数(将参数传递给实际函数),如下所示:Javascript “vars退货警报”;“长度”;或;项目「;,javascript,html,dom,lambda,Javascript,Html,Dom,Lambda,我有一个16x16表,我向所有td分配了一个lambda函数(将参数传递给实际函数),如下所示: function handlerAsignment() { var trs = document.getElementsByTagName("tr"); var tds; for (tr in trs) { tds = trs[tr].getElementsByTagName("td"); for (td in tds){
function handlerAsignment()
{
var trs = document.getElementsByTagName("tr");
var tds;
for (tr in trs) {
tds = trs[tr].getElementsByTagName("td");
for (td in tds){
tds[td].onclick = function() {
atack(tr, td);
};
}
}
}
正如您将看到的,我必须传递关于正确tr的tr编号和td编号。
但我有这个功能:
function atack(tr, td)
{
alert("Tr: " +tr+ " td: " +td);
}
function atack(evt) {
var cell = this;
var row = cell.parentNode;
alert("Tr: " + row + " td: " + cell);
}
这会显示消息“Tr:item td:length”为什么?
建议:我不想在函数atack中使用事件来检测正确的td。我需要这些参数来访问16x16多维数组(与表相同,但有更多信息)。这是典型的闭包误解。您分配给
onclick
的函数(闭包)具有对tr
和td
变量的持久引用,而不是创建时的变量副本。因此,所有的onclick
函数都使用相同的变量和值;两个循环结束时的值
这里通常的答案是使用生成器函数,以便它们使用单独的变量:
function handlerAsignment()
{
var trs = document.getElementsByTagName("tr");
var tds;
for (tr in trs) {
tds = trs[tr].getElementsByTagName("td");
for (td in tds){
tds[td].onclick = buildHandler(tr, td);
}
}
}
function buildHandler(tr, td) {
return function() {
atack(tr, td);
};
}
现在,处理程序关闭传递到buildHandler
的tr
和td
参数,而不是循环中使用的tr
和td
变量。因为这些参数永远不会改变(每个对buildHandler
的调用都有自己的参数),所以它解决了这个问题
更多关于我的博客:
还有两件事值得一提:
td
或tr
,因此您正沦为for in
来循环节点列表
实例for in
循环遍历对象的属性名称。将它与主机提供的对象(如NodeList
)一起使用不能保证工作,而且依赖于主机提供的对象使某些内容可枚举,而其他内容不可枚举。改用标准循环。因此:
function handlerAsignment()
{
var trs = document.getElementsByTagName("tr");
var tds;
var trIndex, tdIndex;
for (trIndex = 0; trIndex < trs.length; ++trIndex) {
tds = trs[trIndex].getElementsByTagName("td");
for (tdIndex = 0; tdIndex < tds.length; ++tdIndex){
tds[tdIndex].onclick = buildHandler(trIndex, tdIndex);
}
}
}
function buildHandler(tr, td) {
return function() {
atack(tr, td);
};
}
|
您可以在任何类似数组的对象上安全地使用
Array#forEach
,而不仅仅是数组<代码>节点列表对象类似于数组。这是经典的闭包误解。您分配给onclick
的函数(闭包)具有对tr
和td
变量的持久引用,而不是创建时的变量副本。因此,所有的onclick
函数都使用相同的变量和值;两个循环结束时的值
这里通常的答案是使用生成器函数,以便它们使用单独的变量:
function handlerAsignment()
{
var trs = document.getElementsByTagName("tr");
var tds;
for (tr in trs) {
tds = trs[tr].getElementsByTagName("td");
for (td in tds){
tds[td].onclick = buildHandler(tr, td);
}
}
}
function buildHandler(tr, td) {
return function() {
atack(tr, td);
};
}
现在,处理程序关闭传递到buildHandler
的tr
和td
参数,而不是循环中使用的tr
和td
变量。因为这些参数永远不会改变(每个对buildHandler
的调用都有自己的参数),所以它解决了这个问题
更多关于我的博客:
还有两件事值得一提:
td
或tr
,因此您正沦为for in
来循环节点列表
实例for in
循环遍历对象的属性名称。将它与主机提供的对象(如NodeList
)一起使用不能保证工作,而且依赖于主机提供的对象使某些内容可枚举,而其他内容不可枚举。改用标准循环。因此:
function handlerAsignment()
{
var trs = document.getElementsByTagName("tr");
var tds;
var trIndex, tdIndex;
for (trIndex = 0; trIndex < trs.length; ++trIndex) {
tds = trs[trIndex].getElementsByTagName("td");
for (tdIndex = 0; tdIndex < tds.length; ++tdIndex){
tds[tdIndex].onclick = buildHandler(trIndex, tdIndex);
}
}
}
function buildHandler(tr, td) {
return function() {
atack(tr, td);
};
}
|
您可以在任何类似数组的对象上安全地使用Array#forEach
,而不仅仅是数组NodeList
对象类似于数组。for(tr-in-trs)
不是您想要的东西。它依次将tr
设置为trs
的每个属性的名称。由于trs
是一个NodeList
,它的命名属性是length
及其项
方法
for(tr of trs)
语法可以工作,但您是为浏览器编码的,浏览器对此的支持并不普遍
NodeList
不是一个真正的数组,因此您无法轻松地在其上使用array.forEach
因此,您最好使用for(var i=0;i
plustrs[i]
plus T.J.buildHandler
技巧来确保您的处理程序关闭的变量在创建关闭后不会更改。for(trs中的tr)
不是您想要的东西。它依次将tr
设置为trs
的每个属性的名称。由于trs
是一个NodeList
,它的命名属性是length
及其项
方法
for(tr of trs)
语法可以工作,但您是为浏览器编码的,浏览器对此的支持并不普遍
NodeList
不是一个真正的数组,因此您无法轻松地在其上使用array.forEach
因此,您最好使用
for(var i=0;i
plustrs[i]
加上T.J.的buildHandler
技巧,以确保您的处理程序关闭的变量在创建闭包后不会更改。房间里没有人讨论过大象:创建一个将引用传递给它所在元素的处理程序是不必要的,因为可以将处理程序设置为将该元素作为引用这是默认设置
类似地,当该元素作为this.parentNode
可用时,将引用传递给该元素的父元素也没有意义
使用addEventListener或attachEvent(视情况而定)添加侦听器的简单函数:
function addListener(element, event, fn) {
// Use addEventListener if available
if (element.addEventListener) {
element.addEventListener(event, fn, false);
// Otherwise use attachEvent, set this and event
} else if (element.attachEvent) {
element.attachEvent('on' + event, (function (el) {
return function() {
fn.call(el, window.event);
};
}(element)));
// Break closure and primary circular reference to element
element = null;
}
}
使用上述方法将侦听器连接到单元格上,然后在atack(攻击?)功能中:
function atack(tr, td)
{
alert("Tr: " +tr+ " td: " +td);
}
function atack(evt) {
var cell = this;
var row = cell.parentNode;
alert("Tr: " + row + " td: " + cell);
}
如果您调查事件委派,您可能会发现您只需要一个侦听器就可以了。没有人在房间里讨论过大象:创建一个将引用传递给el的处理程序