Git Product home page Git Product logo

blog's Introduction

blog's People

Contributors

kaynewang avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

blog's Issues

《JavaScript高级程序设计第三版》(章节总结)

《JavaScript高级程序设计第三版》(章节总结)

初衷

方便快速浏览高级程序设计各章节的大致内容。

注意:由于该文只提供了各章节的总结,所以内容比较有限,如需了解详细内容,还请阅读《JavaScript高级程序设计第三版》

目录

  1. 第1章 JavaScript简介
  2. 第2章 在HTML中使用JavaScript
  3. 第3章 基本概念
  4. 第4章 变量、作用域和内存问题
  5. 第5章 引用类型
  6. 第6章 面向对象的程序设计
  7. 第7章 函数表达式
  8. 第8章 BOM
  9. 第9章 客户端检测
  10. 第10章 DOM
  11. 第11章 DOM扩展
  12. 第12章 DOM2和DOM3

第1章 JavaScript简介

JavaScript是一种专为与网页交互而设计的脚本语言,由下列三个不同的部分组成:

  • ECMAScript,由ECMA-262定义,提供核心语言功能;
  • 文档对象模型(DOM),提供访问和操作网页内容的方法和接口;
  • 浏览器对象模型(BOM),提供与浏览器交互的方法和接口。

JavaScript的这三个组成部分,在当前五个主要浏览器(IE、Firefox、Chrome、Safari和Opera)中都得到了不同程度的支持。其中,所有浏览器对ECMAScript第3版的支持大体上都还不错,而对ECMAScript5的支持程度越来越高,但对DOM的支持则彼此相差比较多。对HTML5已经正式纳入标准的BOM来说,尽管各浏览器都实现了某些众所周知的共同特性,但其他特性还是会因浏览器而异。

第2章 在HTML中使用JavaScript

把JavaScript插入到HTML页面中要使用<script>元素。使用这个元素可以把JavaScript嵌入到HTML页面中,让脚本与标记混合在一起;也可以包含外部的JavaScript文件。而我们需要注意的地方有:

  • 在包含外部JavaScript文件时,必须将src属性设置为指向相应文件的URL。而这个文件既可以是与包含它的页面位于同一服务器上的文件,也可以是其他任何域中的文件。
  • 所有<script>元素都会按照它们在页面中出现的先后顺序依次被解析。在不使用defer和async属性的情况下,只有在解析完前面<script>元素中的代码之后,才会开始解析后面<script>元素中的代码。
  • 由于浏览器会先解析完不使用defer属性的<script>元素中的代码,然后再解析后面的内容,所以一般应该把<script>元素放在页面最后,即主要内容后面,标签前面。
  • 使用defer属性可以让脚本在文档完全呈现之后再执行。延迟脚本总是按照指定它们的顺序执行。
  • 使用async属性可以表示当前脚本不必等待其他脚本,也不必阻塞文档呈现。不能保证异步脚本按照它们在页面中出现的顺序执行。

另外,使用元素可以指定在不支持脚本的浏览器中显示替代内容。但在启用了脚本的情况下,浏览器不会显示元素中的任何内容。

第3章 基本概念

JavaScript的核心语言特性在ECMA-262中是以名为ECMAScript的伪语言的形式来定义的。ECMAScript中包含了所有基本的语法、操作符、数据类型以及完成基本的计算任务所必须的对象,但没有对取得输入和产生输出的机制作出规定。理解ECMAScript及其纷繁复杂的各种细节,是理解其在Web浏览器中的实现——JavaScript的关键。目前大多数实现所遵循的都是ECMA-262第3版,但很多也已经着手开始实现第5版了。以下简要总结了ECMAScript中基本的要素。

  • ECMAScript中的基本数据类型包括Undefined、Null、Boolean、Number和String。
  • 与其他语言不同,ECMAScript没有为整数和浮点数值分别定义不同的数据类型,Number类型可用于表示所有数值。
  • ECMAScript中也有一种复杂的数据类型,即Object类型,该类型是这门语言中所有对象的基础类型。
  • 严格模式为这门语言中容易出错的地方施加了限制。
  • ECMAScript提供了很多与C及其他类C语言中相同的基本操作符,包括算术操作符、布尔操作符、关系操作符、相等操作符及赋值操作符等。
  • ECMAScript从其他语言中借鉴了很多流控制语句,例如if语句、for语句和switch语句等。ECMAScript中的函数与其他语言中的函数有诸多不同之处。
  • 无须指定函数的返回值,因为任何ECMAScript函数都可以在任何时候返回任何值。
  • 实际上,未指定返回值的函数返回的是一个特殊的undefined值。
  • ECMAScript中也没有函数签名的概念,因为其函数参数是以一个包含零或多个值的数组的形式传递的。
  • 可以向ECMAScript函数传递任意数量的参数,并且可以通过arguments对象来访问这些参数。
  • 由于不存在函数签名的特性,ECMAScript函数不能重载。

