前端梳理

前端知识体系大体上可分为JavaScript、HTML、CSS以及浏览器的实现原理和API

JavaScript

数据类型

JavaScript的数据类型有7种语言类型 Undefined、Null、Boolean、String、Number、Symbol、Object。

undefined和NULL

Undefined 类型表示未定义,它的类型只有一个值,就是 undefined。任何变量在赋值前是 Undefined 类型、值为 undefined,一般我们可以用全局变量 undefined(就是名为 undefined 的这个变量)来表达这个值,或者 void 运算来把任意一个表达式变成 undefined 值
Undefined 跟 Null 有一定的表意差别,Null 表示的是:“定义了但是为空”。
Null 类型也只有一个值,就是 null,它的语义表示空值,undefined是一个变量,与 undefined 不同,null 是 JavaScript 关键字,所以在任何代码中,你都可以放心用 null 关键字来获取 null 值。

为什么有的编程规范要求用 void 0 代替 undefined?

Boolean

Boolean 类型有两个值, true 和 false,它用于表示逻辑意义上的真和假,同样有关键字 true 和 false 来表示两个值。

String

用于表示文本数据类型。
String 有最大长度是 2^53 - 1。所谓最大长度,并不完全是字符数,因为 String 的意义并非“字符串”,而是字符串的 UTF16 编码,我们字符串的操作 charAt、charCodeAt、length 等方法针对的都是 UTF16 编码。所以,字符串的最大长度,实际上是受字符串的编码长度影响的。

Number

  • NaN
  • Infinity,无穷大
  • -Infinity,负无穷大
0.1 + 0.2 为什么不等于0.3 ?

根据浮点数的定义,非整数的 Number 类型无法用 == (=== 也不行)来比较.
实际上,这里错误的不是结论,而是比较的方法,正确的比较方法是使用 JavaScript 提供的最小精度值.检查等式左右两边差的绝对值是否小于最小精度

1
2
console.log( 0.1 + 0.2 == 0.3)
console.log( Math.abs(0.1 + 0.2 - 0.3) <= Number.EPSILON)

Symbol

Symbol 是 ES6 中引入的新类型,它是一切非字符串的对象 key 的集合,在 ES6 规范中,整个对象系统被用 Symbol 重塑

Object

Object是 JavaScript 中最复杂的类型,也是 JavaScript 的核心机制之一。Object 表示对象的意思,它是一切有形和无形物体的总称。
在JavaScript中,对象的定义是”属性的集合”。属性分为数据属性和访问器属性,二者都是 key-value 结构,key 可以是字符串或者 Symbol 类型。

对象的特征
  • 对象具有唯一标识性:即使完全相同的两个对象,也并非同一个对象。
    一般而言,各种语言的对象唯一标识性都是用内存地址来体现的, 对象具有唯一标识的内存地址,所以具有唯一的标识。
  • 对象有状态:对象具有状态,同一对象可能处于不同状态之下。
  • 对象具有行为:即对象的状态,可能因为它的行为产生变迁。
    在 JavaScript 中,将状态和行为统一抽象为属性。
1
2
3
4
5
6
7
var o = { // o 是一个对象

d: 1, // d 是对象o的一个属性
f() { // 函数 f也是对象o的一个属性
console.log(this.d);
}
}
  • 对象具有高度的动态性,因为 JavaScript 赋予了使用者在运行时为对象添改状态和行为的能力。
1
2
3
var o = { a: 1 };
o.b = 2;
console.log(o.a, o.b); //1 2
对象的两类属性

对 JavaScript 来说,属性并非只是简单的名称和值,JavaScript 用一组特征(attribute)来描述属性(property)。

  • 数据属性
    它比较接近于其它语言的属性概念。数据属性具有四个特征:

    1. value:就是属性的值。
    2. writable:决定属性能否被赋值。
    3. enumerable:决定 for in 能否枚举该属性。
    4. configurable:决定该属性能否被删除或者改变特征值。

    在大多数情况下,我们只关心数据属性的值即可。

  • 访问器(getter/setter)属性

    1. getter:函数或 undefined,在取属性值时被调用。
    2. setter:函数或 undefined,在设置属性值时被调用。
    3. enumerable:决定 for in 能否枚举该属性。
    4. configurable:决定该属性能否被删除或者改变特征值。

    访问器属性使得属性在读和写时执行代码,它允许使用者在写和读属性时,得到完全不同的值,它可以视为一种函数的语法糖。

原型
  • 原型系统的“复制操作”思路
    1. 并不是真的去复制一个原型对象,而是使得新对象持有一个原型的引用。
    2. 切实地复制对象,从此两个对象再无关联
  • Js原型系统
    1. 如果所有对象都有私有字段[[prototype]],就是对象的原型。
    2. 读一个属性,如果对象本身没有,则会继续访问对象的原型,直到原型为空或者找到为止。

ES6提供了一系列的内置函数,以便更为直接地访问操纵原型。三个方法分别为:

  1. Object.create 根据指定的原型创建新对象,原型可以是 null
  2. Object.getPrototypeOf 获得一个对象的原型;
  3. Object.setPrototypeOf 设置一个对象的原型。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var cat = {
say() {
console.log('meow!')
},
jump() {
console.log('jump')
}
}

