整理其他前端常见面试知识点

原文:http://segmentfault.com/a/1190000002562454

转自 : https://github.com/markyun/My-blog/tree/master/Front-end-Developer-Questions/Questions-and-Answers

注:本文是在原文基础上加上了自己的一些理解和想法,同时也删掉了一些部分的。(只是整理,非原创)

0.html语义化

1,去掉或者丢失样式的时候能够让页面呈现出清晰的结构
2,有利于SEO:和搜索引擎建立良好沟通,有助于爬虫抓取更多的有效信息:爬虫依赖于标签来确定上下文和各个关键字的权重;
3,方便其他设备解析(如屏幕阅读器、盲人阅读器、移动设备)以意义的方式来渲染网页;
4,便于团队开发和维护,语义化更具可读性,是下一步吧网页的重要动向,遵循W3C标准的团队都遵循这个标准,可以减少差异化。

1.CSS 选择符有哪些?哪些属性可以继承?优先级算法如何计算? CSS3新增伪类有那些?(这道题网易面试时问了好久,就是答不出来,哎。。。)

答: 

1.id选择器( # myid)

2.类选择器(.myclassname)
3.标签选择器(div, h1, p)
4.相邻选择器(h1 + p):选择的是紧邻在h1后面的p元素
5.子选择器(ul > li) : 就选择儿子,不选择孙子辈的
6.后代选择器(li a) : 选择所有的儿子,孙子,重孙子等等
7.通配符选择器( * ):选择所有
8.属性选择器(a[rel = "external"])
9.伪类选择器(a: hover, li:nth-child)
        
可继承的样式: font-size font-family color, text-indent;
        
不可继承的样式:border padding margin width height ;
        
优先级就近原则,同权重情况下样式定义最近者为准;
载入样式以最后载入的定位为准;

优先级为:
!important >  id > class > tag  
important 比内联优先级高,但内联比 id 要高
补充:!important是css1中的(额,一直都不知道,还以为是css3呢,惭愧啊。。。),由于IE并不支持该语法,所以我们可以利用这一点解决部分CSS的浏览器兼容问题。
如果把的CSS样式写为
a{color:teal !important;color:red}
,则在火狐和IE6+的浏览器里则以color:teal为准,
因为他们认识!important,则它的优化级高,所以采用color:teal。
而IE6呢,尤由它不认识!important,但能认识color:teal这个属性,所以color:teal和color:red都要采用,
但后来定义的颜色会覆盖 前面定义的颜色,也就是说color:red会覆盖color:teal,
所以我们在IE6里我看到的应该是red这个色。
CSS3新增伪类举例:

p:first-of-type 选择属于其父元素的首个 <p> 元素的每个 <p> 元素。
p:last-of-type  选择属于其父元素的最后 <p> 元素的每个 <p> 元素。
p:only-of-type  选择属于其父元素唯一的 <p> 元素的每个 <p> 元素。
p:only-child    选择属于其父元素的唯一子元素的每个 <p> 元素。(父元素中只能有且只有一个p元素)
p:nth-child(2)  选择属于其父元素的第二个子元素的每个 <p> 元素。
:enabled  :disabled 控制表单控件的禁用状态。
:checked        单选框或复选框被选中。

2.CSS3的新特性:

CSS3实现圆角(border-radius),阴影(box-shadow),
对文字加特效(text-shadow、),线性渐变(gradient),旋转(transform)
transform:rotate(9deg) scale(0.85,0.90) translate(0px,-30px) skew(-9deg,0deg);//旋转,缩放,定位,倾斜
增加了更多的CSS选择器  多背景 rgba 
在CSS3中唯一引入的伪元素是::selection.
媒体查询,多栏布局
border-image

//在这里补充一点,在工作中用到最多的样式(在一个表格中,当文字超出一定长度时,显示为省略号形式)

 xx;         //一定要设置宽度,不过可是设置为相对值,则可以实现自适应
text-overflow: ellipsis;
white-space: nowrap;     /*禁止自动换行*/
overflow: hidden;

3.xml与html的区别区别:

1.所有的标记都必须要有一个相应的结束标记
2.所有标签的元素和属性的名字都必须使用小写
3.所有的XML标记都必须合理嵌套
4.所有的属性必须用引号""括起来
5.把所有<和&特殊符号用编码表示
6.给所有属性赋一个值
7.不要在注释内容中使“--8.图片必须有说明文字

4.常见的兼容性问题

png24位的图片在iE6浏览器上出现背景,解决方案是做成PNG8.也可以引用一段脚本处理.
    
浏览器默认的margin和padding不同。解决方案是加一个全局的*{margin:0;padding:0;}来统一。
    
IE6双边距bug:块属性标签float后,又有横行的margin情况下,在ie6显示margin比设置的大。 
    
浮动ie产生的双倍距离(IE6双边距问题:在IE6下,如果对元素设置了浮动,同时又设置了margin-left或margin-right,margin值会加倍。)
      #box{ float:left; 10px; margin:0 0 0 100px;} 
    
     这种情况之下IE会产生20px的距离,解决方案是在float的标签样式控制中加入 ——_display:inline;将其转化为行内属性。(_这个符号只有ie6会识别)
    
渐进识别的方式,从总体中逐渐排除局部。 
    
      首先,巧妙的使用“9”这一标记,将IE游览器从所有情况中分离出来。 
      接着,再次使用“+”将IE8和IE7、IE6分离开来,这样IE8已经独立识别。
    
      css
          .bb{
           background-color:#f1ee18;/*所有识别*/
          .background-color:#00deff9; /*IE6、7、8识别*/
          +background-color:#a200ff;/*IE6、7识别*/
          _background-color:#1e0bd1;/*IE6识别*/ 
          } 
    
IE下,可以使用获取常规属性的方法来获取自定义属性,也可以使用getAttribute()获取自定义属性;
Firefox下,只能使用getAttribute()获取自定义属性. 
解决方法:统一通过getAttribute()获取自定义属性.
    
IE下,event对象有x,y属性,但是没有pageX,pageY属性; Firefox下,event对象有pageX,pageY属性,但是没有x,y属性.
解决方法:(条件注释)缺点是在IE浏览器下可能会增加额外的HTTP请求数。
    
Chrome 中文界面下默认会将小于 12px 的文本强制按照 12px 显示, 可通过加入 CSS 属性 -webkit-text-size-adjust: none; 解决.
    
超链接访问过后hover样式就不出现了 被点击访问过的超链接样式不在具有hover和active了解决方法是改变CSS属性的排列顺序:
    L-V-H-A :  a:link {} a:visited {} a:hover

5.关于浮动(原来有三种方法清除浮动,一直只知道clear :both;好忧桑。。。)

浮动元素脱离文档流,不占据空间。浮动元素碰到包含它的边框或者浮动元素的边框停留。

1.使用空标签清除浮动。
   这种方法是在所有浮动标签后面添加一个空标签 定义css clear:both. 弊端就是增加了无意义标签2.使用overflow。
   给包含浮动元素的父标签添加css属性 overflow:auto; zoom:1; zoom:1用于兼容IE6。
3.使用after伪对象清除浮动。
   该方法只适用于非IE浏览器。具体写法可参照以下示例。使用中需注意以下几点。一、该方法中必须为需要清除浮动元素的伪对象中设置 height:0,否则该元素会比实际高出若干像素;

6.浮动元素引起的问题和解决办法?

浮动元素引起的问题:
(1)父元素的高度无法被撑开,影响与父元素同级的元素
(2)与浮动元素同级的非浮动元素会跟随其后
(3)若非第一个元素浮动,则该元素之前的元素也需要浮动,否则会影响页面显示的结构
解决方法:
使用CSS中的clear:both;属性来清除元素的浮动可解决2、3问题,对于问题1,添加如下样式,给父元素添加clearfix样式:

.clearfix:after{content: ".";display: block;height: 0;clear: both;visibility: hidden;}
.clearfix{display: inline-block;} /* for IE/Mac */

7.清除浮动的几种方法

1,额外标签法,<div style="clear:both;"></div>(缺点:不过这个办法会增加额外的标签使HTML结构看起来不够简洁。)
2,使用after伪类

#parent:after{
    content:".";
    height:0;
    visibility:hidden;
    display:block;
    clear:both;
    }