第4章 变量、作用域和内存问题

JavaScript变量可以用来保存两种类型的值:基本类型值和引用类型值。基本类型的值源自以下5种基本数据类型:Undefined、Null、Boolean、Number和String。基本类型值和引用类型值具有以下特点:

  • 基本类型值在内存中占据固定大小的空间,因此被保存在栈内存中;
  • 从一个变量向另一个变量复制基本类型的值,会创建这个值的一个副本;
  • 引用类型的值是对象,保存在堆内存中;
  • 包含引用类型值的变量实际上包含的并不是对象本身,而是一个指向该对象的指针;
  • 从一个变量向另一个变量复制引用类型的值,复制的其实是指针,因此两个变量最终都指向同一个对象;
  • 确定一个值是哪种基本类型可以使用typeof操作符,而确定一个值是哪种引用类型可以使用instanceof操作符。

所有变量(包括基本类型和引用类型)都存在与一个执行环境(也称为作用域)当中,这个执行环境决定了变量的生命周期,以及哪一部分代码可以访问其中的变量。以下是关于执行环境的几点总结:

  • 执行环境有全局执行环境(也称为全局环境)和函数执行环境之分;
  • 每次进入一个新执行环境,都会创建一个用于搜索变量和函数的作用域链;
  • 函数的局部环境不仅有权访问函数作用域中的变量,而且有权访问其包含(父)环境,乃至全局环境;
  • 全局环境只能访问在全局环境中定义的变量和函数,而不能直接访问局部环境中的任何数据;
  • 变量的执行环境有助于确定应该何时释放内存。

JavaScript是一门具有自动垃圾收集机制的编程语言,开发人员不必关心内存分配和回收问题。可以对JavaScript的垃圾收集历程做如下总结。

  • 离开作用域的值将被自动标记为可以回收,因此将在垃圾收集期间被删除。
  • ”标记清除“是目前主流的垃圾收集算法,这种算法的**是给当前不使用的值加上标记,然后再回收其内存。
  • 另一种垃圾收集算法是”引用计数“,这种算法的**是跟踪记录所有支被引用的次数。JavaScript引擎目前都不再使用这种算法;但在IE中访问非原生JavaScript对象(如DOM元素)时,这种算法仍然可能会导致问题。
  • 当代码中存在循环引用现象时,”引用计数“算法就会导致问题。
  • 解除变量的引用不仅有助于消除循环引用现象,而且对垃圾收集也有好处。为了确保有效地回收内存,应该及时解除不再使用的全局对象、全局对象属性以及循环引用变量的引用。

第5章 引用类型

对象在JavaScript中被称为引用类型的值,而且有一些内置的引用类型可以用来创建特定的对象,现简要总结如下:

  • 引用类型与传统面向对象程序设计中的类相似,但实现不同;
  • Object是一个基础类型,其他所有类型都从Object继承了基本的行为;
  • Array类型是一组值的有序列表,同时还提供了操作和转换这些值的功能;
  • Date类型提供了有关日期和时间的信息,包括当前日期和时间以及相关的计算功能;
  • RegExp类型是ECMAScript支持正则表达式的一个接口,提供了最基本的和一些高级的正则表达式功能。

函数实际上是Function类型的实例,因此函数也是对象;而这一点正是JavaScript最有特色的地方。由于函数是对象,所以函数也拥有方法,可以用来增强其行为。
因为有了基本包装类型,所以JavaScript中的基本类型值可以被当作对象来访问。三种基本包装类型分别是:Boolean、Number和String。以下是它们的共同特征:

  • 每个包装类型都映射到同名的基本类型;
  • 在读取模式下访问基本类型值时,就会创建对应的基本包装类型的一个对象,从而方便了数据操作;
  • 操作基本类型值的语句一经执行完毕,就会立即销毁新创建的包装对象。

