前端面试题总结(算法)
javascript递归遍历所有DOM文档节点
//当窗体加载完毕后触发此函数
window.onload = function() {
//document 获取根元素
var root = document.documentElement;
//遍历所哟的节点
traverseNodes(root);
document.write(msg);
}
function traverseNodes(node) {
//判断是否是元素节点
if (node.nodeType == 1) {
display(node);
//判断是否有属性节点
for (var i = 0; i < node.attributes.length; i++) {
//得到属性节点
var attr = node.attributes.item(i);
//判断该节点是否存在
if (attr.specified) {
//如果存在 显示输出
display(attr);
}
}
//判断该元素节点是否有子节点
if (node.hasChildNodes) {
//得到所有的子节点
var sonnodes = node.childNodes;
//遍历所哟的子节点
for (var i = 0; i < sonnodes.length; i++) {
//得到具体的某个子节点
var sonnode = sonnodes.item(i);
//递归遍历 traverseNodes(sonnode);
}
}
} else {
display(node);
}
}
var msg = "";
var num = 0;
function display(node) {
msg += (++num) + " nodeName=" + node.nodeName + " nodeValue=" + node.nodeValue + " nodeType=" + node.nodeType + "<br/>";
}
HTTP 方法:GET 对比 POST
- GET 方法
请注意,查询字符串(名称/值对)是在 GET 请求的 URL 中发送的:
有关 GET 请求的其他一些注释:
GET 请求可被缓存
GET 请求保留在浏览器历史记录中
GET 请求可被收藏为书签
GET 请求不应在处理敏感数据时使用
GET 请求有长度限制
GET 请求只应当用于取回数据
/test/demo_form.asp?name1=value1&name2=value2
- POST 方法
请注意,查询字符串(名称/值对)是在 POST 请求的 HTTP 消息主体中发送的:
POST /test/demo_form.asp HTTP/1.1
Host: w3schools.com
name1=value1&name2=value2
有关 POST 请求的其他一些注释:
POST 请求不会被缓存
POST 请求不会保留在浏览器历史记录中
POST 不能被收藏为书签
POST 请求对数据长度没有要求
GET访问 浏览器 认为 是等幂的就是 一个相同的URL 只有一个结果[相同是指 整个URL字符串完全匹配]所以 第二次访问的时候 如果 URL字符串没变化 浏览器是 直接拿出了第一次访问的结果
POST则 认为是一个 变动性 访问 (浏览器 认为 POST的提交 必定是 有改变的)
防止 GET 的 等幂 访问 就在URL后面加上 ?+new Date();,[总之就是使每次访问的URL字符串不一样的]设计WEB页面的时候 也应该遵守这个原则
GET请求没有body
ajax 缓存
HTTP缓存,明确的要知道GET请求可以被缓存,POST不能被缓存,所以要想在客户端做HTTP的缓存一定要注意使用GET请求!
谈Ajax的Get和Post的区别:
- 用get方式可传送简单数据,但大小一般限制在1KB下,数据追加到url中发送(http的header传送),也就是说,浏览器将各个表单字段元素及其数据按照URL参数的格式附加在请求行中的资源路径后面。
另外最重要的一点是,它会被客户端的浏览器缓存起来,那么,别人就可以从浏览器的历史记录中,读取到此客户的数据,比如帐号和密码等。
因此,在某些情况下,get方法会带来严重的安全性问题。 - Post方式:当使用POST方式时,浏览器把各表单字段元素及其数据作为HTTP消息的实体内容发送(
xmlHttp.send(name)
; 如果是get方式,直接xmlHttp.send(null);
)给Web服务器,而不是作为URL地址的参数进行传递,使用POST方式传递的数据量要比使用GET方式传送的数据量大的多。` - 总之,GET方式传送数据量小,处理效率高,安全性低,会被缓存,而POST反之。
使用get方式需要注意:
- 对于get请求(或凡涉及到url传递参数的),被传递的参数都要先经encodeURIComponent方法处理.例:
var url = "update.php?username=" +encodeURIComponent(username) + "&content=" +encodeURIComponent(content)+"&id=1" ;
使用Post方式需注意:
- 设置header的Context-Type为application/x-www-form-urlencode确保服务器知道实体中有参数变量. 通常使用XmlHttpRequest对象的
SetRequestHeader("Context-Type","application/x-www- form-urlencoded;")
。例:xmlHttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded")
; - 参数是名/值一一对应的键值对,每对值用&号隔开.如 var name=abc&sex=man&age=18,注意var name=update.php?abc&sex=man&age=18以及var name=?abc&sex=man&age=18的写法都是错误的;
- **参数在Send(参数)方法中发送,例:
xmlHttp.send(name)
; 如果是get方式,直接xmlHttp.send(null);
** - 服务器端请求参数区分Get与Post。如果是get方式则$username = $_GET["username"]; 如果是post方式,则$username = $_POST["username"];
ajax cache参数:
cache (默认: true, dataType为"script"和"jsonp"时默认为false)
类型: Boolean
如果设置为 false ,浏览器将不缓存此页面。注意: 设置cache
为 false将在 HEAD和GET请求中正常工作。它的工作原理是在GET请求参数中附加"_={timestamp}"(译者注:时间戳)。该参数不是其他请求所必须的,除了在IE8中,当一个POST请求一个已经用GET请求过的URL。
如果客户端发送的是一个条件验证(Conditional Validation)请求,则web服务器可能会返回HTTP/304响应,这就表明了客户端中所请求资源的缓存仍然是有效的,也就是说该资源从上次缓存到现在并没有被修改过.条件请求可以在确保客户端的资源是最新的同时避免因每次都请求完整资源给服务器带来的性能问题.
全面:HTTP缓存
操作 Cache-Control Last-Modified/Etag
前进后退 有效 有效
刷新-F5 无效 有效
强制刷新 无效
浏览器是否使用缓存、缓存多久,是由服务器控制的。
网站优化:浏览器缓存控制简介及配置策略
使用缓存的策略
- 为静态资源设置长缓存时间
有些资源是很长时间不会改变的,比如网站的 logo 图片、jQuery 库、字体等,因此可以为它们设定「永不过期」的缓存时间,例如设定为 10 年。 - 确保文件修改生效
我觉得因为我们的静态资源设置了长缓存,所以我们更新了js后,给它加版本号取新的
有些时候我们会修改一些资源,比如更新了 jQuery 版本,或网站的 CSS 样式。如果这些资源已经被缓存,那么除非用户手工刷新页面,否则要等缓存自然过期之后用户才会获得新版本。如何在这种情况下强制浏览器重新下载呢?最有效的一个办法就是在这类资源的文件名中包含版本信息,并在更改之后对应地修改文件名。浏览器发现文件更换后,自然无法使用缓存,而会重新下载。
- 对于 HTML 文档谨慎设定过期时间
大部分情况下,对于其他图片、CSS、JavaScript 等资源的请求都来自一个单一的 HTML 文档。对于这类页面通常应该设定比较短的过期时间,或者干脆不设定。因为如果这类页面被缓存,那么页面中包含的资源的文件名等等信息都会一并被缓存,导致对它的更新难以确保立即对用户生效。 - 引用静态资源时,不要使用 Query String
Query String 就是例如?key=val
的字符串,如
<script src="/static/js/func.js?v=a87ff8"></script>
这会阻止一部分较老的浏览器(包括 IE6 )对该资源进行缓存。
函数声明
var getfn = function(){
function f(){
return 1
}
return f();
function f(){
return 3;
}
var f;
f = 2;
}
console.log(getfn());//3
函数提升优先级比变量提升要高,且不会被变量声明覆盖,但是会被变量赋值覆盖,所以你上面的代码实际上是
function foo(){
console.log("函数声明");
}
var foo;
console.log(foo);
foo = "变量";
在最后再加上打印就能看到函数已经被覆盖了。
注:初始化变量不会把值也提上上去,只会提升变量的声明。
这是一项很古老的规则。少数事件,例如focus,blur,change等,并不会在dom树上冒泡。这样设计准确的原因已经无从考究,但部分原因只是由于这些事件对一些元素来说是没有意义的。用户不可能更改或聚焦于一段随即的段落上。因此这些事件不支持这一些html标签。于是,它们不会发生冒泡了。
图片
冒泡排序O(n^2)
function bubbleSort(arr) {
var len = arr.length;
var temp;
while (len > 0) {
for (var j = 0; j < len - 1; j++) {
if (arr[j] > arr[j + 1]) {
temp = arr[j + 1];
arr[j + 1] = arr[j];
arr[j] = temp;
}
}
len--;
}
return arr;
}
快速排序O(nlogn)
快速排序:
思路:找到数组中间的元素,把它单拎出来,然后从0开始判断数组中的元素比该基准元素大还是小,小的存左边,大的存右边,然后如此反复递归,得出结果。
function quickSort(arr) {
if (arr.length <= 1) { return arr; }//如果输入数组长度小于等于1,直接返回数组。这也是递归算法的终结部分
var base = Math.floor(arr.length / 2);//找到中间的基准元素位置
var baseEle = arr.splice(base, 1)[0];//把基准元素从arr中摘除
var left = [];
var right = [];
for (var i = 0; i < arr.length; i++) {
if (arr[i] < baseEle) {
left.push(arr[i]);
} else {
right.push(arr[i]);
}
}
return quickSort(left).concat([baseEle ], quickSort(right));
//返回递归左右两个部分concat中间元素,这就是结果
};
console.log(quickSort([3,2,1]))
二分查找
/**
* [binarySearch 二分查找]
* @param {[type]} value [查找元素]
* @param {[type]} arr [数组]
* @param {[type]} startIndex [开始索引]
* @param {[type]} endIndex [结束索引]
* @return {[type]} [返回查找元素的索引]
*/
function binarySearch(value,arr,startIndex,endIndex) {
if(!value|| !(arr instanceof Array)) return;
var len = arr.length,
startIndex = typeof startIndex === "number" ? startIndex : 0,
endIndex = typeof endIndex === "number" ? endIndex : len-1,
midIndex = Math.floor((startIndex + endIndex) / 2),
midval = arr[midIndex];
if(startIndex > endIndex) return ;
if(midval === value){
return midIndex;
}else if (midval > value) {
return binarySearch(value, arr, startIndex, midIndex - 1);
}else {
return binarySearch(value, arr, midIndex + 1, endIndex);
}
}
console.log(binarySearch(3,[1,2,3,4,5,6,7]));//2
插入排序 O(n^2)
⒈从有序数列和无序数列{a2,a3,…,an}开始进行排序;
⒉处理第i个元素时(i=2,3,…,n),数列{a1,a2,…,ai-1}是已有序的,而数列{ai,ai+1,…,an}是无序的。用ai与ai-1,a i-2,…,a1进行比较,找出合适的位置将ai插入;
⒊重复第二步,共进行n-i次插入处理,数列全部有序。
function insertSort(arr)
{
var len=arr.length;
var temp;
for(var i=1;i<len;i++)
{
var t=i-1;
while(t>=0 && arr[t]>arr[t+1])
{
temp=arr[t+1];
arr[t+1]=arr[t];
arr[t]=temp;
t--;
}
}
return arr;
}
选择排序 O(n^2)
对比数组中前一个元素跟后一个元素的大小,如果后面的元素比前面的元素小则用一个变量k来记住他的位置,接着第二次比较,前面“后一个元素”现变成了“前一个元素”,继续跟他的“后一个元素”进行比较如果后面的元素比他要小则用变量k记住它在数组中的位置(下标),等到循环结束的时候,我们应该找到了最小的那个数的下标了,然后进行判断,如果这个元素的下标不是第一个元素的下标,就让第一个元素跟他交换一下值,这样就找到整个数组中最小的数了。然后找到数组中第二小的数,让他跟数组中第二个元素交换一下值,以此类推。
function selectionSort(arr)
{
var len=arr.length;
var temp,min;
for(var j =0;j<len-1;j++)
{
min=j;
//查找最小值
for(var i=j+1;i<len;i++)
{
if(arr[i]<arr[min])
{
min=i;
}
}
//交换
if(min!=j)
{
temp=arr[min];
arr[min]=arr[j];
arr[j]=temp;
}
}
return arr;
}
arr.sort方法的实现
上一篇: 她是唐太祖李世民的姐姐 那么平阳昭公主到底有多厉害呢
下一篇: IE之死__原来与CSS有关