3,浮动外部元素
4,设置`overflow`为`hidden`或者auto

8.线程与进程的区别(这是通信中的吧,学通信的我跪了。。。)

线程是指进程内的一个执行单元,也是进程内的可调度实体.
与进程的区别:
(1)地址空间:进程内的一个执行单元;进程至少有一个线程;它们共享进程的地址空间;而进程有自己独立的地址空间;
(2)资源拥有:进程是资源分配和拥有的单位,同一个进程内的线程共享进程的资源
(3)线程是处理器调度的基本单位,但进程不是.
4)二者均可并发执行.

进程和线程都是由操作系统所体会的程序运行的基本单元,系统利用该基本单元实现系统对应用的并发性。进程和线程的区别在于:

简而言之,一个程序至少有一个进程,一个进程至少有一个线程. 
线程的划分尺度小于进程,使得多线程程序的并发性高。 
另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。 
线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。 
从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。

进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位. 
线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源. 
一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行.

9.null和undefined的区别?(SAP问了一下)

null是一个表示"无"的对象,转为数值时为0;undefined是一个表示"无"的原始值,转为数值时为NaN。

当声明的变量还未被初始化时,变量的默认值为undefined。
null用来表示尚未存在的对象,常用来表示函数企图返回一个不存在的对象。

undefined表示"缺少值",就是此处应该有一个值,但是还没有定义。典型用法是:

(1)变量被声明了,但没有赋值时,就等于undefined。

(2) 调用函数时,应该提供的参数没有提供,该参数等于undefined。

(3)对象没有赋值的属性,该属性的值为undefined。

(4)函数没有返回值时,默认返回undefined。
null表示"没有对象",即该处不应该有值。典型用法是:

(1) 作为函数的参数,表示该函数的参数不是对象。

(2) 作为对象原型链的终点。

补充一点:一般清除变量或方法,都是用的赋值为null,js内存回收机制就会将其回收掉。

10.一个页面从输入 URL 到页面加载显示完成,这个过程中都发生了什么?(这道题特别常问)

分为4个步骤:
    (1)当发送一个URL请求时,不管这个URL是Web页面的URL还是Web页面上每个资源的URL,浏览器都会开启一个线程来处理这个请求同时在远程DNS服务器上启动一个DNS查询这能使浏览器获得请求对应的IP地址。
    (2)浏览器与远程Web服务器通过TCP三次握手协商来建立一个TCP/IP连接。该握手包括一个同步报文,一个同步-应答报文和一个应答报文,这三个报文在 浏览器和服务器之间传递。该握手首先由客户端尝试建立起通信,而后服务器应答并接受客户端的请求,最后由客户端发出该请求已经被接受的报文。
    (3)一旦TCP/IP连接建立,浏览器会通过该连接向远程服务器发送HTTP的GET请求。远程服务器找到资源并使用HTTP响应返回该资源,值为200的HTTP响应状态表示一个正确的响应。
    (4)此时,Web服务器提供资源服务,客户端开始下载资源。
请求返回后,便进入了我们关注的前端模块

11.ajax实现过程

(1)创建XMLHttpRequest对象,也就是创建一个异步调用对象.

(2)创建一个新的HTTP请求,并指定该HTTP请求的方法、URL及验证信息.

(3)设置响应HTTP请求状态变化的函数.

(4)发送HTTP请求.

(5)获取异步调用返回的数据.

(6)使用JavaScript和DOM实现局部刷新.

//补充一个特别生动形象好记的方法

将ajax的实现过程比喻为打电话
(1)首先得有一部电话吧 : 创建ajax对象
(2)拨通对方号码: 连接到服务器
(3)说你要说的内容 : 发送请求(告诉服务器你要什么)
(4)听对方的反馈 : 接收对方的响应

//具体的代码实现

function ajax ( url , fnSucc ,fnFailed )
{
     //创建ajax对象
    var oAjax = window.XMLHTTPRequest ? new XMLHTTPRequest() : new ActiveXObject("Microsoft.XMLHTTP");  
    //连接到服务器
   oAjax.open("请求的类型" , "请求的内容", true); //最后一个为是否为异步
   //发送请求
   oAjax.send();      
   //接收响应
    oAjax.onreaystatechange = function () {
       if ( oAjax.readyState == 4)
        {
             if ( oAjax.status == 200 )
              {
                      fnSucc();
                }
             else
                   {
                        fnFailed();
                   }
        }
    }
}
                                                 

//readyState的5种值

0 : (未初始化)还没有调用open()方法
1 : (载入)已调用send()方法,正在发送请求
2 : (载入完成)send()方法完成,已收到全部响应内容
3 : (解析)正在解析响应内容
4 :  (完成)响应内容解析完成(不代表成功,成不成功还要看status的值),可以在客户端调用了

//status的值解析

1xx表示临时响应
100   (继续) 请求者应当继续提出请求。 服务器返回此代码表示已收到请求的第一部分,正在等待其余部分。 
101   (切换协议) 请求者已要求服务器切换协议,服务器已确认并准备切换。
2xx表示成功
200   (成功)  服务器已成功处理了请求。 通常,这表示服务器提供了请求的网页。
201   (已创建)  请求成功并且服务器创建了新的资源。
202   (已接受)  服务器已接受请求,但尚未处理。
203   (非授权信息)  服务器已成功处理了请求,但返回的信息可能来自另一来源。
204   (无内容)  服务器成功处理了请求,但没有返回任何内容。
205   (重置内容) 服务器成功处理了请求,但没有返回任何内容。
206   (部分内容)  服务器成功处理了部分 GET 请求。
3xx重定向
300   (多种选择)  针对请求,服务器可执行多种操作。 服务器可根据请求者 (user agent) 选择一项操作,或提供操作列表供请求者选择。
301   (永久移动)  请求的网页已永久移动到新位置。 服务器返回此响应(对 GET 或 HEAD 请求的响应)时,会自动将请求者转到新位置。
302   (临时移动)  服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。
303   (查看其他位置) 请求者应当对不同的位置使用单独的 GET 请求来检索响应时,服务器返回此代码。
304   (未修改) 自从上次请求后,请求的网页未修改过。 服务器返回此响应时,不会返回网页内容。
305   (使用代理) 请求者只能使用代理访问请求的网页。 如果服务器返回此响应,还表示请求者应使用代理。
306   在最新版的规范中,306状态码已经不再被使用。
307 (临时重定向) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。 http状态返回代码 4xx(请求错误) 这些状态代码表示请求可能出错,妨碍了服务器的处理。 4xx客户端错误 400 (错误请求) 服务器不理解请求的语法。 401 (未授权) 请求要求身份验证。 对于需要登录的网页,服务器可能返回此响应。 403 (禁止) 服务器拒绝请求。(刚才腾讯面试的时候问到了。。。没答出来) 404 (未找到) 服务器找不到请求的网页。 405 (方法禁用) 禁用请求中指定的方法。 406 (不接受) 无法使用请求的内容特性响应请求的网页。 407 (需要代理授权) 此状态代码与 401(未授权)类似,但指定请求者应当授权使用代理。 408 (请求超时) 服务器等候请求时发生超时。 409 (冲突) 服务器在完成请求时发生冲突。 服务器必须在响应中包含有关冲突的信息。 410 (已删除) 如果请求的资源已永久删除,服务器就会返回此响应。 411 (需要有效长度) 服务器不接受不含有效内容长度标头字段的请求。 412 (未满足前提条件) 服务器未满足请求者在请求中设置的其中一个前提条件。 413 (请求实体过大) 服务器无法处理请求,因为请求实体过大,超出服务器的处理能力。 414 (请求的 URI 过长) 请求的 URI(通常为网址)过长,服务器无法处理。 415 (不支持的媒体类型) 请求的格式不受请求页面的支持。 416 (请求范围不符合要求) 如果页面无法提供请求的范围,则服务器会返回此状态代码。 417 (未满足期望值) 服务器未满足"期望"请求标头字段的要求。 5xx服务器端错误 500 (服务器内部错误) 服务器遇到错误,无法完成请求。 501 (尚未实施) 服务器不具备完成请求的功能。 例如,服务器无法识别请求方法时可能会返回此代码。 502 (错误网关) 服务器作为网关或代理,从上游服务器收到无效响应。 503 (服务不可用) 服务器目前无法使用(由于超载或停机维护)。 通常,这只是暂时状态504 (网关超时) 服务器作为网关或代理,但是没有及时从上游服务器收到请求。 505 (HTTP 版本不受支持) 服务器不支持请求中所用的 HTTP 协议版本。

