当前位置:  开发笔记 > 编程语言 > 正文

常见前端面试题及答案

本文是在GitHub上看到一个大牛总结的前端常见面试题,很多问题问的都很好,很经典、很有代表性。上面没有答案,我就整理了一下,从网上找了一些相关问题的答案

前言

本文是在GitHub上看到一个大牛总结的前端常见面试题,很多问题问的都很好,很经典、很有代表性。上面没有答案,我就整理了一下,从网上找了一些相关问题的答案。里面有一部分问题的答案我也没有进行考证,不少答案都来源于网络,或许会有疏漏之处,仅供大家参考哦!(还有一部分问题答案还未整理,大家也可以自己搜索一下答案)

1.你能描述一下渐进增强和优雅降级之间的不同吗?

优雅降级:Web站点在所有新式浏览器中都能正常工作,如果用户使用的是老式浏览器,则代码会检查以确认它们是否能正常工作。由于IE独特的盒模型布局问题,针对不同版本的IE的hack实践过优雅降级了,为那些无法支持功能的浏览器增加候选方案,使之在旧式浏览器上以某种形式降级体验却不至于完全失效.

渐进增强:从被所有浏览器支持的基本功能开始,逐步地添加那些只有新式浏览器才支持的功能,向页面增加无害于基础浏览器的额外样式和功能的。当浏览器支持时,它们会自动地呈现出来并发挥作用。

2.线程与进程的区别

一个程序至少有一个进程,一个进程至少有一个线程。线程的划分尺度小于进程,使得多线程程序的并发性高。

另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。

线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。

从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。

3.说说你对语义化的理解?

•1:去掉或样式丢失的时候能让页面呈现清晰的结构:html本身是没有表现的,我们看到例如

是粗体,字体大小2em,加粗;是加粗的,不要认为这是html的表现,这些其实html默认的css样式在起作用,所以去掉或样式丢失的时候能让页面呈现清晰的结构不是语义化的HTML结构的优点,但是浏览器都有有默认样式,默认样式的目的也是为了更好的表达html的语义,可以说浏览器的默认样式和语义化的HTML结构是不可分割的。
•2.屏幕阅读器(如果访客有视障)会完全根据你的标记来“读”你的网页。
•3.PDA、手机等设备可能无法像普通电脑的浏览器一样来渲染网页(通常是因为这些设备对CSS的支持较弱)。
•4.有利于SEO:和搜索引擎建立良好沟通,有助于爬虫抓取更多的有效信息:爬虫依赖于标签来确定上下文和各个关键字的权重。
•6.便于团队开发和维护,语义化更具可读性,是下一步吧网页的重要动向,遵循W3C标准的团队都遵循这个标准,可以减少差异化。

4.你如何对网站的文件和资源进行优化?

期待的解决方案包括:文件合并文件最小化/文件压缩使用CDN托管缓存的使用(多个域名来提供缓存)其他。

5.为什么利用多个域名来提供网站资源会更有效?

•1.CDN缓存更方便
•2.突破浏览器并发限制(一般每个域名建立的链接不超过6个)
•3.Cookieless,节省带宽,尤其是上行带宽一般比下行要慢
•4.对于UGC的内容和主站隔离,防止不必要的安全问题(上传js窃取主站cookie之类的)。正是这个原因要求用户内容的域名必须不是自己主站的子域名,而是一个完全独立的第三方域名。
•5.数据做了划分,甚至切到了不同的物理集群,通过子域名来分流比较省事。这个可能被用的不多。

PS:关于Cookie的问题,带宽是次要的,安全隔离才是主要的。关于多域名,也不是越多越好,虽然服务器端可以做泛解释,浏览器做dns解释也是耗时间的,而且太多域名,如果要走https的话,还有要多买证书和部署的问题。

6.请说出三种减少页面加载时间的方法。(加载时间指感知的时间或者实际加载时间)