在所有代码执行之前,作用域中就已经存在两个内置对象:Global和Math。在大多数ECMAScript实现中都不能直接访问Global对象;不过,Web浏览器实现了承担该角色的window对象。全局变量和函数都是Global对象的属性。Math对象提供了很多属性和方法,用于辅助完成复杂的数学计算任务。

第6章 面向对象的程序设计

ECMAScript支持面向对象(OO)编程,但不使用类或者接口。对象可以在代码执行过程中创建和增强,因此具有动态性而非严格定义的实体。在没有类的情况下,可以采用下列模式创建对象。

  • 工厂模式,使用简单的函数创建对象,为对象添加属性和方法,然后返回对象。这个模式后来被构造函数模式所取代。
  • 构造函数模式,可以创建自定义引用类型,可以像创建内置对象实例一样使用new操作符。不过,构造函数模式也有缺点,即它的每个成员都无法得到复用,包括函数。由于函数可以不局限于任何对象(即与对象具有松散耦合的特点),因此没有理由不在多个对象间共享函数。
  • 原型模式,使用构造函数的prototype属性来制定那些应该共享的属性和方法。组合使用构造函数模式和原型模式时,使用构造函数定义实例属性,而使用原型定义共享的属性和方法。

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);
};

第7章 函数表达式

在JavaScript编程中,函数表达式是一种非常有用的技术。使用函数表达式可以无须对函数命名,从而实现动态编程。匿名函数,也称为拉姆达函数,是一种使用JavaScript函数的强大方式。以下总结了函数表达式的特点。

  • 函数表达式不同于函数声明。函数声明要求有名字,但函数表达式不需要。没有名字的函数表达式也叫做匿名函数。
  • 再无法确定如何引用函数的情况下,递归函数就会变得比较复杂;
  • 递归函数应该始终使用arguments.callee来递归地调用自身,不要使用函数名——函数名可能会发生变化。
// 经典递归阶乘函数
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中没有正式的私有对象属性的概念,但可以使用闭包来实现公有方法,而通过公有方法可以访问在包含作用域中定义的变量。
  • 有权访问私有变量的公有方法叫做特权方法。
  • 可以使用构造函数模式、原型模式来实现自定义类型的特权方法,也可以使用模块模式、增强的模块模式来实现单例的特权方法。

JavaScript中的函数表达式和闭包都是极其有用的特性,利用它们可以实现很多功能。不过,因为创建闭包必须维护额外的作用域,所以过度使用它们可能会占用大量内存。

第8章 BOM

浏览器对象模型(BOM)以window对象为依托,表示浏览器窗口以及页面可见区域。同时,window对象还是ECMAScript中的Global对象,因而所有全局变量和函数都是它的属性,且所有原生的构造函数及其他函数也都存在于它的命名空间下。本章讨论了下列BOM的组成部分。

  • 在使用框架时,每个框架都有自己的window对象以及所有原生构造函数及其他函数的副本。每个框架都保存在frames集合中,可以通过位置或通过名称来访问。
  • 有一些窗口指针,可以用来引用其他框架,包括父框架。
  • top对象始终指向最外围的框架,也就是整个浏览器窗口。
  • parent对象表示包含当前框架的框架,而self对象则回指window。
  • 使用location对象可以通过编程方式来访问浏览器的导航系统。设置相应的属性,可以逐段或整体性地修改浏览器的URL。
  • 调用replace()方法可以导航到一个新URL,同时该URL会替换浏览器历史记录中当前显示的页面。
  • navigator对象提供了与浏览器有关的信息。到底提供哪些信息,很大程度上取决于用户的浏览器;不过,也有一些公共的属性(如userAgent)存在于所有浏览器中。

BOM中还有两个对象:screen和history,但它们的功能有限。screen对象中保存着与客户端显示器有关的信息,这些信息一般只用于站点分析。history对象为访问浏览器的历史记录开了一个小缝隙,开发人员可以据此来判断历史记录的数量,也可以在历史记录中向后或向前导航到任意页面。

第9章 客户端检测