12. new 一个对象的时候,都干了些什么?

1、创建一个空对象,并且 this 变量引用该对象,同时还继承了该函数的原型。
2、属性和方法被加入到 this 引用的对象中。
3、新创建的对象由 this 所引用,并且最后隐式的返回 thisvar obj  = {};
obj.__proto__ = Base.prototype;
Base.call(obj); 

13.documen.write和 innerHTML的区别

document.write只能重绘整个页面

innerHTML可以重绘页面的一部分

14.哪些操作会造成内存泄漏?

内存泄漏指任何对象在您不再拥有或需要它之后仍然存在。
垃圾回收器定期扫描对象,并计算引用了每个对象的其他对象的数量。如果一个对象的引用数量为 0(没有其他对象引用过该对象),或对该对象的惟一引用是循环的,那么该对象的内存即可回收。

setTimeout 的第一个参数使用字符非串而函数的话,会引发内存泄漏。
闭包、控制台日志、循环(在两个对象彼此引用且彼此保留时,就会产生一个循环)

15.doctype?

Doctype作用? 严格模式与混杂模式如何区分?它们有何意义?1)<!DOCTYPE> 声明位于文档中的最前面,处于 <html> 标签之前。告知浏览器以何种模式来渲染文档。2)严格模式的排版和 JS 运作模式是  以该浏览器支持的最高标准运行。3)在混杂模式中,页面以宽松的向后兼容的方式显示。模拟老式浏览器的行为以防止站点无法工作。4DOCTYPE不存在或格式不正确会导致文档以混杂模式呈现。   
你知道多少种Doctype文档类型? 该标签可声明三种 DTD 类型,分别表示严格版本、过渡版本以及基于框架的 HTML 文档。 HTML
4.01 规定了三种文档类型:Strict、Transitional 以及 Frameset。 XHTML 1.0 规定了三种 XML 文档类型:Strict、Transitional 以及 Frameset。 Standards (标准)模式(也就是严格呈现模式)用于呈现遵循最新标准的网页,而 Quirks (包容)模式(也就是松散呈现模式或者兼容模式)用于呈现为传统浏览器而设计的网页。

16.cookie

cookie虽然在持久保存客户端数据提供了方便,分担了服务器存储的负担,但还是有很多局限性的。
第一:每个特定的域名下最多生成20个cookie

1.IE6或更低版本最多20个cookie
2.IE7和之后的版本最后可以有50个cookie。
3.Firefox最多50个cookie
4.chrome和Safari没有做硬性限制
IE和Opera 会清理近期最少使用的cookie,Firefox会随机清理cookie。

cookie的最大大约为4096字节,为了兼容性,一般不能超过4095字节。

IE 提供了一种存储可以持久化用户数据,叫做userData,从IE5.0就开始支持。每个数据最多128K,每个域名下最多1M。这个持久化数据放在缓存中,如果缓存没有清理,那么会一直存在。

优点:极高的扩展性和可用性
1.通过良好的编程,控制保存在cookie中的session对象的大小。
2.通过加密和安全传输技术(SSL),减少cookie被破解的可能性。
3.只在cookie中存放不敏感数据,即使被盗也不会有重大损失。
4.控制cookie的生命期,使之不会永远有效。偷盗者很可能拿到一个过期的cookie。
缺点:
1.`Cookie`数量和长度的限制。每个domain最多只能有20条cookie,每个cookie长度不能超过4KB,否则会被截掉。 2.安全性问题。如果cookie被人拦截了,那人就可以取得所有的session信息。即使加密也与事无补,因为拦截者并不需要知道cookie的意义,他只要原样转发cookie就可以达到目的了。 3.有些状态不可能保存在客户端。例如,为了防止重复提交表单,我们需要在服务器端保存一个计数器。如果我们把这个计数器保存在客户端,那么它起不到任何作用。

17.浏览器本地存储

在较高版本的浏览器中,js提供了sessionStorage和globalStorage。在HTML5中提供了localStorage来取代globalStorage。
html5中的Web Storage包括了两种存储方式:sessionStorage和localStorage。
sessionStorage用于本地存储一个会话(session)中的数据,这些数据只有在同一个会话中的页面才能访问并且当会话结束后数据也随之销毁。因此sessionStorage不是一种持久化的本地存储,仅仅是会话级别的存储。
而localStorage用于持久化的本地存储,除非主动删除数据,否则数据是永远不会过期的。

//cookie

Cookie: 在web中得到广泛应用,但局限性非常明显,容量太小,有些站点会因为出于安全的考虑而禁用cookie,cookie没有想象中的那么安全,Cookie 的内容会随着页面请求一并发往服务器。

//user Data

User Data: 是微软为IE专门在系统中开辟的一块存储空间,所以说只支持Windows+IE的组合,实际测试在2000(IE5.5)、XP(IE6、IE7),Vista(IE7)下都是可以正常使用的。在XP下,一般位于C:Documents and Settings用户名UserData,有些时候会在C:Documents and Settings用户名Application DataMicrosoftInternet ExplorerUserData。在Vista下,位于C:Users用户名AppDataRoamingMicrosoftInternet ExplorerUserData;单个文件的大小限制是128KB,一个域名下总共可以保存1024KB的文件,文件个数应该没有限制。在受限站点里这两个值分别是64KB和640KB,所以如果考虑到各种情况的话,单个文件最好能控制64KB以下。

//补充一下localStorage

相对于上述本地存储方案,localStorage有自身的优点:容量大、易用、强大、原生支持;缺点是兼容性差些(chrome,  safari, firefox,IE 9,IE8都支持 localStorage,主要是IE8以下版本不支持)、安全性也差些(所以请勿使用localStorage保存敏感信息)。
  • Google Gears: Google的离线方案,已经停止更新,官方推荐使用html5的localStorage方案。(HTML5不可逆转的趋势呀!)

18.web storage和cookie的区别

Web Storage的概念和cookie相似,区别是它是为了更大容量存储设计的。Cookie的大小是受限的,并且每次你请求一个新的页面的时候Cookie都会被发送过去,这样无形中浪费了带宽,另外cookie还需要指定作用域,不可以跨域调用。

除此之外,Web Storage拥有setItem,getItem,removeItem,clear等方法,不像cookie需要前端开发者自己封装setCookie,getCookie。

