function highlight(s, id) {
	// 判断传入的字符串s的长度是否为0，如果长度为0，表示可能不需要进行高亮相关操作了，执行以下代码块
	if (s.length == 0) {
		// 通过document.getElementById方法根据传入的id获取对应的DOM元素，并将其赋值给变量obj，后续会对这个元素的innerHTML内容进行处理
		var obj = document.getElementById(id);
		// 使用正则表达式替换obj元素innerHTML中的内容，目的是去除已经存在的带有"highlight"类名的<span>标签，只保留其内部的文本内容，
		// 正则表达式 /<span\s+class=.?highlight.?>([^<>]*)<\/span>/gi 用于匹配包含"highlight"类名的<span>标签及其内部的非尖括号内容（通过 ([^<>]*) 捕获），并将匹配到的内容替换为捕获的内部文本内容（通过 $1 引用捕获组）
		var t = obj.innerHTML.replace(/<span\s+class=.?highlight.?>([^<>]*)<\/span>/gi, "$1");
		// 将处理后的文本内容重新赋值给obj元素的innerHTML属性，实现去除已有高亮标签的效果
		obj.innerHTML = t;
		// 返回false，表示在这种字符串长度为0的情况下，没有进行实际的搜索和高亮操作
		return false;
	}
	// 调用内部定义的encode函数，对传入的字符串s进行编码处理（主要是对一些特殊字符进行转义等操作，从函数内部实现可以看到具体转义的字符），并将结果重新赋值给s
	s = encode(s);
	// 通过document.getElementById方法根据传入的id获取对应的DOM元素，赋值给变量obj，后续会基于这个元素来查找匹配的文本并进行高亮显示操作
	var obj = document.getElementById(id);
	// 同样使用正则表达式替换obj元素innerHTML中的内容，去除已有的带有"highlight"类名的<span>标签，只保留其内部文本内容，与前面长度为0时的处理类似，目的是先清理之前可能存在的高亮标记，准备进行新的高亮操作
	var t = obj.innerHTML.replace(/<span\s+class=.?highlight.?>([^<>]*)<\/span>/gi, "$1");
	// 将清理后的文本内容重新赋值给obj元素的innerHTML属性
	obj.innerHTML = t;
	// 调用内部定义的loopSearch函数，传入经过编码处理的字符串s和获取到的DOM元素obj，这个函数会递归地在DOM元素及其子元素中查找匹配的文本内容，并返回匹配到的次数，将返回的结果赋值给变量cnt
	var cnt = loopSearch(s, obj);
	// 获取obj元素当前的innerHTML内容，并赋值给变量t，后续会基于这个内容再次进行处理，添加高亮显示的标签
	var t = obj.innerHTML
	// 定义一个正则表达式r，用于匹配之前在文本中标记好的需要高亮显示的位置（通过 {searchHL} 和 {/searchHL} 包裹的内容），以便后续将其替换为带有"highlight"类名的<span>标签来实现可视化的高亮效果
	var r = /{searchHL}(({(?!\/searchHL})|[^{])*){\/searchHL}/g
	// 使用正则表达式r对变量t（即obj元素的innerHTML内容）进行替换操作，将匹配到的用 {searchHL} 和 {/searchHL} 包裹的内容替换为带有"highlight"类名的<span>标签包裹的内容，实现文本的高亮显示效果，然后将替换后的结果重新赋值给变量t
	t = t.replace(r, "<span class='highlight'>$1</span>");
	// 将添加了高亮显示标签后的文本内容重新赋值给obj元素的innerHTML属性，使得页面上对应的DOM元素中的文本呈现出高亮显示的效果
	obj.innerHTML = t;

	// 定义一个名为encode的内部函数，用于对传入的字符串进行编码处理，主要是对一些在正则表达式中有特殊含义或者HTML中有特殊用途的字符进行转义，防止出现意外的匹配或解析问题
	function encode(s) {
		// 使用字符串的replace方法，通过正则表达式匹配并替换相应的特殊字符，将 & 替换为 & （HTML实体编码转义），< 替换为 < （防止被解析为HTML标签开头），> 替换为 > （同理防止被解析为HTML标签结尾），
		// 对于正则表达式中有特殊含义的字符（如 \、.、*、[、]、(、)、$、^ 等），在其前面添加 \ 进行转义，使其在后续作为正则表达式内容时能按字面意思进行匹配，最后将处理后的字符串返回
		return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/([\\\.\*\[\]\(\)\$\^])/g, "\\$1");
	}

	// 定义一个名为decode的内部函数，与encode函数作用相反，用于对经过编码的字符串进行解码还原操作，将转义后的字符恢复为原来的字符形式
	function decode(s) {
		// 使用字符串的replace方法，通过正则表达式匹配并替换相应的转义字符，将前面添加了 \ 转义的字符（如 \[ 等）还原为原来的字符（去除前面的 \ ），
		// 然后将 > 替换为 > ，< 替换为 < ，& 替换为 & ，恢复字符串中这些特殊字符的原始形式，最后将处理后的字符串返回
		return s.replace(/\\([\\\.\*\[\]\(\)\$\^])/g, "$1").replace(/>/g, ">").replace(/</g, "<").replace(/&/g, "&");
	}

	// 定义一个名为loopSearch的内部函数，它会递归地在给定的DOM元素及其子元素中查找与传入字符串s匹配的文本内容，并统计匹配的次数，返回统计的匹配次数
	function loopSearch(s, obj) {
		// 初始化一个变量cnt，用于记录匹配到的次数，初始值设为0
		var cnt = 0;
		// 判断当前DOM元素obj的节点类型是否为3（在DOM中，节点类型3表示文本节点），如果是文本节点，则调用内部的replace函数在这个文本节点中查找并替换匹配的文本内容，并将返回的匹配次数赋值给cnt，然后直接返回cnt
		if (obj.nodeType == 3) {
			cnt = replace(s, obj);
			return cnt;
		}
		// 如果当前DOM元素不是文本节点，说明可能是包含子节点的元素节点（如<div>等），通过循环遍历它的子节点（使用childNodes属性获取子节点列表），
		// 对于每个子节点c，判断如果其不存在className属性或者className属性不等于"highlight"（即不是已经处理过的高亮显示的节点），则递归调用loopSearch函数在这个子节点中继续查找匹配内容，并将返回的匹配次数累加到变量cnt中
		for (var i = 0, c; c = obj.childNodes[i]; i++) {
			if (!c.className || c.className!= "highlight") {
				cnt += loopSearch(s, c);
			}

		}
		// 循环结束后，将统计好的匹配次数cnt返回，这个cnt就是整个DOM元素及其所有子元素中匹配到传入字符串s的总次数
		return cnt;
	}

	// 定义一个名为replace的内部函数，它用于在给定的文本节点dest中查找与传入字符串s匹配的文本内容，并进行替换操作，将匹配的内容用特定标记包裹起来（后续会进一步处理为高亮显示的标签），同时返回匹配到的次数
	function replace(s, dest) {
		// 根据传入的字符串s创建一个正则表达式对象r，设置全局匹配模式（g标志），用于在文本节点中查找所有匹配的内容
		var r = new RegExp(s, "g");
		// 初始化一个变量tm，用于存储通过正则表达式匹配到的结果，初始值设为null
		var tm = null;
		// 获取文本节点dest的nodeValue属性（即文本节点中的文本内容），赋值给变量t，后续会基于这个文本内容进行查找和替换操作
		var t = dest.nodeValue;
		// 初始化一个变量cnt，用于记录匹配到的次数，初始值设为0
		var cnt = 0;
		// 使用match方法在文本t中查找所有与正则表达式r匹配的内容，如果匹配到了（即tm不为null），则执行以下代码块
		if (tm = t.match(r)) {
			// 将匹配到的次数（即tm数组的长度，因为match方法返回的数组包含了所有匹配到的内容）赋值给变量cnt，记录匹配的次数
			cnt = tm.length;
			// 使用replace方法对文本t进行替换操作，将匹配到的内容替换为用 {searchHL} 和 {/searchHL} 包裹起来，并且内部通过decode函数对匹配的字符串s进行解码还原后的内容，
			// 这样就标记好了需要后续处理为高亮显示的文本位置，然后将替换后的结果重新赋值给文本节点dest的nodeValue属性，实现文本内容的初步替换标记
			t = t.replace(r, "{searchHL}" + decode(s) + "{/searchHL}")
			dest.nodeValue = t;
		}
		// 将记录的匹配次数cnt返回，供外部调用的函数（如loopSearch函数）获取并进一步处理（比如累加统计总的匹配次数等）
		return cnt;
	}
}