客户端检测时JavaScript开发中最具争议的一个话题。由于浏览器间存在差别,通常需要根据不同浏览器的能力分别编写不同的代码。有不少客户端检测方法,但下列是最经常使用的。

  • 能力检测:在编写代码之前先检测特定浏览器的能力。例如,脚本在调用某个函数之前,可能要先检测该函数是否存在。这种检测方法将开发人员从考虑具体的浏览器类型和版本中解放出来,让他们把注意力集中到相应的能力是否存在上。能力检测无法精确地检测特定的浏览器和版本。
  • 怪癖检测:怪癖实际上是浏览器实现中存在的bug,例如早期的WebKit中就存在一个怪癖,即它会在for-in循环中返回被隐藏的属性。怪癖检测通常涉及到运行一小段代码,然后确定浏览器是否存在的某个怪癖。由于怪癖检测与能力检测相比较效率更低,因此应该只在某个怪癖会干扰脚本运行的情况下使用。怪癖检测无法精确地检测特定的浏览器和版本。
  • 用户代理检测:通过检测用户代理字符串来识别浏览器。用户代理字符串中包含大量与浏览器有关的信息,包括浏览器、平台、操作系统及浏览器版本。用户代理字符串有过一段相当长的发展历史,在此期间,浏览器提供商试图通过在用户代理字符串中添加一些欺骗性信息,欺骗网站相信自己的浏览器是另外一种浏览器。用户代理检测需要特殊的技巧,特别是要注意Opera会隐瞒其用户代理字符串的情况。即便如此,通过用户代理字符串仍然能够检测出浏览器所用的呈现引擎以及所在的平台,包括移动设备和游戏系统。

在决定使用哪种客户端检测方法时,一般应优先考虑使用能力检测。怪癖检测是确定应该如何处理代码的第二种选择。而用户代理检测则是客户端检测的最后一种方案,因为这种方法对用户代理字符串具有很强的依赖性。

第10章 DOM

DOM是语言中立的API,用于访问和操作HTML和XML文档。DOM1级将HTML和XML文档形象地看作一个层次化的节点树,可以使用JavaScript来操作这个节点树,进而改变底层文档的外观和结构。

DOM由各种节点构成,简要总结如下。

  • 最基本的节点类型是Node,用于抽象地表示文档中一个独立的部分;所有其他类型都继承自Node。
  • Document类型表示整个文档,是一组分层节点的根节点。在JavaScript中,document对象是Document的一个实例。使用document对象,有很多种方式可以查询和取得节点。
  • Element节点表示文档中的所有HTML或XML元素,可以用来操作这些元素的内容和特性。
  • 另外还有一些节点类型,分别表示文本内容、注释、文档类型、CDATA区域和文档片段。

访问DOM的操作在多数情况下都很直观,不过在处理<script>和<style>元素时还是存在一些复杂性。由于这两个元素分别包含脚本和样式信息,因此浏览器通常会将它们与其他元素区别对待。这些区别导致了在针对这些元素使用innerHTML时,以及在创建新元素时的一些问题。

理解DOM的关键,就是理解DOM对性能的影响。DOM操作往往是JavaScript程序中开销最大的部分,而因访问NodeList导致的问题最多。NodeList对象都是“动态的”,这就意味着每次访问NodeList对象,都会运行一次查询。有鉴于此,最好的办法就是尽量减少DOM操作。

第11章 DOM扩展

虽然DOM为与XML及HTML文档交互制定了一系列核心API,但仍然有几个规范对标准的DOM进行了扩展。这些扩展中有很多原来是浏览器专有的,但后来成为了事实标准,于是其他浏览器也都提供了相同的实现。本章介绍的三个这方面的规范如下。

  • Selectors API,定义了两个方法,让开发人员能够基于CSS选择符从DOM中取得元素,这两个方法是querySelector()和querySelectorAll()。
  • Element Traversal,为DOM元素定义了额外的属性,让开发人员能够更方便地从一个元素跳到另一个元素。之所以会出现这个扩展,是因为浏览器处理DOM元素间空白符的方式不一样。
  • HTML5,为标准的DOM定义了很多扩展功能。其中包括在innerHTML属性这样的事实标准基础上提供的标准定义,以及为管理焦点、设置字符集、滚动页面而规定的扩展API。