但是Cookie也是不可以或缺的:Cookie的作用是与服务器进行交互,作为HTTP规范的一部分而存在 ,而Web Storage仅仅是为了在本地“存储”数据而生

浏览器的支持除了IE7及以下不支持外,其他标准浏览器都完全支持(ie及FF需在web服务器里运行),值得一提的是IE总是办好事,例如IE7、IE6中的UserData其实就是javascript本地存储的解决方案。通过简单的代码封装可以统一到所有的浏览器都支持web storage。

localStorage和sessionStorage都具有相同的操作方法,例如setItem、getItem和removeItem等

 19.一些javascript的书写规范

1.不要在同一行声明多个变量。
2.请使用 ===/!== 来比较true/false或者数值 (好吧,这一条我老是用== 和 != 去比较,但是=== 是要求类型和值都要完全相等的全等,要求很严格,一般我比较str和number都会现将其类型强制转换为int)
3.使用对象字面量替代new Array这种形式 
4.不要使用全局函数。 5.Switch语句必须带有default分支 6.函数不应该有时候有返回值,有时候没有返回值。 7.For循环必须使用大括号 8.If语句必须使用大括号 9.for-in循环中的变量 应该使用var关键字明确限定作用域,从而避免作用域污染。
//这里补充一个什么是对象字面量:
形式是:{键:值,键:值} 
语法中的“健/值”会成为对象的静态成员。
如果给某个“健”指定的值是一个匿名函数,那么该函数就会变成对象的静态方法;否则就是对象的一个静态属性。
这种语法结构与JSON语法相似。只要记住对象字面量语法会自动创建Object对象实例即可,也就是不能使用new关键字对其再次进行实例化。

//在这里更加加上一条连接,来自汤姆大叔的博客《编写高质量JavaScript代码的基本要点

http://www.cnblogs.com/TomXu/archive/2011/12/28/2286877.html

20.eval是做什么的?

它的功能是把对应的字符串解析成JS代码并运行;
应该避免使用eval,不安全,非常耗性能(2次,一次解析成js语句,一次执行)。

//补充一点知识

var json = eval('(' + str + ')');
 ()是一个 分组运算符. 作用是优先级. 本质就是舍弃其他可能的多余的语法树.

之所以要这样做的原因是 {} 花括号二义性造成的. 
eval('{a:1}')     //不会抛出异常.  结果是1
eval('{a:1,b:2}')  //抛出异常 : Uncaught SyntaxError: Unexpected token :

对比:
eval('({a:1})'); //Object {a:1}
eval('({a:1,b:2})'); //Object{a:1,b:2}
这并不是eval的错. 错误来自语法分析时, {}被当做 statement block(语句块),而不是一个 JSONObject(Json对象). 所以.抛出异常是因为a:1被解析成 lableStatement(标签声明) 了.那么它后面的 "," 逗号,就使得parser不得不停下来了.因为 逗号运算符不能出现在lableStatement后面. 所以 { a:1, b:2 } 在任何被解析为statement block的情况下.都将导致异常. 解决办法.把他们并入表达式.让parser使用 JSONObject的语法树.比如 ({a:1,b:2}) 1,{a:1,b:2} +{a:1,b:2} var a ={a:1,b:2} 等等等等... 说说为什么()不是强制运算符,因为它不具备这个功能. 分组运算符 同 delete typeof 等运算符类似. 不会对运算元.造成 GetValue() . 举个例子: delete 玩笑; //不会抛出异常. 原因是运行时,执行到 delete 玩笑; 时, 并不会对标识符-玩笑,进行GetValue(). delete (玩笑);//同样不会抛出异常. 可见分组运算符() 并没有对 标识符 -玩笑 做额外的工作. 它仅仅是影响语法树的产生过程. 从ECMA262的角度来看此问题亦如此. 这里涉及到 Reference Type 的base property 为null时的情况下,对其 GetValue()才抛出异常.

21.Js异步加载的方式有哪些?

(1) defer,只支持IE

(2) async:

(3) 创建script,插入到DOM中,加载完毕后callBack

//补充一些,感觉这个蛮重要的,摘自:http://blog.csdn.net/m13666368773/article/details/7586106

1. 同步加载
我们平时最常使用的就是这种同步加载形式:
<script src="http://yourdomain.com/script.js"></script> 
同步模式,又称阻塞模式,会阻止浏览器的后续处理,停止了后续的解析,因此停止了后续的文件加载(如图像)、渲染、代码执行。
 js 之所以要同步执行,是因为 js 中可能有输出 document 内容、修改dom、重定向等行为,所以默认同步执行才是安全的。
以前的一般建议是把<script>放在页面末尾</body>之前,这样尽可能减少这种阻塞行为,而先让页面展示出来。
简单说:加载的网络 timeline 是瀑布模型,而异步加载的 timeline 是并发模型。
2. 常见异步加载(Script DOM Element)
(function() {
     var s = document.createElement('script');
     s.type = 'text/javascript';
     s.async = true;
     s.src = 'http://yourdomain.com/script.js';
     var x = document.getElementsByTagName('script')[0];
     x.parentNode.insertBefore(s, x);
 })();
但是,这种加载方式在加载执行完之前会阻止 onload 事件的触发,而现在很多页面的代码都在 onload 时还要执行额外的渲染工作等,所以还是会阻塞部分页面的初始化处理。
3. onload 时的异步加载
(function() {
     function async_load(){
         var s = document.createElement('script');
         s.type = 'text/javascript';
         s.async = true;
         s.src = 'http://yourdomain.com/script.js';
         var x = document.getElementsByTagName('script')[0];
         x.parentNode.insertBefore(s, x);
     }
     if (window.attachEvent)
         window.attachEvent('onload', async_load);
     else
         window.addEventListener('load', async_load, false);
 })();
这和前面的方式差不多,但关键是它不是立即开始异步加载 js ,而是在 onload 时才开始异步加载。这样就解决了阻塞 onload 事件触发的问题。
补充:DOMContentLoaded 与 OnLoad 事件
DOMContentLoaded : 页面(document)已经解析完成,页面中的dom元素已经可用。但是页面中引用的图片、subframe可能还没有加载完。
OnLoad:页面的所有资源都加载完毕(包括图片)。浏览器的载入进度在这时才停止。
这两个时间点将页面加载的timeline分成了三个阶段。
4.其他异步方式
由于Javascript的动态特性,还有很多异步加载方法:
  • XHR Eval 
  • XHR Injection
  • Script in Iframe
  • Script Defer
  • document.write Script Tag
  • 还有一种方法是用 setTimeout 延迟0秒 与 其它方法组合。
XHR Eval 通过 ajax 获取js的内容,然后 eval 执行。
var xhrObj = getXHRObject(); 
 xhrObj.onreadystatechange =  
   function() {  
     if ( xhrObj.readyState != 4 ) return; 
     eval(xhrObj.responseText); 
   }; 
 xhrObj.open('GET', 'A.js', true); 
 xhrObj.send('');
 
Script in Iframe:创建并插入一个iframe元素,让其异步执行 js
var iframe = document.createElement('iframe'); 
 document.body.appendChild(iframe); 
 var doc = iframe.contentWindow.document; 
 doc.open().write('<body onload="insertJS()">'); 
 doc.close();
 
GMail Mobile:页内 js 的内容被注释,所以不会执行,然后在需要的时候,获取script元素中 text 内容,去掉注释后 eval 执行。
<script type="text/javascript"> 
 /* 
 var ...  
 */ 
 </script>

二、async 和 defer 属性
1. defer 属性
<script src="file.js" defer></script> 
defer属性声明这个脚本中将不会有 document.write 或 dom 修改。
浏览器将会并行下载 file.js 和其它有 defer 属性的script,而不会阻塞页面后续处理。
 
