如何重构此 JavaScript 代码以避免使函数处于循环中?

发布于 2024-09-02 23:12:43 字数 1685 浏览 4 评论 0原文

我为我正在从事的项目编写了以下代码:

var clicky_tracking = [
  ['related-searches', 'Related Searches'],
  ['related-stories', 'Related Stories'],
  ['more-videos', 'More Videos'],
  ['web-headlines', 'Publication']
];

for (var x = 0, length_x = clicky_tracking.length; x < length_x; x++) {
  links = document.getElementById(clicky_tracking[x][0])
                  .getElementsByTagName('a');
  for (var y = 0, length_y = links.length; y < length_y; y++) {
    links[y].onclick = (function(name, url) {
      return function() {
        clicky.log(url, name, 'outbound');
      };
    }(clicky_tracking[x][1], links[y].href));
  }
}

我想做的是:

  • 定义一个二维数组,每个实例的内部数组包含两个元素:一个id属性值(例如“相关搜索”)和相应的描述(例如“相关搜索”);
  • 对于每个内部数组,在 document 中查找具有相应 id 属性的元素,然后收集所有 的集合> 其中的元素(超链接);
  • 循环遍历该集合,并将 onclick 处理程序附加到每个超链接,该处理程序应调用 clicky.log,并将与 id 对应的描述作为参数传递code>(例如,id“相关搜索”的“相关搜索”)以及 href 属性的值code> 被单击的元素。

希望这没有完全令人困惑!该代码可能比这更不言自明。

我相信我在这里实现的是一个闭包,但 JSLint 抱怨:

http://img .skitch.com/20100526-k1trfr6tpj64iamm8r4jf5rbru.png

所以,我的问题是:

  • 如何重构这段代码以使 JSLint 令人满意?或者,更好的是,无论 JSLint 有何想法,是否有一种我所缺少的最佳实践方法可以做到这一点?
  • 我应该依赖事件委托吗?也就是说,将 onclick 事件处理程序附加到数组中具有 id 属性的 document 元素,然后查看 event.target ?我以前做过一次并理解了理论,但我对细节非常模糊,并且希望获得一些关于它的外观的指导 - 假设这是一种可行的方法。

非常感谢您的帮助!

I wrote the following code for a project that I'm working on:

var clicky_tracking = [
  ['related-searches', 'Related Searches'],
  ['related-stories', 'Related Stories'],
  ['more-videos', 'More Videos'],
  ['web-headlines', 'Publication']
];

for (var x = 0, length_x = clicky_tracking.length; x < length_x; x++) {
  links = document.getElementById(clicky_tracking[x][0])
                  .getElementsByTagName('a');
  for (var y = 0, length_y = links.length; y < length_y; y++) {
    links[y].onclick = (function(name, url) {
      return function() {
        clicky.log(url, name, 'outbound');
      };
    }(clicky_tracking[x][1], links[y].href));
  }
}

What I'm trying to do is:

  • define a two-dimensional array, with each instance the inner arrays containing two elements: an id attribute value (e.g., "related-searches") and a corresponding description (e.g., "Related Searches");
  • for each of the inner arrays, find the element in the document with the corresponding id attribute, and then gather a collection of all <a> elements (hyperlinks) within it;
  • loop through that collection and attach an onclick handler to each hyperlink, which should call clicky.log, passing in as parameters the description that corresponds to the id (e.g., "Related Searches" for the id "related-searches") and the value of the href attribute for the <a> element that was clicked.

Hopefully that wasn't thoroughly confusing! The code may be more self-explanatory than that.

I believe that what I've implemented here is a closure, but JSLint complains:

http://img.skitch.com/20100526-k1trfr6tpj64iamm8r4jf5rbru.png

So, my questions are:

  • How can I refactor this code to make JSLint agreeable? Or, better yet, is there a best-practices way to do this that I'm missing, regardless of what JSLint thinks?
  • Should I rely on event delegation instead? That is, attaching onclick event handlers to the document elements with the id attributes in my arrays, and then looking at event.target? I've done that once before and understand the theory, but I'm very hazy on the details, and would appreciate some guidance on what that would look like - assuming this is a viable approach.

Thanks very much for any help!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

能怎样 2024-09-09 23:12:44

授权是一种更好的方法。 JSLint 会抱怨,因为您每次都在循环内创建一个新函数。但是,我宁愿在分配了 id 的所有单个根元素上设置一个处理程序,而不是在文档上设置单个事件来侦听所有单击事件。单个处理程序可以重复用于所有这些元素。

function logClick(event) {
    event = event || window.event;
    var link = event.target || event.srcElement;

    if(link.nodeName.toLowerCase() !== "a") {
        return;
    }

    var name = clicky_tracking[this.id];
    clicky.log(link.href, name, 'outbound');
}