虽然目前DOM扩展的数量还不多,但随着Web技术的发展,相信一定还会涌现出更多扩展来。很多浏览器都在试验专有的扩展,而这些扩展一旦获得认可,就能成为“伪”标准,甚至会被收录到规范的更新版本中。

第12章 DOM2和DOM3

DOM2级规范定义了一些模块,用于增强DOM1级。“DOM2级核心”为不同的DOM类型引入了一些与XML命名空间有关的方法。这些变化只在使用XML或XHTML文档时才有用;对于HTML文档没有实际意义。除了与XML命名空间有关的方法外,“DOM2级核心”还定义了以编程方式创建Document实例的方法,也支持了创建DocumentType对象。

“DOM2级样式”模块主要针对操作元素的样式信息而开发,其特性简要总结如下。

  • 每个元素都有一个关联的style对象,可以用来确定和修改行内的样式。
  • 要确定某个元素的计算样式(包括应用给它的所有CSS规则),可以使用getComputedStyle()方法。
  • IT不支持getComputedStyle()方法,但为所有元素都提供了能够返回相同信息currentStyle属性。
  • 可以通过document.styleSheets集合访问样式表。
  • 除IE之外的所有浏览器都支持针对样式表的这个接口,IE也为几乎所有相应的DOM功能提供了自己的一套属性和方法。

“DOM2级遍历和范围”模块提供了与DOM结构交互的不同方式,简要总结如下。

  • 遍历即使用NodeIterator或TreeWalker对DOM执行深度优先的遍历。
  • NodeIterator是一个简单的接口,只允许以一个节点的步幅前后移动。而TreeWalker在提供相同功能的同时,还支持在DOM结构的各个方向上移动,包括父节点、同辈节点和子节点等方向。
  • 范围是选择DOM结构中特定部分,然后再执行相应操作的一种手段。
  • 使用范围选区可以在删除文档中某些部分的同时,保持文档结构的格式良好,或者复制文档中的相应部分。
  • IE8及更早版本不支持“DOM2级遍历和范围”模块,但它提供了一个专有的文本范围对象,可以用来完成简单的基于文本的范围操作。IE9完全支持DOM遍历。

JS面试题总结

JS面试题总结

以下面试题来自砖家个人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的时候,就可以执行对应的事件了,然后终止循环。

那什么样的事件可以用事件委托,什么样的事件不可以用呢?

  • 适合用事件委托的事件:click,mousedown,mouseup,keydown,keyup,keypress。
  • mouseover和mouseout虽然也有事件冒泡,但是处理它们的时候需要特别的注意,因为需要经常计算它们的位置,处理起来不太容易。
  • focus,blur之类的,本身就没用冒泡的特性,自然就不能用事件委托了。

请解释JavaScript 中this 是如何工作的

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
  • this 永远指向函数运行时所在的对象,而不是函数创建时所在的对象
  • 匿名函数和不处于任何对象中的函数,This指向window
  • call, apply, with指的This是谁就是谁
  • 普通函数调用,函数被谁调用,This就指向谁

javascript继承(以下代码来自JS高级编程)

  • 原型链
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);
}

javascript模块化

commonJS

CommonJS定义模块分为:模块引用(require)、模块导出(exports)、模块标识(module)。浏览器不兼容CommomJS的原因是因为缺少node环境的四个变量:

  • module
  • exports
  • require
  • global

模块加载原理:

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)

  • 本地对象就是 ECMA-262 定义的类(引用类型)
  • 所有非本地对象都是宿主对象(host object),即由 ECMAScript 实现的宿主环境提供的对象。

请指出以下代码的区别:function Person(){}、var person = Person()、var person = new Person()?

  • 定义了一个 Person 函数
  • 定义了一个 person 变量,同时将 Person 函数的返回结果赋值给它
  • 将 Person 当成一个构造函数,使用 new 操作符创建一个 Person 实例并赋值给 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()

  1. 加载外部脚本的时候可以使用该方法,例如:
<script>
document.write('<link  rel="stylesheet" href="xxx.css">');
</script>
  1. 在新的窗口中写入新的页面数据时,由于document.write会重写整个页面,异步调用会影响本页面的文档,如果在新窗口空白页调用,就没影响了。(由于带来的弊端较多,一般不建议使用。要对DOM进行操作时,还是应当使用安全且对DOM的友好的API方法,以避免不必要的问题出现。)
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]));