defer属性在IE 4.0中就实现了,超过13年了!Firefox 从 3.5 开始支持defer属性 。(注:W3C上写只有 Internet Explorer 支持 defer 属性。)
注:所有的defer 脚本保证是按顺序依次执行
最后请注意两点:
1、不要在defer型的脚本程序段中调用document.write命令,因为document.write将产生直接输出效果。
2、而且,不要在defer型脚本程序段中包括任何立即执行脚本要使用的全局变量或者函数。
 
2. async 属性
<script src="file.js" async></script> 
async属性是HTML5新增的。作用和defer类似,但是它将在下载后尽快执行,不能保证脚本会按顺序执行它们将在onload 事件之前完成。
Firefox 3.6、Opera 10.5、IE 9 和 最新的Chrome 和 Safari 都支持 async 属性。可以同时使用 async 和 defer,这样IE 4之后的所有 IE 都支持异步加载。
关于defer和async的区别:(引一段话)
Both async and defer scripts begin to download immediately without pausing the parser and both support an optional onload handler to address the common need to perform initialization which depends on the script. The difference between async and defer centers around when the script is executed. Each async script executes at the first opportunity after it is finished downloading and before the window’s load event. This means it’s possible (and likely) thatasync scripts are not executed in the order in which they occur in the page. The defer scripts, on the other hand, are guaranteed to be executed in the order they occur in the page. That execution starts after parsing is completely finished, but before the document’sDOMContentLoaded event.

注:其实翻译过来指的就是async和defer最大的区别在于下载完脚本以后什么时候执行。每个async(异步)脚本都是在下载完后尽快执行,所以不能保证脚本会按顺序执行。而defer脚本(延迟脚本)则保证按照顺序执行的。

另 :
<script> 标签在 HTML 4.01 与 HTML5 的区别:
  • type 属性在HTML 4中是必须的,在HTML5中是可选的。
  • async 属性是HTML5中新增的。
  • 个别属性(xml:space)在HTML5中不支持。
说明:
没有 async 属性,script 将立即获取(下载)并执行,然后才继续后面的处理,这期间阻塞了浏览器的后续处理。
如果有 async 属性,那么 script 将被异步下载并执行,同时浏览器继续后续的处理。
HTML4中就有了defer属性,它提示浏览器这个 script 不会产生任何文档元素(没有document.write),因此浏览器会继续后续处理和渲染。
如果没有 async 属性 但是有 defer 属性,那么script 将在页面parse之后执行。
如果同时设置了二者,那么 defer 属性主要是为了让不支持 async 属性的老浏览器按照原来的 defer 方式处理,而不是同步方式。

作者补充:(链接地址)http://blog.csdn.net/m13666368773/article/details/7586106

既然 HTML5 中已经支持异步加载,为什么还要使用前面推荐的那种麻烦(动态创建 script 元素)的方式?
答:为了兼容尚不支持 async 老浏览器。如果将来所有浏览器都支持了,那么直接在script中加上async 属性是最简单的方式。

六、异步加载的问题

在异步加载的时候,无法使用 document.write 输出文档内容。
在同步模式下,document.write 是在当前 script 所在的位置输 出文档的。而在异步模式下,浏览器继续处理后续页面内容,根本无法确定 document.write 应该输出到什么位置,所以异步模式下 document.write 不可行。而到了页面已经 onload 之后,再执行 document.write 将导致当前页面的内容被清空,因为它会自动触发 document.open 方法。
实际上document.write的名声并不好,最好少用。
 
替代方法:
1. 虽然异步加载不能用 document.write,但还是可以onload之后执行操作dom(创建dom或修改dom)的,这样可以实现一些自己的动态输出。比如要在页面异步创建一个浮动元素,这和它在页面中的位置就没关系了,只要创建出该dom元素添加到 document 中即可。
2. 如果需要在固定位置异步生成元素的内容,那么可以在该固定位置设置一个dom元素作为目标,这样就知道位置了,异步加载之后就可以对这个元素进行修改。

 22.延迟加载

延迟加载:有些 js 代码并不是页面初始化的时候就立刻需要的,而稍后的某些情况才需要的。延迟加载就是一开始并不加载这些暂时不用的js,而是在需要的时候或稍后再通过js 的控制来异步加载。
也就是将 js 切分成许多模块,页面初始化时只加载需要立即执行的 js ,然后其它 js 的加载延迟到第一次需要用到的时候再加载。
特别是页面有大量不同的模块组成,很多可能暂时不用或根本就没用到。
就像图片的延迟加载,在图片出现在可视区域内时(在滚动条下拉)才加载显示图片。

23.script标签使用的历史

1. script 放在 HEAD 中
<head>
  <script src=“…”></script>
  </head>
 