向每个根元素注册上述处理程序。

for(var id in clicky_tracking) {
    var root = document.getElementById(id);
    root.onclick = logClick;
}

另外,为了避免搜索数组,我将 clicky_tracking 从数组更改为对象,以便更轻松地进行键控访问。

var clicky_tracking = {
  'related-searches': 'Related Searches',
  'related-stories': 'Related Stories',
  'more-videos': 'More Videos',
  'web-headlines': 'Publication'
};

Delegation is a better approach. JSLint complains because you are creating a new function each time within the loop. However, instead of setting up a single event on the document to listen for all click events, I would rather setup a handler on all individual root elements that have id's assigned to them. A single handler can be reused for all these elements.

function logClick(event) {
    event = event || window.event;
    var link = event.target || event.srcElement;

    if(link.nodeName.toLowerCase() !== "a") {
        return;
    }

    var name = clicky_tracking[this.id];
    clicky.log(link.href, name, 'outbound');
}

Register the above handler with each root element.

for(var id in clicky_tracking) {
    var root = document.getElementById(id);
    root.onclick = logClick;
}

Also to avoid searching through the array, I've changed clicky_tracking from array to an object for easier keyed access.

var clicky_tracking = {
  'related-searches': 'Related Searches',
  'related-stories': 'Related Stories',
  'more-videos': 'More Videos',
  'web-headlines': 'Publication'
};
幸福不弃 2024-09-09 23:12:44

这段代码不太可维护!我讨厌把 jQuery 强加给你,但这看起来对你来说非常有用,比如:

$('a.trackable').click(function(e) {

  clicky.log(url, name, 'outbound');
};

你可以通过向每个链接添加“trackable”类来启用跟踪,并使用例如 $ 将链接映射到查找表(this).attr('rel').

希望这是有道理的。

This code isnt very maintainable! I hate shoving jQuery down your throat but this looks like a situation where is would be very useful to you, something like:

$('a.trackable').click(function(e) {

  clicky.log(url, name, 'outbound');
};

You could enable tracking by adding class 'trackable' to each link, and map links to a lookup table by using eg $(this).attr('rel').

Hope that makes sense.

浅浅 2024-09-09 23:12:44

您可以创建一个函数来构建事件处理程序,例如:

function createClickHandler(url, name) {
  return function () {
    clicky.log(url, name, 'outbound');
  };
}

for (var x = 0, length_x = clicky_tracking.length; x < length_x; x++) {
  links = document.getElementById(clicky_tracking[x][0]) // NOTE:links should be 
                  .getElementsByTagName('a');            // declared at the top
  for (var y = 0, length_y = links.length; y < length_y; y++) {
    links[y].onclick = createClickHandler(clicky_tracking[x][1], links[y].href);
  }
}

我还认为 事件委托也是一个非常好的选择,你可以很容易地实现它:

var clicky_tracking = [
  ['related-searches', 'Related Searches']
  //...
], elem;

function createClickHandler(name) { // capture only the 'name' variable
  return function (e) {
    e = e || window.event; // cross-browser way to get the event object
    var target = e.target || e.srcElement; // and the event target

    if (target.nodeName == "A") { // make sure that the target is an anchor
      clicky.log(target.href, name, 'outbound');
    }
  };
}

for (var x = 0, len = clicky_tracking.length; x < len; x++) {
  elem = document.getElementById(clicky_tracking[x][0]); // find parent element
  elem.onclick = createClickHandler(clicky_tracking[x][1]); // bind the event
}
​

You could create a function to build the event handlers, e.g.:

function createClickHandler(url, name) {
  return function () {
    clicky.log(url, name, 'outbound');
  };
}

for (var x = 0, length_x = clicky_tracking.length; x < length_x; x++) {
  links = document.getElementById(clicky_tracking[x][0]) // NOTE:links should be 
                  .getElementsByTagName('a');            // declared at the top
  for (var y = 0, length_y = links.length; y < length_y; y++) {
    links[y].onclick = createClickHandler(clicky_tracking[x][1], links[y].href);
  }
}

I also think that event delegation is also a really good option, you can implement it very easily:

var clicky_tracking = [
  ['related-searches', 'Related Searches']
  //...
], elem;

function createClickHandler(name) { // capture only the 'name' variable
  return function (e) {
    e = e || window.event; // cross-browser way to get the event object
    var target = e.target || e.srcElement; // and the event target

    if (target.nodeName == "A") { // make sure that the target is an anchor
      clicky.log(target.href, name, 'outbound');
    }
  };
}

for (var x = 0, len = clicky_tracking.length; x < len; x++) {
  elem = document.getElementById(clicky_tracking[x][0]); // find parent element
  elem.onclick = createClickHandler(clicky_tracking[x][1]); // bind the event
}
​
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文