HTML和CSS面试题总结

HTML和CSS面试题

以下面试题来自砖家个人blog的总结,希望大家都去看一下砖家的blog,总结的特别好。

以下面试题的答案还在完善中,每个人的答案都不一样,这些仅仅是个人搜集的一些总结,不正确的地方还请大家指正。

Html

DOCTYPE(文档类型)的作用是什么?

可以使用不同的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-*可以解决自定义属性混乱无管理的现状。

data-*有两种设置方式,可以直接在HTML元素标签上书写

<div id="test" data-age="24">
    click here
</div>

HTML5中元素都会有一个dataset的属性,这是一个DOMStringMap类型的键值对集合

var test = document.getElementById('test');
test.dataset.my = 'Byron';

如果把HTML5看作一个开放平台,它的构建模块有哪些?

标签及属性
地理位置
画布
视频
音频
拖放
微数据
应用缓存
Web存储
web workers
服务器发送事件

cookies,sessionStorage和localStorage的区别?

为了持久化存储一些有用的数据,对于网络化编程,一般将这项任务交给了服务器端的数据库或者浏览器端的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 async> 和 <script defer> 的区别

script 当页面解析到script标签时,会停止解析并下载对应的脚本,并马上执行,执行完后再继续解析页面。

script async 在下载脚本的同时不会停止对页面的解析,但是在下载完成之后会停止解析并开始执行,执行完毕后继续解析页面。

script defer 下载时跟async一样不会停止解析页面,下载完毕后会延迟到页面解析完后执行。

async和defer都只对外部脚本有效,IE7及更早的版本对嵌入脚本也支持defer;另外,HTML5规范中,defer要按照顺序执行,但实际上defer跟async都不一定会按照顺序执行。

通常推荐将CSS 放在之间,而将JS <script>放置在之前,有哪些例外?

如果把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和XHTML的区别?

为了规范HTML,W3C结合XML制定了XHTML1.0标准,这个标准没有增加任何新的tag,只是按照XML的要求规范HTML。

XHTML中的标签都必须被正确地嵌套,HTML中的某些标签可以彼此不正确的嵌套。

XHTML中的所有标签必须要关闭。

XHTML中规范定义:标签名和属性对大小写敏感,所有XHTML标签名必须用小写字母。

XHTML文档必须有根元素。

XHTML中标签属性值要使用双引号。