var tiger = Object.create(cat, {
say: {
writable: true,
value: function(){
console.log('roar!')
},
configurable: true,
enumerable: true
}
})

var otherCat = Object.create(cat)
otherCat.say()

var otherTiger = Object.create(tiger)
otherTiger.say()
otherTiger.jump()
new

new 运算接受一个构造器和一组调用参数,实际上做了几件事:

  1. 以构造器的 prototype 属性(注意与私有字段[[prototype]]的区分)为原型,创建新对象;
  2. 将 this 和调用参数传给构造器,执行;
  3. 如果构造器返回的是对象,则返回,否则返回第一步创建的对象。

new 这样的行为,试图让函数对象在语法上跟类变得相似,但是,它客观上提供了两种方式,一是在构造器中添加属性,二是在构造器的 prototype 属性上添加属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function c1(){
// 直接在构造器中修改 this,给 this 添加属性
this.p1 = 1;
this.p2 = function () {
console.log(this.p1)
}
}

var o1 = new c1()
o1.p2()

function c2() {
// 修改构造器的 prototype 属性指向的对象,它是从这个构造器构造出来的所有对象的原型
this.prototype.p1 = 1;
this.prototype.p2 = function () {
console.log(this.p1);
}
}

var o2 = new c2;
o2.p2();
class

在此不再举例赘述,创建对象的方法详见 Js创建对象

类型转换

因为 JS 是弱类型语言,所以类型转换发生非常频繁,大部分我们熟悉的运算都会先进行类型转换。

StringToNumber

字符串到数字的类型转换,存在一个语法结构,类型转换支持十进制、二进制、八进制和十六进制。如30、0b111、0o13、0xFF
此外,JavaScript 支持的字符串语法还包括正负号科学计数法,可以使用大写或者小写的 e 来表示。如 1e3、-1e-2。

NumberToString

在较小的范围内,数字到字符串的转换是完全符合你直觉的十进制表示。当 Number 绝对值较大或者较小时,字符串表示则是使用科学计数法表示的。

装箱转换

每一种基本类型 Number、String、Boolean、Symbol 在对象中都有对应的类,所谓装箱转换,正是把基本类型转换为对应的对象,它是类型转换中一种相当重要的种类。

  • Symbol
    全局的 Symbol 函数无法使用 new 来调用,但我们仍可以利用装箱机制来得到一个 Symbol 对象,我们可以利用一个函数的 call 方法来强迫产生装箱。
1
2
3
4
var symbolObject = (function() {return this}.call(Symbol("a")))
console.log(typeof symbolObject); //object
console.log(symbolObject instanceof Symbol); //true
console.log(symbolObject.constructor == Symbol); //true

对象的分类

宿主对象

由 JavaScript 宿主环境提供的对象,它们的行为完全由宿主环境决定。
如 Date,Boolean,String, Number …等

用对象来模拟函数与构造器:函数对象与构造器对象

内置对象
  • 固有对象
    固有对象是由标准规定,随着 JavaScript 运行时创建而自动创建的对象实例。
    固有对象在任何 JavaScript 代码执行前就已经被创建出来了,它们通常扮演者类似基础库的角色。
  • 原生对象
    我们把 JavaScript 中,能够通过语言本身的构造器创建的对象称作原生对象。

事件循环(EventLoop)

主线程从任务队列中读取事件,整个过程是循环不断的,所以这种整个的运行机制被称为事件循环。

在操作系统中,通常等待的行为就是一个时间循环。

任务队列

任务队列是一个事件的队列。

Js的语言特性是单线程,也就是说,同一时间只能做一件事。意味着所有的事件都需要排队,前一个任务结束,才会执行下一个任务,如果前一个任务耗时很长,那么下一个任务就只能等着。

事件

在Js中,事件分为宏观任务微观任务

宏观任务

由宿主(如浏览器)发起的任务

微观任务

由Js引擎发起的任务

详见Js异步

闭包

闭包可以理解为一个绑定了执行环境的函数

1
2
3
4
5
6
var addNum = (() => {
var nums = 0
return () => {
return nums += 1
}
})()

闭包是一种保护私有变量的机制,在函数执行时形成私有的作用域,保护里面的私有变量不受干扰。直观的说就是形成一个不销毁的栈环境。

表达式

移位算表达式

1
2
3
<< 向左移位
>> 向右移位
>>> 无符号向右移位

移位运算可以把操作数看做二进制表示的整数,然后移动特定的位数。
左移n位就相当于乘以2的n次方,右移n位相当于除以2取整n次方。

HTML

HTML 的功能主要由标签来承担,根据标签的不同作用可大致分为以下几类

文档元信息

通常是出现在 head 标签中的元素,包含了描述文档自身的一些信息。如 title、meta、style、link、base。

语义相关

扩展了纯文本,表达文章结构、不同语言要素的标签。

链接

提供到文档内和文档外的链接

替换型标签

引入声音、图片、视频等外部元素替换自身的一类标签

表单

用于填写和提交信息的一类标签;

表格

表头、表尾、单元格等表格的结构。

CSS

布局类

正常流

弹性布局

绘制类

交互类

浏览器实现原理

解析原理: 解析、构建DOM树、计算CSS、渲染、合成和绘制。

工程实践

性能

工具链

持续集成

构建系统

架构与基础库