写在前面
听闻大佬们在写一些框架或者库的时候,到处都隐藏了一些细节,所以阅读他们的源代码,无论从性能优化、还是JS API的学习、亦或是代码风格等方面给到我们很多启发。这两天我翻看了一下jQuery1.x的源代码,看到了这么一段,着实让我觉得很细节,在这儿和大家分享一下。
不再废话,看代码
看上图,整个jquery的初始化做成被包裹在了一个自执行函数中,这很容易理解,因为自执行函数在执行时创建了自己的作用域,在jquery中声明的变量不小心污染全局空间的可能。
但令人疑惑的是,为什么这个自执行函数还会把window回想作为一个函数参数传进来呢?在自执行函数内部就能访问了window呀 ?
从作用域链谈起
解答上面的问题,其实也不难,这就要提到一个概念: “作用域链”。
JS中函数也是一个对象,函数拥有可以通过代码访问的属性和一系列仅供js引擎访问的内部属性。
其中一个内部属性是[[scope]]。该内部属性包含了函数被创建的作用域中对象的集合,这个集合被称为函数的作用域链,它决定了哪些数据能被函数访问 函数被创建时,它的作用域链中会填入一个全局对象,该全局对象包含了所有全局变量。
执行函数时,会创建一个称为‘运行期上下文’的内部对象,运行期上下文定义了函数执行的环境。每个运行期上下文都有自己的作用域链,用于标识符解析。在解析这些标识符时,JS引擎会沿着自己的作用域链,逐步地往上查找,找到标识符,则停止。
知道了作用域链的查找原理,那么上面的问题也就好回答了:
之所以要把window对象传入自执行函数,是因为jquery源码中,应该存在较多的对window对象的引用,此时就应当把window对象置于作用域链的头部,这样就避免了需要window对象时,需要跳过头部的作用域向上查找,这样有助于提升性能。
再说说 “with”
相信很多人在面试时都会被问到 “为什么不建议使用 with ?”
在这主要由两个原因:
- with 在严格模式下不能使用
- 第二点也就是跟我们上面提到的作用域链有关了。 with 会创建自己的所用域,使得作用域链增长,此时在 with 代码块内部访问外部的变量时,会造成一定的性能损失。
OK,上面就是我想给大家分享的内容。
过年啦!最后祝各位看到文章的朋友们涨薪涨不停!!!