HTML5新标签

  1. header 页眉(网页的头部 顶部 导航区域等等),闭合标签;块元素,默认的宽:100%;高:内容的高度;实质上跟DIV标签完全一样。

  2. nav 导航链接部分,闭合标签;块元素,默认的宽:100%;高:内容的高度;实质上跟DIV标签完全一样。

  3. section 标签定义网页中的区域(部分)。比如章节、页眉、页脚或文档中的其他部分。闭合标签;块元素,默认的宽:100%;高:内容的高度;实质上跟DIV标签完全一样。

  4. footer 页脚(网页的底部,版权区域等等),闭合标签;块元素,默认的宽:100%;高:内容的高度;实质上跟DIV标签完全一样。

  5. article 内容是引用其他地方的。一个区域中的另外一部分内容;块元素,默认的宽:100%;高:内容的高度;实质上跟DIV标签完全一样。

  6. aside跟article是一起使用;辅助article区域的内容。可以理解为整个网页的辅助区域(京东右侧的工具栏)

  7. hgroup 给标题分组,为标题或者子标题进行分组,通常与h1-h6元素组合使用。闭合标签;块元素,默认的宽:100%;高:内容的高度;实质上跟DIV标签完全一样。

  8. figure 对多个元素进行组合。通常与figcaption联合使用。闭合标签;块元素,默认的宽:100%;高:内容的高度;实质上跟DIV标签完全一样。ficaption定义figure元素组的标题,必须写在figure元素中。一个figure元素内最多只允许放置一个figcaption元素。闭合标签;块元素,默认的宽:100%;高:内容的高度;实质上跟DIV标签完全一样。

  9. audio 播放声音文件,比如音乐或者其它音频流。可以在开始标签和结束标签之间放置文本内容,这样老的浏览器就可以显示出不支持该标签的信息。闭合标签;行内元素;默认的宽:controls的宽度300px;高:controls的高度32px;autoplay属性,音频在就绪后马上播放。controls属性,向用户显示控件,比如播放按钮。preload属性,音频在页面加载时进行加载,并预备播放,如果使用autoplay则忽略该属性。src url要播放音频的URL。

  10. video 播放视频文件,比如电影或其它视频流。可以在开始标签和结束标签之间放置文本内容,这样老的浏览器就可以显示出不支持该标签的信息。闭合标签;行内元素;默认的宽:300px 高:150px。autoplay属性,视频就绪后马上播放。controls属性,向用户显示控件,比如播放按钮。height设置视频播放器的高度。loop属性,媒介文件播放后再次开始播放。preload属性,视频在页面加载时进行加载,并预备播放,如果使用autoplay,则忽略该属性。src url 要播放的视频的URL。width设置视频播放器的宽度。

  11. source 为媒介元素(比如video和audio)指定多个播放格式与编码,浏览器会自动选择一个可以识别的格式。非闭合标签,只有开始标签,没有结束标签。source行内元素,默认无宽度和高度。media定义媒介资源的类型,供浏览器决定是否下载。src媒介的URL。type定义播放器在音频流中的什么位置开始播放。默认,音频从头播放。

  12. canvas 定义图形,比如图表和其他图像。闭合标签;行内元素;默认情况下,canvas创建的画布宽:300px 高:150px

  13. datalist 定义可选数据的列表。与input元素配合使用,就可以制作出输入值的下拉列表。闭合标签;行内元素;默认无宽度和高度。

  14. embed 定义嵌入的内容,比如插件。用来插入各种多媒体,格式可以是MIDI、MP3等。非闭合标签,只有开始标签,没有结束标签。行内元素,默认的宽:300px;高:150px

  15. time 定义日期或时间,或者两者。闭合标签;行内元素,默认情况宽:内容的宽度,高:内容的高度。

  16. address 为文档或section定义联系信息,比如:电子邮箱、地址、电话、QQ、微信号等。闭合标签;块元素;默认的宽是:100%;高:内容的高度;实质上,跟DIV标签,可以说是完全一样的特性。

  17. map定义客户端的图像映射。图像映射是带有可点击区域的图像。闭合标签;行内元素;默认情况下,无宽度和高度。

  18. area area 元素永远嵌套在 map 元素内部。area 元素可定义图像映射中的区域。闭合标签,行内元素;只有结束标签,没有开始标签。默认情况下,无宽度和高度。

  19. mark定义页面中需要突出显示或高亮显示的内容,通常在引用原文时,使用此元素,目的就是引起当前用户的注意。闭合标签;行内元素;默认情况下,宽:内容的宽度;高:内容的高度。

  20. details 标签定义元素的细节,用户可进行查看,或通过点击进行隐藏。(备注信息),块元素;默认的宽是:100%;高:内容的高度;实质上,跟DIV标签,可以说是完全一样的特性;但是有一个动态的效果,点击可以显示(展开)内容,再点击可以隐藏(收起)内容。

CSS

CSS 中类和ID的区别

  1. ID选择器只能在文档中使用一次,类可以使用多次。
  2. 可以使用类选择器列表方法为一个元素同时设置多个样式。ID选择器不行。
  3. 书写不同

请问 "resetting" 和 "normalizing" CSS 之间的区别?你会如何选择,为什么?

Normalize 相对「平和」,注重通用的方案,重置掉该重置的样式,保留有用的 user agent 样式,同时进行一些 bug 的修复,这点是 reset 所缺乏的。

Reset 相对「暴力」,不管你有没有用,统统重置成一样的效果,且影响的范围很大,讲求跨浏览器的一致性。

Normalize.css是一种CSS reset的替代方案。它们的区别有:

  1. Normalize.css 保护了有价值的默认值,Reset通过为几乎所有的元素施加默认样式,强行使得元素有相同的视觉效果。相比之下,Normalize.css保持了许多默认的浏览器样式。这就意味着你不用再为所有公共的排版元素重新设置样式。当一个元素在不同的浏览器中有不同的默认值时,Normalize.css会力求让这些样式保持一致并尽可能与现代标准相符合。
  2. Normalize.css 修复了浏览器的bug,它修复了常见的桌面端和移动端浏览器的bug。这往往超出了Reset所能做到的范畴。关于这一点,Normalize.css修复的问题包含了HTML5元素的显示设置、预格式化文字的font-size问题、在IE9中SVG的溢出、许多出现在各浏览器和操作系统中的与表单相关的bug。
  3. Normalize.css 不会让你的调试工具变的杂乱
  4. Normalize.css 是模块化的
  5. Normalize.css 拥有详细的文档