•1.优化图片
•2.图像格式的选择(GIF:提供的颜色较少,可用在一些对颜色要求不高的地方)
•3.优化CSS(压缩合并css,如margin-top,margin-left...)
•4.网址后加斜杠(如www.campr.com/目录,会判断这个“目录是什么文件类型,或者是目录。)
•5.标明高度和宽度(如果浏览器没有找到这两个参数,它需要一边下载图片一边计算大小,如果图片很多,浏览器需要不断地调整页面。这不但影响速度,也影响浏览体验。当浏览器知道了高度和宽度参数后,即使图片暂时无法显示,页面上也会腾出图片的空位,然后继续加载后面的内容。从而加载时间快了,浏览体验也更好了。)
•6.减少http请求(合并文件,合并图片)。

7.如果你参与到一个项目中,发现他们使用Tab来缩进代码,但是你喜欢空格,你会怎么做?

•建议这个项目使用像EditorConfig(http://editorconfig.org/)之类的规范
•为了保持一致性,接受项目原有的风格
•直接使用VIM的retab命令

8.请写一个简单的幻灯效果页面

如果不使用JS来完成,可以加分。(如:纯CSS实现的幻灯片效果)

9.你都使用哪些工具来测试代码的性能?

Profiler,JSPerf(http://jsperf.com/nexttick-vs-setzerotimeout-vs-settimeout),Dromaeo。

10.如果今年你打算熟练掌握一项新技术,那会是什么?

nodejs,html5,css3,less等。

11.请谈一下你对网页标准和标准制定机构重要性的理解。

w3c存在的意义就是让浏览器兼容性问题尽量小,首先是他们对浏览器开发者的约束,然后是对开发者的约束。

12.什么是FOUC(无样式内容闪烁)?你如何来避免FOUC?

FOUC(Flash Of Unstyled Content)--文档样式闪烁

而引用CSS文件的@import就是造成这个问题的罪魁祸首。IE会先加载整个HTML文档的DOM,然后再去导入外部的CSS文件,因此,在页面DOM加载完成到CSS导入完成中间会有一段时间页面上的内容是没有样式的,这段时间的长短跟网速,电脑速度都有关系。解决方法简单的出奇,只要在之间加入一个或者

this is first p

运行后,你会发现新增的p元素,并没用被绑定click事件。你可以改成.live(“click”)方式解决此问题,代码如下:

$(function() {
  $("p").live("click",function() {
    // 改成live方式
    alert($(this).text());
  });

  $("button").click(function() {
    $("

this is second p

").appendTo("body"); }); })

但我并不建议大家这么做,我想用另一种方式去解决这个问题,代码如下:

$(function() {
  $("p").click(function() {
    alert($(this).text());
  });

  $("button").click(function() {
    $("

this is second p

").click(function() { // 为新增的元素重新绑定一次 alert($(this).text()); }).appendTo("body"); }); })

虽然我把绑定事件重新写了一次,代码多了点,但这种方式的效率明显高于live()方式,特别是在频繁的DOM操作中,这点非常明显。

80.请解释.end()的用途。

在官方的API上是这样描述end()方法的:“回到最近的一个"破坏性"操作之前。即,将匹配的元素列表变为前一次的状态。”;看样子好像是找到最后一次操作的元素的上一元素,在如下的例子中:html代码:

复制代码 代码如下:

 
测试内容1
测试内容2

jQuery代码:

复制代码 代码如下:
$('

新增内容

').appendTo('div').addClass('c1').end().addClass('c2');

复制代码代码如下:

测试内容1

新增内容

测试内容2

新增内容

这里我就有一点不太明白了,怎么只有第一个

标签有两个样式,end()方法后返回的是什么,在火狐里添加了监控,得到如下结果:1.$('

新增内容

').appendTo('div')返回的是:[p,p]对象数组,即新增后的两个p标签;2.$('

新增内容

').appendTo('div').addClass('c1')返回的是:[p.c1,p.c1]对象数组,即添加了c1类样式后的p对象数组;3.$('

新增内容

').appendTo('div').addClass('c1').end()返回的是[p.c1],是第1个
中的

,在2操作中,最后“破坏”的是第2个

中的

,所以他的前一次操作的对象是第1个

中的

,返回的就是它;4.$('

新增内容

').appendTo('div').addClass('c1').end().addClass('c2')返回的仍然是第1个
中的

;现在算是有点明白了,关键是要搞清楚最后一次操作的元素的上一元素是什么。

81.你如何给一个事件处理函数命名空间,为什么要这样做?

任何作为type参数的字符串都是合法的;如果一个字符串不是原生的JavaScript事件名,那么这个事件处理函数会绑定到一个自定义事件上。这些自定义事件绝对不会由浏览器触发,但可以通过使用.trigger()或者.triggerHandler()在其他代码中手动触发。如果type参数的字符串中包含一个点(.)字符,那么这个事件就看做是有命名空间的了。这个点字符就用来分隔事件和他的命名空间。举例来说,如果执行.bind('click.name',handler),那么字符串中的click是事件类型,而字符串name就是命名空间。命名空间允许我们取消绑定或者触发一些特定类型的事件,而不用触发别的事件。参考unbind()来获取更多信息。

jQuery的bind/unbind方法应该说使用很简单,而且大多数时候可能并不会用到,取而代之的是直接用click/keydown之类的事件名风格的方法来做事件绑定操作。

但假设如下情况:需要在运行时根据用户交互的结果进行不同click事件处理逻辑的绑定,因而理论上会无数次对某一个事件进行bind/unbind操作。但又希望unbind的时候只把自己绑上去的处理逻辑给释放掉而不是所有其他地方有可能的额外的同一事件绑定逻辑。这时候如果直接用.click()/.bind('click')加上.unbind('click')来进行重复绑定的话,被unbind掉的将是所有绑定在元素上的click处理逻辑,潜在会影响到该元素其他第三方的行为。

当然如果在bind的时候是显示定义了function变量的话,可以在unbind的时候提供function作为第二个参数来指定只unbind其中一个处理逻辑,但实际应用中很可能会碰到各种进行匿名函数绑定的情况。对于这种问题,jQuery的解决方案是使用事件绑定的命名空间。即在事件名称后添加.something来区分自己这部分行为逻辑范围。

比如用.bind('click.myCustomRoutine',function(){...});同样是把匿名函数绑定到click事件(你可以用自己的命名空间多次绑定不同的行为方法上去),当unbind的时候用.unbind('click.myCustomRoutine')即可释放所有绑定到.myCustomRoutine命名空间的click事件,而不会解除其他通过.bind('click')或另外的命名空间所绑定的事件行为。同时,使用命令空间还可以让你一次性unbind所有此命名空间下的自定义事件绑定,通过.unbind('.myCustomRoutine')即可。要注意的是,jQuery的命名空间并不支持多级空间。

因为在jQuery里面,如果用.unbind('click.myCustomRoutine.myCustomSubone'),解除的是命名空间分别为myCustomRoutine和myCustomSubone的两个并列命名空间下的所有click事件,而不是"myCustomRoutine下的myCustomSubone子空间"。

82.请说出你可以传递给jQuery方法的四种不同值。

选择器(字符串),HTML(字符串),回调函数,HTML元素,对象,数组,元素数组,jQuery对象等。

83.什么是效果队列?

jQuery中有个动画队列的机制。当我们对一个对象添加多次动画效果时后添加的动作就会被放入这个动画队列中,等前面的动画完成后再开始执行。可是用户的操作往往都比动画快,如果用户对一个对象频繁操作时不处理动画队列就会造成队列堆积,影响到效果。jQuery中有stop这个方法可以停止当前执行的动画,并且它有两个布尔参数,默认值都为false。第一个参数为true时会清空动画队列,第二个参数为true时会瞬间完成掉当前动画。所以,我们经常使用obj.stop(true,true)来停止动画。但是这还不够!正如jQuery文档中的说法,即使第二个参数为true,也仅仅是把当前在执行的动画跳转到完成状态。这时第一个参数如果也为true,后面的队列就会被清空。如果一个效果需要多个动画同时处理,我们仅完成其中的一个而把后面的队列丢弃了,这就会出现意料之外的结果。

84.请指出.get(),[],eq()的区别。

eq:返回是一个jquery对象作用是将匹配的元素集合缩减为一个元素。这个元素在匹配元素集合中的位置变为0,而集合长度变成1。

get:是一个html对象数组作用是取得其中一个匹配的元素。num表示取得第几个匹配的元素。

85.请指出.bind(),.live()和.delegate()的区别。

在操纵DOM的语境中,document是根节点。现在我们可以较容易地说明.bind()、.live()和.delegate()的不同之处了。

.bind()

复制代码 代码如下:

$('a').bind('click', function() {alert("That tickles!")});

这是最简单的绑定方法了。JQuery扫描文档找出所有的$(‘a')元素,并把alert函数绑定到每个元素的click事件上。

.live()

复制代码 代码如下:

$('a').live('click', function() {alert("That tickles!")});

JQuery把alert函数绑定到$(document)元素上,并使用'click'和'a'作为参数。任何时候只要有事件冒泡到document节点上,它就查看该事件是否是一个click事件,以及该事件的目标元素与'a'这一CSS选择器是否匹配,如果都是的话,则执行函数。

live方法还可以被绑定到具体的元素(或context)而不是document上,像这样:

复制代码 代码如下:

$('a', $('#container')[0]).live(...);

.delegate()
复制代码 代码如下:

$('#container').delegate('a', 'click', function() {alert("That tickles!")});

JQuery扫描文档查找$(‘#container'),并使用click事件和'a'这一CSS选择器作为参数把alert函数绑定到$(‘#container')上。任何时候只要有事件冒泡到$(‘#container')上,它就查看该事件是否是click事件,以及该事件的目标元素是否与CCS选择器相匹配。如果两种检查的结果都为真的话,它就执行函数。

可以注意到,这一过程与.live()类似,但是其把处理程序绑定到具体的元素而非document这一根上。精明的JS'er们可能会做出这样的结论,即$('a').live()==$(document).delegate('a'),是这样吗?嗯,不,不完全是。

为什么.delegate()要比.live()好用?

基于几个原因,人们通常更愿意选用jQuery的delegate方法而不是live方法。考虑下面的例子:

复制代码 代码如下:

 $('a').live('click', function(){blah()}); // 或者
 $(document).delegate('a', 'click', function(){blah()});

速度

后者实际上要快过前者,因为前者首先要扫描整个的文档查找所有的$(‘a')元素,把它们存成jQuery对象。尽管live函数仅需要把'a'作为串参数传递以用做之后的判断,但是$()函数并未知道被链接的方法将会是.live()。而另一方面,delegate方法仅需要查找并存储$(document)元素。

一种寻求避开这一问题的方法是调用在$(document).ready()之外绑定的live,这样它就会立即执行。在这种方式下,其会在DOM获得填充之前运行,因此就不会查找元素或是创建jQuery对象了。

灵活性和链能力

live函数也挺令人费解的。想想看,它被链到$(‘a')对象集上,但其实际上是在$(document)对象上发生作用。由于这个原因,它能够试图以一种吓死人的方式来把方法链到自身上。实际上,我想说的是,以$.live(‘a',…)这一形式作为一种全局性的jQuery方法,live方法会更具意义一些。

仅支持CSS选择器

最后一点,live方法有一个非常大的缺点,那就是它仅能针对直接的CSS选择器做操作,这使得它变得非常的不灵活。
•为什么选择.live()或.delegate()而不是.bind()?

毕竟,bind看起来似乎更加的明确和直接,难道不是吗?嗯,有两个原因让我们更愿意选择delegate或live而不是bind:

为了把处理程序附加到可能还未存在于DOM中的DOM元素之上。因为bind是直接把处理程序绑定到各个元素上,它不能把处理程序绑定到还未存在于页面中的元素之上。

如果你运行了$(‘a').bind(…),而后新的链接经由AJAX加入到了页面中,则你的bind处理程序对于这些新加入的链接来说是无效的。而另一方面live和delegate则是被绑定到另一个祖先节点上,因此其对于任何目前或是将来存在于该祖先元素之内的元素都是有效的。

或者为了把处理程序附加到单个元素上或是一小组元素之上,监听后代元素上的事件而不是循环遍历并把同一个函数逐个附加到DOM中的100个元素上。把处理程序附加到一个(或是一小组)祖先元素上而不是直接把处理程序附加到页面中的所有元素上,这种做法带来了性能上的好处。

停止传播

最后一个我想做的提醒与事件传播有关。通常情况下,我们可以通过使用这样的事件方法来终止处理函数的执行:

复制代码 代码如下:

 $('a').bind('click', function(e) {
     e.preventDefault();
     // 或者 e.stopPropagation();
 });

不过,当我们使用live或是delegate方法的时候,处理函数实际上并没有在运行,需要等到事件冒泡到处理程序实际绑定的元素上时函数才会运行。而到此时为止,我们的其他的来自.bind()的处理函数早已运行了。

86.请指出$和$.fn的区别,或者说出$.fn的用途。

Jquery为开发插件提供了两个方法,分别是:

复制代码 代码如下:

 $.extend(obj);
 $.fn.extend(obj);
 

•1.那么这两个分别是什么意思?

$.extend(obj);是为了扩展jquery本身,为类添加新的方法。
$.fn.extend(obj);给JQUERY对象添加方法。

•2.$.fn中的fn是什么意思,其实是prototype,即$.fn=$.prototype;

具体用法请看下面的例子:

$.extend({

  add:function(a, b) {
    return a+b;
  }
})

$.add(5,8); // return 13

注意没有,这边的调用直接调用,前面不用任何对象。直接$.+方法名

$.fn.extend(obj);对prototype进行扩展,为jquery类添加成员函数,jquery类的实例可以使用这个成员函数。

$.fn.extend({

  clickwhile:function(){

    $(this).click(function(){
      alert($(this).val())
    })
  }
})

$('input').clickwhile(); // 当点击输入框会弹出该对象的Value值


注意调用时候前面是有对象的。即$('input')这么个东西。

87.请写出一个函数实现N!的计算。N取很大的值时,该怎么办?

使用循环、递归都能写出函数。

当N取值很大时,应该考虑把数值转化为字符串再进行运算。大数乘法再转化为大数加法运算,其具体算法应该有不少C语言实现,可以参考一下。

88.modulo(12,5) //2 ;问题:实现满足上述结果的modulo函数。

89."i'm a lasagna hog".split("").reverse().join("");问题:上面的语句的返回值是什么?

答案:"goh angasal a m'i";

90.(window.foo||(window.foo="bar"));问题:window.foo的值是什么?

答案:"bar"只有window.foo为假时的才是上面答案,否则就是它本身的值。

var foo="Hello";(function(){var bar="World";alert(foo+bar);})();alert(foo+bar);

91.问题:上面两个alert的结果是什么?

答案:"Hello World"和ReferenceError:bar is not defined

92.var foo=[];foo.push(1);foo.push(2);问题:foo.length的值是什么?

答案:2

有趣的问题:

91.你编写过的最酷的代码是什么?其中你最自豪的是什么?

92.在你使用过的开发工具中,最喜欢哪个?

93.你有什么业余项目吗?是哪种类型的?

94.你最爱的IE特性是什么?

数据冰冷的,但我们要让数据温暖起来,改变我们的生活!

推荐阅读
mobiledu2402851323
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有