kaynewang / blog Goto Github PK
View Code? Open in Web Editor NEWblog: https://kaynewang.github.io/
blog: https://kaynewang.github.io/
方便快速浏览高级程序设计各章节的大致内容。
注意:由于该文只提供了各章节的总结,所以内容比较有限,如需了解详细内容,还请阅读《JavaScript高级程序设计第三版》
JavaScript是一种专为与网页交互而设计的脚本语言,由下列三个不同的部分组成:
JavaScript的这三个组成部分,在当前五个主要浏览器(IE、Firefox、Chrome、Safari和Opera)中都得到了不同程度的支持。其中,所有浏览器对ECMAScript第3版的支持大体上都还不错,而对ECMAScript5的支持程度越来越高,但对DOM的支持则彼此相差比较多。对HTML5已经正式纳入标准的BOM来说,尽管各浏览器都实现了某些众所周知的共同特性,但其他特性还是会因浏览器而异。
把JavaScript插入到HTML页面中要使用<script>元素。使用这个元素可以把JavaScript嵌入到HTML页面中,让脚本与标记混合在一起;也可以包含外部的JavaScript文件。而我们需要注意的地方有:
另外,使用元素可以指定在不支持脚本的浏览器中显示替代内容。但在启用了脚本的情况下,浏览器不会显示元素中的任何内容。
JavaScript的核心语言特性在ECMA-262中是以名为ECMAScript的伪语言的形式来定义的。ECMAScript中包含了所有基本的语法、操作符、数据类型以及完成基本的计算任务所必须的对象,但没有对取得输入和产生输出的机制作出规定。理解ECMAScript及其纷繁复杂的各种细节,是理解其在Web浏览器中的实现——JavaScript的关键。目前大多数实现所遵循的都是ECMA-262第3版,但很多也已经着手开始实现第5版了。以下简要总结了ECMAScript中基本的要素。
JavaScript变量可以用来保存两种类型的值:基本类型值和引用类型值。基本类型的值源自以下5种基本数据类型:Undefined、Null、Boolean、Number和String。基本类型值和引用类型值具有以下特点:
所有变量(包括基本类型和引用类型)都存在与一个执行环境(也称为作用域)当中,这个执行环境决定了变量的生命周期,以及哪一部分代码可以访问其中的变量。以下是关于执行环境的几点总结:
JavaScript是一门具有自动垃圾收集机制的编程语言,开发人员不必关心内存分配和回收问题。可以对JavaScript的垃圾收集历程做如下总结。
对象在JavaScript中被称为引用类型的值,而且有一些内置的引用类型可以用来创建特定的对象,现简要总结如下:
函数实际上是Function类型的实例,因此函数也是对象;而这一点正是JavaScript最有特色的地方。由于函数是对象,所以函数也拥有方法,可以用来增强其行为。
因为有了基本包装类型,所以JavaScript中的基本类型值可以被当作对象来访问。三种基本包装类型分别是:Boolean、Number和String。以下是它们的共同特征:
在所有代码执行之前,作用域中就已经存在两个内置对象:Global和Math。在大多数ECMAScript实现中都不能直接访问Global对象;不过,Web浏览器实现了承担该角色的window对象。全局变量和函数都是Global对象的属性。Math对象提供了很多属性和方法,用于辅助完成复杂的数学计算任务。
ECMAScript支持面向对象(OO)编程,但不使用类或者接口。对象可以在代码执行过程中创建和增强,因此具有动态性而非严格定义的实体。在没有类的情况下,可以采用下列模式创建对象。
JavaScript主要通过原型链实现继承。原型链的构建是通过将一个类型的实例赋值给另一个构造函数的原型实现的。这样,子类型就能够访问超类型的所有属性和方法,这一点与基于类的继承很相似。原型链的问题是对象实例共享所有继承的属性和方法,因此不适宜单独使用。解决这个问题的技术是借用构造函数,即在子类型构造函数的内部调用超类型构造函数。这样就可以做到每个实例都具有自己的属性,同时还能保证只使用构造函数模式来定义类型。使用最多的继承模式是组合继承,这种模式使用原型链继承共享的属性和方法,而通过借用构造函数继承实例属性。
此外,还存在下列可供选择的继承模式。
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
function inheritPrototype(subType, superType) {
var prototype = object(superType.prototype); // 创建对象
prototype.constructor = subType; // 增强对象
subType.prototype = prototype; // 指定对象
}
function SuperType(name) {
this.name = name;
this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function() {
alert(this.name);
};
function SubType(name, age) {
SuperType.call(this, name);
this.age = age;
}
inheritPrototype(SubType, SuperType);
SubType.prototype.sayAge = function() {
alert(this.age);
};
在JavaScript编程中,函数表达式是一种非常有用的技术。使用函数表达式可以无须对函数命名,从而实现动态编程。匿名函数,也称为拉姆达函数,是一种使用JavaScript函数的强大方式。以下总结了函数表达式的特点。
// 经典递归阶乘函数
function factorial(num) { // 非严格模式
if (num <= 1) {
return 1;
} else {
return num * arguments.callee(num - 1);
}
}
var factorial = (function f(num) { // 严格模式和非严格模式都行得通
if (num <= 1) {
return 1;
} else {
return num * f(num - 1);
}
});
当在函数内部定义了其他函数时,就创建了闭包。闭包有权访问包含函数内部的所有变量,原理如下。
使用闭包可以在JavaScript中模仿块级作用域(JavaScript本身没有块级作用域的概念),要点如下。
闭包还可以用于在对象中创建私有变量,相关概念和要点如下。
JavaScript中的函数表达式和闭包都是极其有用的特性,利用它们可以实现很多功能。不过,因为创建闭包必须维护额外的作用域,所以过度使用它们可能会占用大量内存。
浏览器对象模型(BOM)以window对象为依托,表示浏览器窗口以及页面可见区域。同时,window对象还是ECMAScript中的Global对象,因而所有全局变量和函数都是它的属性,且所有原生的构造函数及其他函数也都存在于它的命名空间下。本章讨论了下列BOM的组成部分。
BOM中还有两个对象:screen和history,但它们的功能有限。screen对象中保存着与客户端显示器有关的信息,这些信息一般只用于站点分析。history对象为访问浏览器的历史记录开了一个小缝隙,开发人员可以据此来判断历史记录的数量,也可以在历史记录中向后或向前导航到任意页面。
客户端检测时JavaScript开发中最具争议的一个话题。由于浏览器间存在差别,通常需要根据不同浏览器的能力分别编写不同的代码。有不少客户端检测方法,但下列是最经常使用的。
在决定使用哪种客户端检测方法时,一般应优先考虑使用能力检测。怪癖检测是确定应该如何处理代码的第二种选择。而用户代理检测则是客户端检测的最后一种方案,因为这种方法对用户代理字符串具有很强的依赖性。
DOM是语言中立的API,用于访问和操作HTML和XML文档。DOM1级将HTML和XML文档形象地看作一个层次化的节点树,可以使用JavaScript来操作这个节点树,进而改变底层文档的外观和结构。
DOM由各种节点构成,简要总结如下。
访问DOM的操作在多数情况下都很直观,不过在处理<script>和<style>元素时还是存在一些复杂性。由于这两个元素分别包含脚本和样式信息,因此浏览器通常会将它们与其他元素区别对待。这些区别导致了在针对这些元素使用innerHTML时,以及在创建新元素时的一些问题。
理解DOM的关键,就是理解DOM对性能的影响。DOM操作往往是JavaScript程序中开销最大的部分,而因访问NodeList导致的问题最多。NodeList对象都是“动态的”,这就意味着每次访问NodeList对象,都会运行一次查询。有鉴于此,最好的办法就是尽量减少DOM操作。
虽然DOM为与XML及HTML文档交互制定了一系列核心API,但仍然有几个规范对标准的DOM进行了扩展。这些扩展中有很多原来是浏览器专有的,但后来成为了事实标准,于是其他浏览器也都提供了相同的实现。本章介绍的三个这方面的规范如下。
虽然目前DOM扩展的数量还不多,但随着Web技术的发展,相信一定还会涌现出更多扩展来。很多浏览器都在试验专有的扩展,而这些扩展一旦获得认可,就能成为“伪”标准,甚至会被收录到规范的更新版本中。
DOM2级规范定义了一些模块,用于增强DOM1级。“DOM2级核心”为不同的DOM类型引入了一些与XML命名空间有关的方法。这些变化只在使用XML或XHTML文档时才有用;对于HTML文档没有实际意义。除了与XML命名空间有关的方法外,“DOM2级核心”还定义了以编程方式创建Document实例的方法,也支持了创建DocumentType对象。
“DOM2级样式”模块主要针对操作元素的样式信息而开发,其特性简要总结如下。
“DOM2级遍历和范围”模块提供了与DOM结构交互的不同方式,简要总结如下。
以下面试题来自砖家个人blog的总结,希望大家都去看一下砖家的blog,总结的特别好。
以下面试题的答案还在完善中,每个人的答案都不一样,这些仅仅是个人搜集的一些总结,不正确的地方还请大家指正。
可以使用不同的doctype来激活不同的模式。
html5 的 doctype,激活标准模式
<!DOCTYPE html>
为什么HTML5的doctype这么简单?
因为HTML5不再是基于SGML的语言,而doctype只是用来激活模式的。
HTML5之前,HTML都是用SGML来书写的,DOCTYPE则用来声明文档类型,它可以告诉SGML parser使用什么DTD来解析文档。到了HTML5,根本没有对应的DTD,所以也就没有后面复杂的一串表述了。
为什么HTML5不再是SGML了?
可能的原因:SGML需要在DTD中定义好标签和属性,但是HTML5中要求允许使用自定义标签和属性,原来的框架太过束缚。
什么是SGML
它可以定义标签语言的元语言,比如HTML5之前的版本都是使用SGML来写的。
XHTML1.0 用于过渡的 doctype,它会激活标准模式
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
总结
doctype的作用就是用来激活各种渲染模式的。
所谓的标准模式是指,浏览器按W3C标准解析执行代码;怪异模式则是使用浏览器自己的方式解析执行代码,因为不同的浏览器解析执行的方式不一样,所以称为怪异模式。浏览器解析时到底使用标准模式还是怪异模式,与网页中DTD声明直接相关,DTD声明定义了标准文档的类型,会使浏览器使用相应的方式加载网页并显示,忽略DTD声明,将使网页进入怪异模式。
几乎标准模式是Firefox1+设定的,类似于标准模式。
产生的历史原因是什么?
在HTML和CSS的标准未完成之前,各个浏览器对于HTML和CSS的解析有各自不同的实现,而有很多旧的网页都是按照这些非标准的实现去设计的。
在HTML和CSS标准确定之后,浏览器一方面要按照标准去实现对HTML和CSS的支持,另一方面又要保证对非标准的旧网页设计的后向兼容。因此,现代浏览器一般都有两种渲染方式:标准模式和怪异模式。
怪异模式有哪些怪异的行为?
标准CSS盒模型的宽度和高度等于内容区的高度和宽度,不包含内边距和边框。
IE6之前,盒模型的宽高计算方式是包含内边距和边框的。因此,对于IE来说,怪异模式的盒模型宽高计算方式不同
标准模式下vertical-align属性默认取值为baseline,怪异模式下,vertical-align属性的默认取值为bottom,因此在图片底部会有留白的空间。
标准模式,overflow默认值是visible,怪异模式下,该溢出会被当做扩展box来对待,即元素的大小由其内容决定,溢出不会裁减,元素框自动调整,包含溢出内容。
使用这样的结构可以进行数据存放。使用data-*可以解决自定义属性混乱无管理的现状。
data-*有两种设置方式,可以直接在HTML元素标签上书写
<div id="test" data-age="24">
click here
</div>
HTML5中元素都会有一个dataset的属性,这是一个DOMStringMap类型的键值对集合
var test = document.getElementById('test');
test.dataset.my = 'Byron';
标签及属性
地理位置
画布
视频
音频
拖放
微数据
应用缓存
Web存储
web workers
服务器发送事件
为了持久化存储一些有用的数据,对于网络化编程,一般将这项任务交给了服务器端的数据库或者浏览器端的cookie。随着HTML5的出现,web开发多了两种选择:Web Storage和Web SQL Database。
Web Storage有两种形式:LocalStorage(本地存储)和sessionStorage(会话存储)。这两种方式都允许开发者使用js设置的键值对进行操作,在重新加载不同的页面时读取它们。这一点与cookie类似。
与cookie不同的是:Web Storage数据完全存储在客户端,不需要浏览器请求将数据返回服务器,因此相比cookie能够存储更多的数据,大约5M左右。
LocalStorage和sessionStorage功能上是一样的,但是存储时间不同。
localStorage:浏览器关闭了,数据依然可以保存下来,并可用于所有同源(相同域名、协议和端口)窗口(或标签页)
sessionStorage:数据存储在窗口对象中,窗口关闭后对应的窗口对象消失,存储的数据也会丢失。
script 当页面解析到script标签时,会停止解析并下载对应的脚本,并马上执行,执行完后再继续解析页面。
script async 在下载脚本的同时不会停止对页面的解析,但是在下载完成之后会停止解析并开始执行,执行完毕后继续解析页面。
script defer 下载时跟async一样不会停止解析页面,下载完毕后会延迟到页面解析完后执行。
async和defer都只对外部脚本有效,IE7及更早的版本对嵌入脚本也支持defer;另外,HTML5规范中,defer要按照顺序执行,但实际上defer跟async都不一定会按照顺序执行。
如果把JS代码放在head里面的话,则先被解析,但此时body还没有解析。(常规html结构都是head在前,body在后)如果head的js代码是需要传入一个参数(在body中调用该方法时,才会传入参数),并需调用该参数进行一系列的操作,那么这时候肯定就会报错,因为函数该参数未定义。
而为什么我们经常会看到有很多人把js脚本放在head里面不担心出问题,因为通常把js放在head里的话,一般都会绑定一个监听,当全部的html文档解析完之后,再执行代码。
一般希望DOM还没加载必须需要先加载的js会放置在< head>中,有些加了defer、async的< script>也会放在< head>中。
指浏览器不用等待所有页面资源都渲染好之后再呈现给用户看,而是边下载边渲染,所以用户打开一个网页的时候往往不能第一时间看到所有内容,但是能够看到一个大概的样子,后续的内容浏览器会慢慢补上形成一个完整的页面。
其实就是为了解决JS加载时间问题。
实现方法:需要服务器端渲染SSR,进行首屏渲染,直接返回JSON和页面。
为了规范HTML,W3C结合XML制定了XHTML1.0标准,这个标准没有增加任何新的tag,只是按照XML的要求规范HTML。
XHTML中的标签都必须被正确地嵌套,HTML中的某些标签可以彼此不正确的嵌套。
XHTML中的所有标签必须要关闭。
XHTML中规范定义:标签名和属性对大小写敏感,所有XHTML标签名必须用小写字母。
XHTML文档必须有根元素。
XHTML中标签属性值要使用双引号。
header 页眉(网页的头部 顶部 导航区域等等),闭合标签;块元素,默认的宽:100%;高:内容的高度;实质上跟DIV标签完全一样。
nav 导航链接部分,闭合标签;块元素,默认的宽:100%;高:内容的高度;实质上跟DIV标签完全一样。
section 标签定义网页中的区域(部分)。比如章节、页眉、页脚或文档中的其他部分。闭合标签;块元素,默认的宽:100%;高:内容的高度;实质上跟DIV标签完全一样。
footer 页脚(网页的底部,版权区域等等),闭合标签;块元素,默认的宽:100%;高:内容的高度;实质上跟DIV标签完全一样。
article 内容是引用其他地方的。一个区域中的另外一部分内容;块元素,默认的宽:100%;高:内容的高度;实质上跟DIV标签完全一样。
aside跟article是一起使用;辅助article区域的内容。可以理解为整个网页的辅助区域(京东右侧的工具栏)
hgroup 给标题分组,为标题或者子标题进行分组,通常与h1-h6元素组合使用。闭合标签;块元素,默认的宽:100%;高:内容的高度;实质上跟DIV标签完全一样。
figure 对多个元素进行组合。通常与figcaption联合使用。闭合标签;块元素,默认的宽:100%;高:内容的高度;实质上跟DIV标签完全一样。ficaption定义figure元素组的标题,必须写在figure元素中。一个figure元素内最多只允许放置一个figcaption元素。闭合标签;块元素,默认的宽:100%;高:内容的高度;实质上跟DIV标签完全一样。
audio 播放声音文件,比如音乐或者其它音频流。可以在开始标签和结束标签之间放置文本内容,这样老的浏览器就可以显示出不支持该标签的信息。闭合标签;行内元素;默认的宽:controls的宽度300px;高:controls的高度32px;autoplay属性,音频在就绪后马上播放。controls属性,向用户显示控件,比如播放按钮。preload属性,音频在页面加载时进行加载,并预备播放,如果使用autoplay则忽略该属性。src url要播放音频的URL。
video 播放视频文件,比如电影或其它视频流。可以在开始标签和结束标签之间放置文本内容,这样老的浏览器就可以显示出不支持该标签的信息。闭合标签;行内元素;默认的宽:300px 高:150px。autoplay属性,视频就绪后马上播放。controls属性,向用户显示控件,比如播放按钮。height设置视频播放器的高度。loop属性,媒介文件播放后再次开始播放。preload属性,视频在页面加载时进行加载,并预备播放,如果使用autoplay,则忽略该属性。src url 要播放的视频的URL。width设置视频播放器的宽度。
source 为媒介元素(比如video和audio)指定多个播放格式与编码,浏览器会自动选择一个可以识别的格式。非闭合标签,只有开始标签,没有结束标签。source行内元素,默认无宽度和高度。media定义媒介资源的类型,供浏览器决定是否下载。src媒介的URL。type定义播放器在音频流中的什么位置开始播放。默认,音频从头播放。
canvas 定义图形,比如图表和其他图像。闭合标签;行内元素;默认情况下,canvas创建的画布宽:300px 高:150px
datalist 定义可选数据的列表。与input元素配合使用,就可以制作出输入值的下拉列表。闭合标签;行内元素;默认无宽度和高度。
embed 定义嵌入的内容,比如插件。用来插入各种多媒体,格式可以是MIDI、MP3等。非闭合标签,只有开始标签,没有结束标签。行内元素,默认的宽:300px;高:150px
time 定义日期或时间,或者两者。闭合标签;行内元素,默认情况宽:内容的宽度,高:内容的高度。
address 为文档或section定义联系信息,比如:电子邮箱、地址、电话、QQ、微信号等。闭合标签;块元素;默认的宽是:100%;高:内容的高度;实质上,跟DIV标签,可以说是完全一样的特性。
map定义客户端的图像映射。图像映射是带有可点击区域的图像。闭合标签;行内元素;默认情况下,无宽度和高度。
area area 元素永远嵌套在 map 元素内部。area 元素可定义图像映射中的区域。闭合标签,行内元素;只有结束标签,没有开始标签。默认情况下,无宽度和高度。
mark定义页面中需要突出显示或高亮显示的内容,通常在引用原文时,使用此元素,目的就是引起当前用户的注意。闭合标签;行内元素;默认情况下,宽:内容的宽度;高:内容的高度。
details 标签定义元素的细节,用户可进行查看,或通过点击进行隐藏。(备注信息),块元素;默认的宽是:100%;高:内容的高度;实质上,跟DIV标签,可以说是完全一样的特性;但是有一个动态的效果,点击可以显示(展开)内容,再点击可以隐藏(收起)内容。
Normalize 相对「平和」,注重通用的方案,重置掉该重置的样式,保留有用的 user agent 样式,同时进行一些 bug 的修复,这点是 reset 所缺乏的。
Reset 相对「暴力」,不管你有没有用,统统重置成一样的效果,且影响的范围很大,讲求跨浏览器的一致性。
Normalize.css是一种CSS reset的替代方案。它们的区别有:
选择Normalize.css ,主要是reset.css为几乎所有的元素施加默认样式,所以需要对所有公共的排版元素重新设置样式,这是一件很麻烦的工作。
float属性定义了元素是否浮动及在哪个方向浮动,在CSS中任何元素都可以浮动,且浮动元素会生成一个块级框,而不论它本身是何种元素。并且盒子的宽度不在伸展,而是根据盒子里面的内容的宽度来确定。浮动属性会使得浮动的元素脱离文档流,所以文档的普通流中的块框会表现的像浮动框不存在一样。
<style type="text/css">
.div1{
background:#000080;
border:1px solid red;
}
.div2{
background:#800080;
border:1px solid red;
height:100px;
margin-top:10px;
}
.left{
float:left;
width:20%;
height:200px;
background:#DDD;
}
.right{
float:right;
width:30%;
height:80px;
background:#DDD;
}
/*清除浮动代码*/
.clearfloat:after{
display:block;
clear:both;
content:"";
visibility:hidden;
height:0;
}
.clearfloat{
zoom:1;
}
</style>
<div class="div1 clearfloat">
<div class="left">Left</div>
<div class="right">Right</div>
</div>
<div class="div2">
div2
</div>
原理:IE8以上和非IE浏览器才支持:after,原理和方法2有点类似,zoom(IE转有属性)可解决ie6,ie7浮动问题
<style type="text/css">
.div1{
background:#000080;
border:1px solid red;
}
.div2{
background:#800080;
border:1px solid red;
height:100px;
margin-top:10px;
}
.left{
float:left;
width:20%;
height:200px;
background:#DDD;
}
.right{
float:right;
width:30%;
height:80px;
background:#DDD;
}
/*清除浮动代码*/
.clearfloat{
clear: both;
}
</style>
<div class="div1">
<div class="left">Left</div>
<div class="right">Right</div>
</div>
<div class="clearfloat"></div>
<div class="div2">
div2
</div>
原理:添加一个空div,利用css提供的clear:both清除浮动,让父级div能自动获取到高度
原理:手动定义height,就解决了父级div无法自动获取高度的问题。
原理:必须定义width或zoom:1,同时不能定义height,使用overflow:hidden时,浏览器会自动检查浮动区域的高度
原理:必须定义width或zoom:1,同时不能定义height,使用overflow:auto时,浏览器会自动检查浮动区域的高度
原理:所有代码一起浮动,就变成了一个整体
原理:将div属性变成表格
首先来看在CSS中叠加上下文形成的原因:
margin为负值时元素会依参考线向外偏移。margin-left/margin-top的参考线为左边的元素/上面的元素(如无兄弟元素则为父元素的左内侧/上内侧),margin-right和margin-bottom的参考线为元素本身的border右侧/border下侧。一般可以利用负边距来就行布局,但没有计算好的话就可能造成元素重叠。堆叠顺序由元素在文档中的先后位置决定,后出现的会在上面。
2. position的relative/absolute/fixed定位
当为元素设置position值为relative/absolute/fixed后,元素发生的偏移可能产生重叠,且z-index属性被激活。z-index值可以控制定位元素在垂直于显示屏方向(Z 轴)上的堆叠顺序(stack order),值大的元素发生重叠时会在值小的元素上面。
z-index只能在position属性值为relative或absolute或fixed的元素上有效。
基本原理:z-index值可以控制定位元素在垂直于显示屏方向(Z 轴)上的堆叠顺序(stack order),值大的元素发生重叠时会在值小的元素上面。
使用相对性:z-index值只决定同一父元素中的同级子元素的堆叠顺序。父元素的z-index值(如果有)为子元素定义了堆叠顺序(css版堆叠“拼爹”)。向上追溯找不到含有z-index值的父元素的情况下,则可以视为自由的z-index元素,它可以与父元素的同级兄弟定位元素或其他自由的定位元素来比较z-index的值,决定其堆叠顺序。同级元素的z-index值如果相同,则堆叠顺序由元素在文档中的先后位置决定,后出现的会在上面。所以如果当你发现一个z-index值较大的元素被值较小的元素遮挡了,请先检查它们之间的dom结点关系,多半是因为其父结点含有激活并设置了z-index值的position定位元素。
BFC(Block Formatting Context)直译为“块级格式化上下文”。
定义:一个块级格式化上下文[BFC]是可视化CSS渲染网页的一部分,它是一个区域,块级布局,相互浮动在这个区域发生。它决定了元素如何对其内容进行定位,以及与其他元素的关系和相互作用。
我们在布局时经常会遇到这个问题:对子元素设置浮动后,父元素会发生高度塌陷,也就是父元素的高度变为0。解决这个问题,只需要把把父元素变成一个BFC就行了。常用的办法是给父元素设置OVERFLOW:HIDDEN。
在CSS当中,相邻的两个盒子的外边距可以结合成一个单独的外边距。这种合并外边距的方式被称为折叠,并且因而所结合成的外边距称为折叠外边距。
折叠的结果:
两个相邻的外边距都是正数时,折叠结果是它们两者之间较大的值。
两个外边距一正一负时,折叠结果是两者的相加的和。这个同样可以利用BFC解决。
CSS Sprites是一种网页图片应用处理方式,就是把网页中一些背景图片整合到一张图片文件中,再利用CSS的“background-image”,“background- repeat”,“background-position”的组合进行背景定位。
.afir-pseudo {
overflow: hidden;
position: relative;
}
.afir-pseudo:after {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: url(img/logo.jpg) no-repeat;
}
.mylogo {
display: block;
width: 88px;
height: 31px;
}
<a class="afir-pseudo mylogo" target="_blank" href="http://ciaoca.com">ciaoca</a>
.hide-text {
overflow: hidden;
text-indent: 100%;
white-space: nowrap;
}
.mylogo {
display: block;
width: 88px;
height: 31px;
background: url(img/logo.jpg) no-repeat;
}
<a class="hide-text mylogo" target="_blank" href="http://ciaoca.com">ciaoca</a>
.afir {
overflow: hidden;
position: relative;
}
.afir span {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: url(img/logo.jpg) no-repeat;
}
.mylogo {
display: block;
width: 88px;
height: 31px;
}
<a class="afir mylogo" target="_blank" href="http://ciaoca.com">
<span></span>
ciaoca
</a>
以下面试题来自砖家个人blog的总结,希望大家都去看一下砖家的blog,总结的特别好。
以下面试题的答案还在完善中,每个人的答案都不一样,这些仅仅是个人搜集的一些总结,不正确的地方还请大家指正。
事件代理是利用事件的冒泡原理来实现的。何为事件冒泡?就是事件从最深的节点开始,然后逐步向上传播事件。
<ul id="ul1">
<li>111</li>
<li>222</li>
<li>333</li>
<li>444</li>
</ul>
window.onload = function() {
var oUL = document.getElementById('ul1');
oUL.onclick = function() {
alert(123);
}
}
这里用父级ul做事件代理,当li被点击时,由于冒泡原理,事件会冒泡到ul上,因为ul上有点击事件,所以事件就会触发,当然,这里当点击ul的时候,也是会触发的,那么问题就来了,如果我想让事件代理的效果跟直接给节点的事件效果一样怎么办,比如说只有点击li才会触发。
Event对象提供了一个属性叫target,可以返回事件的目标节点,我们成为事件源,也就是说,target就可以表示为当前的事件操作的dom,但是不是真正操作dom,当然,这个是有兼容性的,标准浏览器用ev.target,IE浏览器用event.srcElement,此时只是获取了当前节点的位置,并不知道是什么节点名称,这里我们用nodeName来获取具体是什么标签名,这个返回的是一个大写的,我们需要转成小写再做比较(习惯问题):
window.onload = function(){
var oUl = document.getElementById("ul1");
oUl.onclick = function(ev){
var ev = ev || window.event;
var target = ev.target || ev.srcElement;
if(target.nodeName.toLowerCase() == 'li'){
alert(123);
alert(target.innerHTML);
}
}
}
现在给一个场景 ul > li > div > p,div占满li,p占满div,还是给ul绑定时间,需要判断点击的是不是li(假设li里面的结构是不固定的),那么e.target就可能是p,也有可能是div,这种情况你会怎么处理呢?
<ul id="test">
<li>
<p>11111111111</p>
</li>
<li>
<div>
22222222
</div>
</li>
<li>
<span>3333333333</span>
</li>
<li>4444444</li>
</ul>
var oUl = document.getElementById('test');
oUl.addEventListener('click',function(ev){
var target = ev.target;
while(target !== oUl ){
if(target.tagName.toLowerCase() == 'li'){
console.log('li click~');
break;
}
target = target.parentNode;
}
})
核心代码是while循环部分,实际上就是一个递归调用,你也可以写成一个函数,用递归的方法来调用,同时用到冒泡的原理,从里往外冒泡,知道currentTarget为止,当当前的target是li的时候,就可以执行对应的事件了,然后终止循环。
那什么样的事件可以用事件委托,什么样的事件不可以用呢?
var x = 0;
var foo = {
x:1,
bar:{
x:2,
baz: function () {
console.log(this.x)
}
}
}
var a = foo.bar.baz
foo.bar.baz() // 2
a() //0
function SuperType() {
this.property = true;
}
SuperType.prototype.getSuperValue = function() {
return this.property;
}
function SubType() {
this.subproperty = false;
}
// 继承了 SuperType
SubType.prototype = new SuperType();
// 给原型添加方法的代码一定要放在替换原型的语句之后
SubType.prototype.getSubValue = function() {
return this.subproperty;
}
var instance = new SubType();
alert(instance.getSuperValue()); // true
function SuperType() {
this.colors = ['red', 'blue', 'green'];
}
function SubType() {
// 继承 SuperType
SuperType.call(this);
}
var instance1 = new SubType();
instance1.colors.push('black');
alert(instance1.colors); // red,blue,green,black
var instance2 = new SubType();
alert(instance2.colors); // red,blue,green
function SuperType(name) {
this.name = name;
this.colors = ['red', 'blue', 'green'];
}
SuperType.prototype.sayName = function() {
console.log(this.name);
}
function SubType(name, age) {
// 继承属性
SuperType.call(this, name);
this.age = age;
}
// 继承方法
SubType.prototype = new SuperType();
SubType.prototype.sayAge = function() {
console.log(this.age);
}
var instance1 = new SubType('kayne', 24);
instance1.colors.push('black');
alert(instance1.colors); // red,blue,green,black
instance1.sayName(); // kayne
instance1.sayAge(); // 24
var instance2 = new SubType('kayne wang', 24);
alert(instance2.colors); // red,blue,green
instance2.sayName(); // kayne wang
instance2.sayAge(); // 24
function object(o) { // 同 Object.create() 方法
function F() {};
F.prototype = o;
return new F();
}
var person = {
name: 'Nicholas',
friends: ['Shelby', 'Court', 'Van']
};
var anotherPerson = object(person);
anotherPerson.name = 'Greg';
anotherPerson.friends.push('Rob');
var yetAnotherPerson = object(person);
yetAnotherPerson.name = 'Linda';
yetAnotherPerson.friends.push('Barbie');
alert(person.friends); // Shelby,Court,Van,Rob,Barbie
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
function createAnother(original) {
var clone = object(original);
clone.sayHi = function() {
alert('Hi');
};
return clone;
}
var person = {
name: 'Nicholas',
friends: ['Shelby', 'Court', 'Van']
};
var anotherPerson = createAnother(person);
anotherPerson.sayHi(); // Hi
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
function inheritPrototype(subType, superType) {
var prototype = object(superType.prototype);
prototype.coustructor = subType;
subType.prototype = prototype;
}
function SuperType(name) {
this.name = name;
this.colors = ['red', 'blue', 'green'];
}
SuperType.prototype.sayName = function() {
console.log(this.name);
}
function SubType(name, age) {
// 继承属性
SuperType.call(this, name);
this.age = age;
}
inheritPrototype(SubType, SuperType);
SubType.prototype.sayAge = function () {
console.log(this.age);
}
commonJS
CommonJS定义模块分为:模块引用(require)、模块导出(exports)、模块标识(module)。浏览器不兼容CommomJS的原因是因为缺少node环境的四个变量:
模块加载原理:
var module = {
exports: []
};
(function(module, exports) {
// 需要导出的模块
exports.mutiply = function(n) { return n * 1000 };
}(module, module.exports))
var f = module.exports.mutiply;
f(5); // 5000
ES6
AMD
由于commonJS的服务端模块规范形成,所以自然也就需要一套客户端模块化规范。由于require是同步的,所以如果直接使用commonJS的require会造成浏览器假死的现象(需要等待模块加载完成),所以在浏览器中引入模块需要异步加载,这就是AMD规范诞生的背景条件。
AMD也是通过require引入模块,但不同于commonJS的是,它需要传入一个callback方法:
require(['math'], function(math) {
math.add(2, 3);
})
目前有两个库实现了AMD规范:require.js和curl.js。
AMD模块使用define()定义,例如:
// define([modules], callback) 第一个参数是当前模块的依赖,如果没有依赖可以不填
// math.js
define(function() {
var add = function(x, y) {
return x + y;
};
return {
add: add
};
});
// 加载方法如下
require(['math'], function(math) {
alert(math.add(1, 1));
})
CMD
玉伯写了seajs,就是遵循他提出的CMD规范,相比AMD使用起来更加方便些。具体的区别可以参考SeaJS与RequireJS的最大异同
IIFE 立即执行函数
null undefined区别
闭包 与 作用域
变量的作用域无非就是两种:全局变量和局部变量
内部函数的作用域链仍然保持着对父函数活动对象的引用,就是闭包(closure)
匿名函数
你是如何组织自己的代码?是使用模块模式,还是使用经典继承的方法?
宿主对象 (host objects) 和原生对象 (native objects)
请指出以下代码的区别:function Person(){}、var person = Person()、var person = new Person()?
apply call bind 深入到源码如何实现这三个功能的
// es6 call 实现
Function.prototype.es6Call = function (context, ...args) {
var context = context || window;
context.fn = this;
const result = context.fn(...args);
delete context.fn;
return result;
}
// es6 apply 实现
Function.prototype.es6Apply = function (context, arr) {
var context = context || window;
context.fn = this;
var result;
if (!arr) {
result = context.fn();
} else {
if (!(arr instanceof Array)) throw new Error('params must be array');
result = context.fn(...arr);
}
delete context.fn;
return result
}
// bind es6 实现
Function.prototype.es6Bind = function(context, ...rest) {
if (typeof this !== 'function') throw new TypeError('invalid invoked!');
var self = this;
return function F(...args) {
if (this instanceof F) {
return new self(...rest, ...args)
}
return self.apply(context, rest.concat(args))
}
}
new 源码如何实现的?
function New(f) {
return function () {
var o = {
"__proto__": f.prototype
};
f.apply(o, arguments);
return o;
}
}
document.write()
<script>
document.write('<link rel="stylesheet" href="xxx.css">');
</script>
document.open();
document.write('anthing')
document.close();
特性检测 特性推断 UA字符串嗅探
特性检测更适合针对实现了特定特性的浏览器进行操作。UA字符串由于被浏览器厂商可以随意修改因此不太靠谱。
Ajax工作原理 着重理解XMLHttpRequest!!
Ajax的工作原理相当于在用户和服务器之间加了—个中间层(AJAX引擎),使用户操作与服务器响应异步化。并不是所有的用户请求都提交给服务器,像—些数据验证和数据处理等都交给Ajax引擎自己来做, 只有确定需要从服务器读取新数据时再由Ajax引擎代为向服务器提交请求。
Ajax其核心有JavaScript、XMLHTTPRequest、DOM对象组成,通过XmlHttpRequest对象来向服务器发异步请求,然后xhr对象提供了一系列属性,可以监听响应的情况,然后从服务器获得数据,再用JavaScript来操作DOM而更新页面。
跨域 图片ping,JSONP,CORS
变量声明提升
作用域内所有变量声明都被提到顶部,被提升的变量初始值为undefined,执行到所在行时才真正赋值。
冒泡机制
attribute 和 property
document load 和 document DOMContentLoaded
== 和 === 有什么不同
同源策略 (same-origin policy) Cookie,iframe,AJAX同源
strict模式
为何通常会认为保留网站现有的全局作用域 (global scope) 不去改变它,是较好的选择
为何你会使用 load 之类的事件 (event)?此事件有缺点吗?你是否知道其他替代品,以及为何使用它们?
请解释什么是单页应用 (single page app), 以及如何使其对搜索引擎友好 (SEO-friendly)
Promise 怎么用?源码如何实现的?
使用一种可以编译成 JavaScript 的语言来写JavaScript 代码有哪些优缺点?
javascript调试工具
对象遍历 和 数组遍历
可变对象和不可变对象
什么是事件循环 (event loop) 深入原理,宏任务,微任务等等
let var const
web worker
// 通用版
function curry(func, args) {
var length = func.length;
var args = args || [];
return function() {
var newArgs = args.concat([].slice.call(arguments));
if (newArgs.length < length) {
return curry.call(this, func, newArgs);
} else {
return func.apply(this, newArgs);
}
}
}
function add(a, b) {
return a + b;
}
var addCurry = curry(add);
addCurry(1, 2); // 3
addCurry(1)(2); // 3
// 定制版:实现一个add方法,使计算结果能够满足如下预期:
// add(1)(2)(3) = 6
// add(1, 2, 3)(4) = 10
// add(1)(2)(3)(4)(5) = 15
function add() {
var args = [].slice.call(arguments);
var fn = function() {
var newArgs = args.concat([].slice.call(arguments));
return add.apply(null, newArgs);
}
fn.toString = function() {
return args.reduce(function(a, b) {
return a + b;
})
}
return fn;
}
创建对象的三种方法
深拷贝和浅拷贝 可以实现手写深拷贝
图片懒加载
实现页面加载进度条
箭头函数ES5如何实现
找出数组中最大的元素
function maxItem (array) {
var hash = {};
for(let i = 0; i < array.length; i++) {
if (!hash[array[i]]) {
hash[array[i]] = 1;
} else {
hash[array[i]] ++;
}
}
var max = 0;
var maxV;
var second = 0;
var secondV;
for (let [key, value] of Object.entries(hash)) {
if (value > max) {
second = max;
secondV = maxV;
max = value;
maxV = key;
} else {
second = value;
secondV = key;
}
}
return { max, maxV, second, secondV };
}
// { max: 5, maxV: '2', second: 2, secondV: '100' }
console.log(maxItem([2,2,2,2,3,4,5,4,3,1,4,4,100,100,2]));
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.