选择Normalize.css ,主要是reset.css为几乎所有的元素施加默认样式,所以需要对所有公共的排版元素重新设置样式,这是一件很麻烦的工作。

请解释浮动 (Floats) 及其工作原理

float属性定义了元素是否浮动及在哪个方向浮动,在CSS中任何元素都可以浮动,且浮动元素会生成一个块级框,而不论它本身是何种元素。并且盒子的宽度不在伸展,而是根据盒子里面的内容的宽度来确定。浮动属性会使得浮动的元素脱离文档流,所以文档的普通流中的块框会表现的像浮动框不存在一样。

清除浮动

  1. 父级div定义伪类:after和zoom(重要)
<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浮动问题

  1. 在结尾处添加空div标签clear:both
<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能自动获取到高度

  1. 父级div定义height

原理:手动定义height,就解决了父级div无法自动获取高度的问题。

  1. 父级div定义overflow:hidden

原理:必须定义width或zoom:1,同时不能定义height,使用overflow:hidden时,浏览器会自动检查浮动区域的高度

  1. 父级div定义overflow:auto

原理:必须定义width或zoom:1,同时不能定义height,使用overflow:auto时,浏览器会自动检查浮动区域的高度

  1. 父级div也一起浮动

原理:所有代码一起浮动,就变成了一个整体

  1. 父级div定义display:table

原理:将div属性变成表格

描述z-index和叠加上下文是如何形成的

首先来看在CSS中叠加上下文形成的原因:

  1. 负边距

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(Block Formatting Context)直译为“块级格式化上下文”。

定义:一个块级格式化上下文[BFC]是可视化CSS渲染网页的一部分,它是一个区域,块级布局,相互浮动在这个区域发生。它决定了元素如何对其内容进行定位,以及与其他元素的关系和相互作用。

  • 有哪些方式能够触发BFC模式?
  1. 根元素(根元素可产生独立BFC)
  2. float属性不为none(总结为 脱离文档流)
  3. position为absolute或fixed(总结为 脱离文档流)
  4. display为inline-block、table-cell、flex、inline-flex
  5. overflow不为visible
  • BFC有哪些应用?
  1. 清除内部浮动

我们在布局时经常会遇到这个问题:对子元素设置浮动后,父元素会发生高度塌陷,也就是父元素的高度变为0。解决这个问题,只需要把把父元素变成一个BFC就行了。常用的办法是给父元素设置OVERFLOW:HIDDEN。

  1. 垂直margin合并

在CSS当中,相邻的两个盒子的外边距可以结合成一个单独的外边距。这种合并外边距的方式被称为折叠,并且因而所结合成的外边距称为折叠外边距。

折叠的结果:

两个相邻的外边距都是正数时,折叠结果是它们两者之间较大的值。

两个外边距一正一负时,折叠结果是两者的相加的和。这个同样可以利用BFC解决。

CSS sprites

CSS Sprites是一种网页图片应用处理方式,就是把网页中一些背景图片整合到一张图片文件中,再利用CSS的“background-image”,“background- repeat”,“background-position”的组合进行背景定位。

  • 优点
  1. 减少网页的http请求,提高性能,这也是CSS Sprites最大的优点,也是其被广泛传播和应用的主要原因;
  2. 减少图片的字节:多张图片合并成1张图片的字节小于多张图片的字节总和;
  3. 减少了命名困扰:只需对一张集合的图片命名,不需要对每一个小元素进行命名提高制作效率;
  4. 更换风格方便:只需要在一张或少张图片上修改图片的颜色或样式,整个网页的风格就可以改变,维护起来更加方便。
  • 缺点
  1. 图片合成比较麻烦;
  2. 背景设置时,需要得到每一个背景单元的精确位置;
  3. 维护合成图片时,最好只是往下加图片,而不要更改已有图片。

图片替换文字方案

  • 伪对象覆盖方法
.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>
  • Hidden Text 取代 -9999px 的方法
.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>

你会如何解决特定浏览器的样式问题?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.