阻止了后续的下载;
在IE 6-7 中 script 是顺序下载的,而不是现在的 “并行下载、顺序执行” 的方式;
在下载和解析执行阶段阻止渲染(rendering);
2. script 放在页面底部(2007
... 
 <script src=“…”></script> 
 </body>
 
不阻止其它下载;
在IE 6-7 中 script 是顺序下载的;
在下载和解析执行阶段阻止渲染(rendering);
3. 异步加载script(2009var se = document.createElement ('script'); se.src = 'http://anydomain.com/A.js'; document.getElementsByTagName('head') [0].appendChild(se); 不阻止其它下载; 在所有浏览器中,script都是并行下载; 只在解析执行阶段阻止渲染(rendering);

4. 异步下载 + 按需执行 (2010) var se = new Image(); se.onload = registerScript(); se.src = 'http://anydomain.com/A.js'; 把下载 js 与 解析执行 js 分离出来 不阻止其它下载; 在所有浏览器中,script都是并行下载; 不阻止渲染(rendering)直到真正需要时;

 24.遇到的问题

pushState()方法

pushState()有三个参数:一个状态对象、一个标题(现在会被忽略),一个可选的URL地址。下面来单独考察这三个参数的细节:

状态对象(state object) — 一个JavaScript对象,与用pushState()方法创建的新历史记录条目关联。无论何时用户导航到新创建的状态,popstate事件都会被触发,并且事件对象的state属性都包含历史记录条目的状态对象的拷贝。

任何可序列化的对象都可以被当做状态对象。因为FireFox浏览器会把状态对象保存到用户的硬盘,这样它们就能在用户重启浏览器之后被还原,我们强行限制状态对象的大小为640k。如果你向pushState()方法传递了一个超过该限额的状态对象,该方法会抛出异常。如果你需要存储很大的数据,建议使用sessionStorage或localStorage。

标题(title) — FireFox浏览器目前会忽略该参数,虽然以后可能会用上。考虑到未来可能会对该方法进行修改,传一个空字符串会比较安全。或者,你也可以传入一个简短的标题,标明将要进入的状态。

地址(URL) — 新的历史记录条目的地址。浏览器不会在调用pushState()方法后加载该地址,但之后,可能会试图加载,例如用户重启浏览器。新的URL不一定是绝对路径;如果是相对路径,它将以当前URL为基准;传入的URL与当前URL应该是同源的,否则,pushState()会抛出异常。该参数是可选的;不指定的话则为文档当前URL。

注意: 在 Gecko 2.0 (Firefox 4 / Thunderbird 3.3 / SeaMonkey 2.1) 至 Gecko 5.0 (Firefox 5.0 / Thunderbird 5.0 / SeaMonkey 2.2) 中,传入的对象使用JSON来进行序列化。从 Gecko 6.0 (Firefox 6.0 / Thunderbird 6.0 / SeaMonkey 2.3)开始,对象使用结构化拷贝算法来进行序列化。这将允许更多类型的对象能够安全传入。
某种意义上,调用pushState()有点类似于设置window.location
='#foo',它们都会在当前文档内创建和激活新的历史记录条目。但pushState()有自己的优势:
新的URL可以是任意的同源URL,与此相反,使用window.location方法时,只有仅修改 hash 才能保证停留在相同的document中。 根据个人需要来决定是否修改URL。相反,设置window.location
='#foo',只有在当前hash值不是foo时才创建一条新历史记录。 你可以在新的历史记录条目中添加抽象数据。如果使用基于hash的方法,你只能把相关数据转码成一个很短的字符串。 注意pushState()方法永远不会触发hashchange事件,即便新的地址只变更了hash。 replaceState()方法 history.replaceState()操作类似于history.pushState(),不同之处在于replaceState()方法会修改当前历史记录条目而并非创建新的条目。 当你为了响应用户的某些操作,而要更新当前历史记录条目的状态对象或URL时,使用replaceState()方法会特别合适。

25.window.location对象

URL:http://b.a.com:88/index.php?name=kang&when=2011#first
           
protocol:    协议    "http:"
hostname:    服务器的名字    "b.a.com"
port:    端口    "88"
pathname:    URL中主机名后的部分    "/index.php"
search:    "?"后的部分,又称为查询字符串    "?name=kang&when=2011"
hash:    返回"#"之后的内容    "#first"
host:    等于hostname + port    "b.a.com:88"
href:    当前页面的完整URL    "http://www.a.com:88/index.php?name=kang&when=2011#first"

26.js的同源策略

概念:同源策略是客户端脚本(尤其是Javascript)的重要的安全度量标准。它最早出自Netscape Navigator2.0,其目的是防止某个文档或脚本从多个不同源装载。

这里的同源策略指的是:协议,域名,端口相同,同源策略是一种安全协议指一段脚本只能读取来自同一来源的窗口和文档的属性。

为什么要有同源限制?

我们举例说明:比如一个黑客程序,他利用Iframe把真正的银行登录页面嵌到他的页面上,当你使用真实的用户名,密码登录时,他的页面就可以通过Javascript读取到你的表单中input中的内容,这样用户名,密码就轻松到手了。

那么接下来的问题就是跨域问题啦??
答案:http://www.cnblogs.com/shixiaomiao/p/4758434.html

27.GET和POST的区别,何时使用POST?

GET:一般用于信息获取,使用URL传递参数,对所发送信息的数量也有限制,一般在2000个字符
POST:一般用于修改服务器上的资源,对所发送的信息没有限制。
    
    GET方式需要使用Request.QueryString来取得变量的值,而POST方式通过Request.Form来获取变量的值,
    也就是说Get是通过地址栏来传值,而Post是通过提交表单来传值。

然而,在以下情况中,请使用 POST 请求:
无法使用缓存文件(更新服务器上的文件或数据库)
向服务器发送大量数据(POST 没有数据量限制)
发送包含未知字符的用户输入时,POST 比 GET 更稳定也更可靠

总结:
GET: 容量小,安全性差(通过网址传递),有缓存
POST : 容量大(2G),安全性较好点,没有缓存

//补充,ajax的type有几种

默认值: "GET")。请求方式 ("POST" 或 "GET"), 默认为 "GET"。注意:其它 HTTP 请求方法,如 PUT 和 DELETE 也可以使用,但仅部分浏览器支持。
其实这四种方式对应的就是: 数据库操作的 增(PUT),删(DELETE),改(POST),查(GET)

//反正都写了,那就把jquery中的ajax参数都列一下

参数
options
类型:Object
可选。AJAX 请求设置。所有选项都是可选的。
async
类型:Boolean
默认值: true。默认设置下,所有请求均为异步请求。如果需要发送同步请求,请将此选项设置为 false。
注意,同步请求将锁住浏览器,用户其它操作必须等待请求完成才可以执行。
beforeSend(XHR) 类型:Function 发送请求前可修改 XMLHttpRequest 对象的函数,如添加自定义 HTTP 头。
XMLHttpRequest 对象是唯一的参数。 这是一个 Ajax 事件。如果返回
false 可以取消本次 ajax 请求。
cache 类型:Boolean 默认值:
truedataType 为 script 和 jsonp 时默认为 false。设置为 false 将不缓存此页面。 jQuery 1.2 新功能。
complete(XHR, TS) 类型:Function 请求完成后回调函数 (请求成功或失败之后均调用)。 参数: XMLHttpRequest 对象和一个描述请求类型的字符串。 这是一个 Ajax 事件。
contentType 类型:String 默认值:
"application/x-www-form-urlencoded"。发送信息至服务器时内容编码类型。 默认值适合大多数情况。如果你明确地传递了一个 content-type 给 $.ajax() 那么它必定会发送给服务器(即使没有数据要发送)。
context 类型:Object 这个对象用于设置 Ajax 相关回调函数的上下文。也就是说,让回调函数内
this 指向这个对象(如果不设定这个参数,那么 this 就指向调用本次 AJAX 请求时传递的 options 参数)。比如指定一个 DOM 元素作为 context 参数,这样就设置了 success 回调函数的上下文为这个 DOM 元素。 就像这样: $.ajax({ url: "test.html", context: document.body, success: function(){ $(this).addClass("done"); }});
data 类型:String 发送到服务器的数据。将自动转换为请求字符串格式。
GET 请求中将附加在 URL 后。查看 processData 选项说明以禁止此自动转换。
必须为 Key
/Value 格式。
如果为数组,jQuery 将自动为不同值对应同一个名称。
如 {foo:["bar1", "bar2"]} 转换为 '&foo=bar1&foo=bar2'。
dataFilter 类型:Function 给 Ajax 返回的原始数据的进行预处理的函数。提供 data 和 type 两个参数:data 是 Ajax 返回的原始数据,type 是调用 jQuery.ajax 时提供的 dataType 参数。函数返回的值将由 jQuery 进一步处理。
dataType 类型:String 预期服务器返回的数据类型。如果不指定,jQuery 将自动根据 HTTP 包 MIME 信息来智能判断,比如 XML MIME 类型就被识别为 XML。在
1.4 中,JSON 就会生成一个 JavaScript 对象,而 script 则会执行这个脚本。
随后服务器端返回的数据会根据这个值解析后,传递给回调函数。
可用值:
"xml": 返回 XML 文档,可用 jQuery 处理。 "html": 返回纯文本 HTML 信息;包含的 script 标签会在插入 dom 时执行。 "script": 返回纯文本 JavaScript 代码。不会自动缓存结果。除非设置了 "cache" 参数。注意:在远程请求时(不在同一个域下),所有 POST 请求都将转为 GET 请求。(因为将使用 DOM 的 script标签来加载) "json": 返回 JSON 数据 。 "jsonp": JSONP 格式。使用 JSONP 形式调用函数时,如 "myurl?callback=?" jQuery 将自动替换 ? 为正确的函数名,以执行回调函数"text": 返回纯文本字符串
error 类型:Function 默认值: 自动判断 (xml 或 html)。请求失败时调用此函数。 有以下三个参数:XMLHttpRequest 对象、错误信息、(可选)捕获的异常对象。 如果发生了错误,错误信息(第二个参数)除了得到
null 之外,还可能是 "timeout", "error", "notmodified" 和 "parsererror"。 这是一个 Ajax 事件。
global 类型:Boolean 是否触发全局 AJAX 事件。默认值:
true。设置为 false 将不会触发全局 AJAX 事件,如 ajaxStart 或 ajaxStop 可用于控制不同的 Ajax 事件。
ifModified 类型:Boolean 仅在服务器数据改变时获取新数据。默认值:
false。使用 HTTP 包 Last-Modified 头信息判断。在 jQuery 1.4 中,它也会检查服务器指定的 'etag' 来确定数据没有被修改过。
jsonp 类型:String 在一个 jsonp 请求中重写回调函数的名字。这个值用来替代在
"callback=?" 这种 GET 或 POST 请求中 URL 参数里的 "callback" 部分,比如 {jsonp:'onJsonPLoad'} 会导致将 "onJsonPLoad=?" 传给服务器。
jsonpCallback 类型:String 为 jsonp 请求指定一个回调函数名。这个值将用来取代 jQuery 自动生成的随机函数名。这主要用来让 jQuery 生成度独特的函数名,这样管理请求更容易,也能方便地提供回调函数和错误处理。你也可以在想让浏览器缓存 GET 请求的时候,指定这个回调函数名。
password 类型:String 用于响应 HTTP 访问认证请求的密码
processData 类型:Boolean 默认值:
true。默认情况下,通过data选项传递进来的数据,如果是一个对象(技术上讲只要不是字符串),都会处理转化成一个查询字符串,以配合默认内容类型 "application/x-www-form-urlencoded"。如果要发送 DOM 树信息或其它不希望转换的信息,请设置为 false
scriptCharset 类型:String 只有当请求时 dataType 为
"jsonp" 或 "script",并且 type 是 "GET" 才会用于强制修改 charset。通常只在本地和远程的内容编码不同时使用。
success 类型:Function 请求成功后的回调函数。 参数:由服务器返回,并根据 dataType 参数进行处理后的数据;描述状态的字符串。 这是一个 Ajax 事件。
traditional 类型:Boolean 如果你想要用传统的方式来序列化数据,那么就设置为
true。请参考工具分类下面的 jQuery.param 方法。
timeout 类型:Number 设置请求超时时间(毫秒)。此设置将覆盖全局设置。
type 类型:String 默认值:
"GET")。请求方式 ("POST" 或 "GET"), 默认为 "GET"。注意:其它 HTTP 请求方法,如 PUT 和 DELETE 也可以使用,但仅部分浏览器支持。
url 类型:String 默认值: 当前页地址。发送请求的地址。
username 类型:String 用于响应 HTTP 访问认证请求的用户名。
xhr 类型:Function 需要返回一个 XMLHttpRequest 对象。默认在 IE 下是 ActiveXObject 而其他情况下是 XMLHttpRequest 。用于重写或者提供一个增强的 XMLHttpRequest 对象。这个参数在 jQuery
1.3 以前不可用。
回调函数 如果要处理 $.ajax() 得到的数据,则需要使用回调函数:beforeSend、error、dataFilter、success、complete。
beforeSend 在发送请求之前调用,并且传入一个 XMLHttpRequest 作为参数。
error 在请求出错时调用。传入 XMLHttpRequest 对象,描述错误类型的字符串以及一个异常对象(如果有的话)
dataFilter 在请求成功之后调用。传入返回的数据以及
"dataType" 参数的值。并且必须返回新的数据(可能是处理过的)传递给 success 回调函数。
success 当请求之后调用。传入返回后的数据,以及包含成功代码的字符串。
complete 当请求完成之后调用这个函数,无论成功或失败。传入 XMLHttpRequest 对象,以及一个包含成功或错误代码的字符串。

