三座大山
原型与原型链
隐式原型
每个对象都有一个proto属性,指向创建该对象的函数的prototype。

检测类型
判断一个变量是不是对象非常简单。值类型的类型判断用typeof
,引用类型的类型判断用instanceof
。
其中A instanceof B
判断的原理是,沿着A的__proto__
这条线来找,同时沿着B的prototype
这条线来找,如果两条线能找到同一个引用,即同一个对象,那么就返回true。如果找到终点还未重合,则返回false。
这就是应用了隐式原型的原理。
原型链
访问一个对象的属性时,先在基本属性中查找,如果没有,再沿着proto这条链向上找,这就是原型链。
执行环境与作用域
每个函数都有自己的执行环境。当执行刘进入一个函数时,函数的环境就会被推入一个环境占中。而在函数执行后,栈将其环境弹出,把控制权返回给之前的执行环境,
当代码在一个环境中执行时,会创建变量对象的一个作用域链。作用域的前端,始终都是当前执行代码所在环境的变量对象。下一个变量对象来自外部环境,再下一个变量对象来自下一个外部环境。
异步
单线程
JavaScript是单线程语言,HTML5提出Web Worker标准,利用多核CPU的计算能力,允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质。
任务队列
具体来说,异步执行的运行机制如下(同步执行也是如此,因为它可以被视为没有异步任务的异步执行)。
- 所有同步任务都在主线程上执行,形成一个执行栈。
- 主线程之外,还存在一个”任务队列”。只要异步任务有了运行结果,就在”任务队列”之中放置一个事件。
- 一旦”执行栈”中的所有同步任务执行完毕,系统就会读取”任务队列”,看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
- 主线程不断重复上面的第三步。
补充1:定时器
如果将setTimeout()的第二个参数设为0,就表示当前代码执行完(执行栈清空)以后,立即执行(0毫秒间隔)指定的回调函数。总之,setTimeout(fn,0)的含义是,指定某个任务在主线程最早可得的空闲时间执行,也就是说,尽可能早得执行。
它在”任务队列”的尾部添加一个事件,因此要等到同步任务和”任务队列”现有的事件都处理完,才会得到执行。补充2:问题解决
一般遇到异步的问题都会在操作上进行优化。
传递参数
ECMAScript 中所有函数的参数都是按值传递的。即使在函数内部修改了参数的值,但原始的引用仍然保持未变。实际上,当在函数内部重写obj时,这个变量引用的就是一个局部对象了。而这个局部对象会在函数执行完毕后立即被销毁。
没有块级作用域
|
|
这里是在一个if语句中定义了变量color。如果是在C、C++或Java中,color会在if语句执 行完毕后被销毁。但在JavaScript中,if语句中的变量声明会将变量添加到当前的执行环境(在这里是 全局环境)中。
垃圾收集
标记清除
当变量进入环境(例如,在函数中声明一个变量)时,就将这个变量标记为“进入环境”。而当变量离开环境时,则将其标记为“离开环境”。
引用计数
当声明了一个变量并将一个引用类型值赋给该变量时,则这个值的引用次数就是1。如果同一个值又被赋给另一个变量,则该值的引用次数加1。相反,如果包含对这个值引用的变量又取得了另外一个值,则这个值的引用次数减1。当这个值的引用次数变成0时,则说明没有办法再访问这个值了,因而就可以将其占用的内存空间回收回来。
而此种方法会存在循环引用的问题。
检测数组
|
|
数组操作方法
|
|
字符串操作方法
slice和substring的第二个参数指定的是子字符串最后一个字符后面的位置,而substr的第二个参数指定的则是返回的字符个数。
在传递给这些方法的参数是负值的情况下,slice会将传入的负值与字符串的长度相加,substr将负的第一个参数加上字符串的长度,而将负的第二个参数转换为0,substring会把所有负值参数都转换为0。
hasOwnProperty & in
hasOwnProperty只在属性存在于实例中时才返回true,in则在属性存在于实例还是原型中时都返回true。因此同时使用hasOwnProperty和in,就可以确定该属性到底是存在于对象中,还是存在于原型中。
new一个对象的过程
1、创建一个新对象;
2、this指向这个对象;
3、执行代码,即给this赋值;
4、返回this。
继承
原型链继承
|
|
问题:
- 来自原型对象的引用属性是所有实例共享的
- 在创建子类型的实例时,不能向超类型的构造函数中传递参数
借用构造函数
|
|
问题:方法都定义在构造函数,影响函数复用。
组合继承
使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。
组合继承避免了原型链和借用构造函数的缺陷,融合了它们的优点,成为JavaScript中最常用的继承模式。
问题:会调用两次超类型构造函数:一次是在创建子类型原型的时候;另一次是在子类型构造函数内部。
原型式继承
借助原型可以基于已有的对象创建新对象,同时还不必因此创建自定义类型。
ECMAScript5通过新增Object.create()方法规范化了原型式继承。
问题:包含引用类型值的属性会共享相应的值,就像使用原型模式一样。
寄生式继承
|
|
寄生组合式继承
所谓寄生组合式是,使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型。
这个例子的高效率体现在它只调用了一次SuperType构造函数,因此避免了在SubType.prototype上面创建不必要的、多余的属性。
开发人员普遍认为寄生组合式继承是引用类型最理想的继承范式。
闭包
闭包是指有权访问另一个函数作用域中的变量的函数。
闭包直接引用element,会导致DOM对象的引用无法解除,因此有必要把element变量设置为null。
减少全局变量污染
只创建一个唯一的全局变量。
|
|
使用模块
模块模式的一般形式是:一个定义了私有变量和函数的函数;利用闭包创建可以访问私有变量的和函数的特权函数;最后返回这个特权函数,或者把它们保存到一个可访问到的地方。
利用匿名函数
|
|
BOM
获取页面视口大小
|
|
间歇调用和超时调用
一般认为,使用超时调用(setTimeOut)来模拟间歇调用(setInterval)是一种最佳模式,原因是后一个间歇调用可能会在前一个间歇调用结束之前启动。
DOM
DocumentFragment类型
假设我们想为一个ul元素添加三个列表项,可以使用一个文档片段来保存创建的列表项,然后再一次性将它们添加到文档中。
previousElementSibling & previousSibling
|
|
Node.js
单线程
Node.js 采用了单线程模型,它不会为每个接入请求分配一个线程,而是用一个主线程处理所有的请求,然后对 I/O 操作进行异步处理,避开了创建、销毁线程以及在线程间切换所需的开销和复杂性。
CPU密集型任务
- 分给子线程(Web Worker)
- cluster模块
常用小方法
常用正则
匹配url
|
|

匹配数字
|
|

参考
- 阮一峰 — JavaScript运行机制详解:再谈Event Loop
- 亚里士朱德的博客 — js高手进阶之路:underscore源码经典
- GitHub — underscore-1.8.3.js 源码解读