如何获取页面出现次数最多的 HTML 标签

相同点:

递归和迭代都是循环的一种。

不同点:

1、程序结构不同

递归是重复调用函数自身实现循环。迭代是函数内某段代码实现循环。 其中,迭代与普通循环的区别是:迭代时,循环代码中参与运算的变量同时是保存结果的变量,当前保存的结果作为下一次循环计算的初始值。

2、算法结束方式不同

递归循环中,遇到满足终止条件的情况时逐层返回来结束。迭代则使用计数器结束循环。 当然很多情况都是多种循环混合采用,这要根据具体需求。

3、效率不同

在循环的次数较大的时候,迭代的效率明显高于递归


这是一道前端基础与编程功底具备的面试题:

如果你前端基础强会了解 document.querySelector(*) 能够列出页面内所有标签
如果你编程能力强能够用递归/正则快速实现同等的效果
有三种 API 可以列出页面所有标签:

  1. document.querySelector(‘*’),标准规范实现
  2. $$(‘*’),devtools 实现
  3. document.all,非标准规范实现

document.querySelectorAll(‘*’)

1
2
3
4
5
6
7
8
< NodeList(593) [html, head, meta, meta, meta, meta, meta, meta, meta, title, link#favicon, link, link#MainCss, link#mobile-style, link, link, link, script, script, script, script, script, script, script, link, script, link, link, script, input#_w_brink, body, a, div#home, div#header, div#blogTitle, a#lnkBlogLogo, img#blogLogo, h1, a#Header1_HeaderTitle.headermaintitle.HeaderMainTitle, h2, div#navigator, ul#navList, li, a#blog_nav_sitehome.menu, li, a#blog_nav_myhome.menu, li, a#blog_nav_newpost.menu, li, a#blog_nav_contact.menu, li, a#blog_nav_rss.menu, li, a#blog_nav_admin.menu, div.blogStats, span#stats_post_count, span#stats_article_count, span#stats-comment_count, div#main, div#mainContent, div.forFlow, div#post_detail, div#topics, div.post, h1.postTitle, a#cb_post_title_url.postTitle2.vertical-middle, span, div.clear, div.postBody, div#cnblogs_post_body.blogpost-body, p, p, strong, p, p, p, strong, div.cnblogs_code, pre, span, span, span, span, span, p, span, strong, pre, strong, span, strong, br, br, br, div.cnblogs_code, pre, span, span, p, p, …]
[099]
[100199]
[200299]
[300399]
[400499]
[500592]
__proto__: NodeList

使用 document.querySelectorAll 实现如下

1
2
3
4
5
6
7
8
9
10
// 实现一个 maxBy 方便找出出现次数最多的 HTML 标签
const maxBy = (list, keyBy) => list.reduce((x, y) => keyBy(x) > keyBy(y) ? x : y)

function getFrequentTag () {
const tags = [...document.querySelectorAll('*')].map(x => x.tagName).reduce((o, tag) => {
o[tag] = o[tag] ? o[tag] + 1 : 1;
return o
}, {})
return maxBy(Object.entries(tags), tag => tag[1])
}

使用 element.children 递归迭代如下 (最终结果多一个 document)

1
2
3
4
5
6
7
8
9
10
function getAllTags(el = document) {
const children = Array.from(el.children).reduce((x, y) => [...x, ...getAllTags(y)], [])
return children
}

// 或者通过 flatMap 实现
function getAllTags(el = document) {
const children = Array.prototype.flatMap.call(el.children, x => getAllTags(x))
return [el, ...children]
}

参考链接

如何获取页面出现次数最多的 HTML 标签


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!