28.哪些地方会出现css阻塞,哪些地方会出现js阻塞?

js的阻塞特性:所有浏览器在下载JS的时候,会阻止一切其他活动,比如其他资源的下载,内容的呈现等等。直到JS下载、解析、执行完毕后才开始继续并行下载其他资源并呈现内容。
为了提高用户体验,新一代浏览器都支持并行下载JS,但是JS下载仍然会阻塞其它资源的下载(例如.图片,css文件等)。 由于浏览器为了防止出现JS修改DOM树,需要重新构建DOM树的情况,所以就会阻塞其他的下载和呈现。 嵌入JS会阻塞所有内容的呈现,而外部JS只会阻塞其后内容的显示,2种方式都会阻塞其后资源的下载。也就是说外部样式不会阻塞外部脚本的加载,但会阻塞外部脚本的执行。 CSS怎么会阻塞加载了?CSS本来是可以并行下载的,在什么情况下会出现阻塞加载了(在测试观察中,IE6下CSS都是阻塞加载) 当CSS后面跟着嵌入的JS的时候,该CSS就会出现阻塞后面资源下载的情况。而当把嵌入JS放到CSS前面,就不会出现阻塞的情况了。 根本原因:因为浏览器会维持html中css和js的顺序,样式表必须在嵌入的JS执行前先加载、解析完。而嵌入的JS会阻塞后面的资源加载,所以就会出现上面CSS阻塞下载的情况。

29.浏览器构造页面的原理

当浏览器从服务器接收到了HTML文档,并把HTML在内存中转换成DOM树,在转换的过程中如果发现某个节点(node)上引用了CSS或者IMAGE,就会再发1个request去请求CSS或image,然后继续执行下面的转换,而不需要等待request的返回,当request返回后,只需要把返回的内容放入到DOM树中对应的位置就OK。
但当引用了JS的时候,浏览器发送1个js request就会一直等待该request的返回。因为浏览器需要1个稳定的DOM树结构,而JS中很有可能有代码直接改变了DOM树结构,比如使用document.write 或 appendChild,甚至是直接使用的location.href进行跳转,浏览器为了防止出现JS修改DOM树,需要重新构建DOM树的情况,所以就会阻塞其他的下载和呈现.

30.上下文和作用域的区别(好吧,一直不是很明白,这个查查清除。。。)

总结:上下文其实就是找准对象,作用域就是可以使用的边界(可以发生作用的边界)

首先需要澄清的问题是上下文和作用域是不同的概念。
每个函数调用都有与之相关的作用域和上下文。从根本上说,范围是基于函数(function-based)而上下文是基于对象(object-based)。换句话说,作用域是和每次函数调用时变量的访问有关,并且每次调用都是独立的。上下文总是关键字 this 的值,是调用当前可执行代码的对象的引用。 

变量作用域 
变量能够被定义在局部或者全局作用域,这导致运行时变量的访问来自不同的作用域。全局变量需被声明在函数体外,在整个运行过程中都存在,能在任何作用域中访问和修改。局部变量仅在函数体内定义,并且每次函数调用都有不同的作用域。这主题是仅在调用中的赋值,求值和对值的操作,不能访问作用域之外的值。 
目前javascript不支持块级作用域,块级作用域指在if语句,switch语句,循环语句等语句块中定义变量,这意味着变量不能在语句块之外被访问。当前任何在语句块中定义的变量都能在语句块之外访问。然而,这种情况很快会得到改变,let 关键字已经正式添加到ES6规范。用它来代替var关键字可以将局部变量声明为块级作用域。 

"this" 上下文
上下文通常是取决于一个函数如何被调用。当函数作为对象的方法被调用时,this 被设置为调用方法的对象:

var object = {
foo: function(){
console.log(this === object);
}
};

object.foo(); // true

同样的原理适用于当调用一个函数时通过new的操作符创建一个对象的实例。当以这种方式调用时,this 的值将被设置为新创建的实例:


function foo(){
console.log(this);
}

foo() // window对象
new foo() // foo {}对象

当调用一个未绑定函数,this 将被默认设置为 全局上下文(global context) 或window对象(如果在浏览器中)。然而如果函数在严格模式下被执行("use strict")this的值将被默认设置为undefined

javascript是一个单线程语言,这意味着在浏览器中同时只能做一件事情。当javascript解释器初始执行代码,它首先默认全局上下文。每次调用一个函数将会创建一个新的执行上下文(注:执行上下文(execution context)“在这里的所要表达的意思是作用域)。

每次新创建一个执行上下文(注:此处指的是作用域),会被添加到作用域链的顶部,又是也成为执行或调用栈。浏览器总是运行在位于作用域链顶部当前执行上下文一旦完成,它(当前执行上下文)将从栈顶被移除并且将控制权归还给之前的执行上下文

不同执行上下文之间的变量命名冲突通过攀爬作用域链解决,从局部直到全局。这意味着具有相同名称的局部变量在作用域链中有更高的优先级。 (近水楼台先得月
简单的说,每次你试图访问函数执行上下文中的变量时,查找进程总是从自己的变量对象开始。如果在自己的变量对象中没发现要查找的变量,继续搜索作用域链。它将攀爬作用域链检查每一个执行上下文的变量对象去寻找和变量名称匹配的值。(这个可以理解为就近原则

31.简单的说一下闭包的应用

最流行的闭包类型是广为人知的模块模式。它允许你模拟公共的,私有的和特权成员:

var Module = (function(){
var privateProperty = 'foo';

function privateMethod(args){
//do something
}

return {

publicProperty: "",

publicMethod: function(args){
//do something
}

}
})();

//此时的Module对象在外部只能获取到的是publicProperty属性和publicMethod方法。

模块实际上有些类似于单例,在末尾添加一对括号,当解释器解释完后立即执行(立即执行函数)。闭包执行上下位的外部唯一可用的成员是返回对象中公用的方法和属性(例如Module.publicMethod)。然而,所有的私有属性和方法在整个程序的生命周期中都将存在,由于(闭包)使执行上下文收到保护,和变量的交互要通过公用的方法。(其实所谓的公有和私有,就是看有没有return出去啦

另一种类型的闭包叫做立即调用函数表达式(immediately-invoked function expression IIFE),无非是一个在window上下文中的自调用匿名函数(self-invoked anonymous function)。

function(window){

var a = 'foo', b = 'bar';

function private(){
// do something
}

window.Module = {

public: function(){
// do something
}
};

})(this);

对保护全局命名空间,这种表达式非常有用,所有在函数体内声明的变量都是局部变量,并通过闭包在整个运行环境保持存在。这种封装源代码的方式对程序和框架都是非常流行的,通常暴露单一全局接口与外界交互。

32.call和apply就不多说了,改变上下文而已的啦,重点讲个bind

call和apply的区别讲得最多的就是,传入参数的形式的不同
apply只接受两个参数
eg:
user.call(window, 'John', 'Doe', 30); 
user.apply(window, ['John', 'Doe', 30]); 
(其实还记得其他地方有讲两者还有其他的不同,找不到了。。。等以后发现了,再来补)

至于这个bind以前没怎么太关注过啊!

33.好吧,这个Function.prototype.bind()原来还是个大牛,值得单独拿出来一写!

先引用一下大牛们的话

Jack Archibald 关于缓存 this 的微博(twitter):

Jake Archibald: “我会为了作用域做任何事情,但是我不会使用 that = this”(好吧,我还经常用,还为此感到丝丝骄傲的!我倒!)

我对这个问题更清晰的认识是在我看到Sindre Sorhus更清楚的描述之后:

Sindre Sorhus:“在jQuery中使用$this,但是对于纯JS我不会,我会使用.bind()”(哭瞎了。。。$this是神马呀,我只会$(this)啊。。。)

通常,我们缓存上下文(其实就是对象啦),是这样的..

var myObj = {
 
    specialFunction: function () {
 
    },
 
    anotherSpecialFunction: function () {
 
    },
 
    getAsyncData: function (cb) {
        cb();
    },
 
    render: function () {
        var that = this;
        this.getAsyncData(function () {
            that.specialFunction();      //注:这里如果改成this,会报错:Uncaught TypeError: Object [object global] has no method specialFunction,因为这里的this指代的是window(这个参数函数没有属于的对象(官方说未绑定对象),so默认为window的对象(忽略strict模式啦))
         that.anotherSpecialFunction();
        });
    }
};
 
myObj.render();

然而使用 Function.prototype.bind() 可以有更加简洁干净的方式:

render: function () {
 
    this.getAsyncData(function () {
 
        this.specialFunction();
 
        this.anotherSpecialFunction();
 
    }.bind(this));
 
}
.bind()创建了一个函数,当这个函数在被调用的时候,它的 this 关键词会被设置成被传入的值(这里指调用bind()时传入的参数)。
因此,我们传入想要的上下文,this(其实就是 myObj),到.bind()函数中。然后,当回调函数被执行的时候, this 便指向 myObj 对象。

bind的内部原理(用this.apply(scope))

Function.prototype.bind = function (scope) {
    var fn = this;
    return function () {
        return fn.apply(scope);
    };
}

bind实例

var foo = {
    x: 3
}
 
var bar = function(){
    console.log(this.x);
}
 
bar(); 
// undefined
 
var boundFunc = bar.bind(foo);
 
boundFunc(); //3
我们创建了一个新的函数,当它被执行的时候,它的 this 会被设置成 foo —— 而不是像我们调用 bar() 时的全局作用域。

34.作用域链的理解。 

每一段js代码(全局代码或函数)都有一个与之关联的作用域链(scope chain)。

当js需要查找变量x值的时候(这个过程称为变量解析(variable resolution)),它会从链的第一个对象开始查找,如果这个对象有一个名为x的属性,则会直接使用这个属性的值,如果第一个对象中没有名为x的属性,js会继续查找链上的下一个对象。如果第二个对象依然没有名为x的属性,则会继续查找下一个,以此类推。

如果作用域链上没有任何一个对象含有属性x,那么就认为这段代码的作用域链上不存在x,并最终抛出一个引用错误(ReferenceError)异常。

35.数组去重

Array.prototype.unique1 = function () {
  var n = []; //一个新的临时数组
  for (var i = 0; i < this.length; i++) //遍历当前数组
  {
    //如果当前数组的第i已经保存进了临时数组,那么跳过,
    //否则把当前项push到临时数组里面
    if (n.indexOf(this[i]) == -1) n.push(this[i]);
  }
  return n;
}

Array.prototype.unique2 = function()
{
    var n = {},r=[]; //n为hash表,r为临时数组
    for(var i = 0; i < this.length; i++) //遍历当前数组
    {
        if (!n[this[i]]) //如果hash表中没有当前项
        {
            n[this[i]] = true; //存入hash表
            r.push(this[i]); //把当前数组的当前项push到临时数组里面
        }
    }
    return r;
}

Array.prototype.unique3 = function()
{
    var n = [this[0]]; //结果数组
    for(var i = 1; i < this.length; i++) //从第二项开始遍历
    {
        //如果当前数组的第i项在当前数组中第一次出现的位置不是i,
        //那么表示第i项是重复的,忽略掉。否则存入结果数组
        if (this.indexOf(this[i]) == i) n.push(this[i]);
    }
    return n;
}

36. js的事件绑定

自己封装函数
function  myAddEvent( obj, ev ,fn )   //注:此处传入的ev是不带"on"的事件名称
{
    if ( obj.attachEvent )
    {
        obj.attachEvent( "on" + ev ,fn );    //此处是在IE下
    }  
    else
    {
       obj.addEventListener ( ev , fn ,false) ;   //第三个参数是 是否捕获 
    }
}

//补充的是
IE方式下:{
绑定事件处理函数: attachEvent( 事件名称,函数)
解除绑定 : detachEvent( 事件名称,函数 )
}
DOM方式下:
{
 绑定事件处理函数: addEventListener ( 事件名称,函数,捕获 )
 解除绑定 : removeEventListener ( 事件名称,函数,捕获)
}
原文地址:https://www.cnblogs.com/shixiaomiao/p/4782506.html