zepto源码阅读笔记(一)

  写在前面:入坑前端已有几年,却一直浮于表面。一直以来,都在忙于追逐日新月异的框架、技术,以及业务代码的编写,却很少深入进去。很多时候都是,知其然,而不知其所以然。最近稍有闲暇,决定读一读常用的开源项目。就从代码量较少,比较简单的zepto开始吧~

 

  废话不多说,直接看代码。以下是zepto v1.2.0源码最外层的结构。

(function(global, factory) {
  //...
}(this, function(window) {
  //...
}))

  可以进一步简化如下:

(function() {
  //...
}())

  初次看到这段代码(或者说初次留意到),我是很疑惑的。最外面的 () 有什么意义?里面的 function(){}() 可以直接执行吗?因为平时都是这样写的:

(function() {
  //...
})()

  一直都是这么理解这段代码的,括号包裹一个匿名函数,然后再加一个括号立即调用该函数。现在才发现这个理解其实是错误的。。。我们先来看看在控制台执行上面两种写法,以及 function(){}() 这句代码会怎样

  为什么会有以上结果呢?此处引出了两个概念:函数声明与函数表达式。

函数声明与函数表达式

  1)函数声明

function sayHello() {
  alert('hello');
}

  2)函数表达式

var sayHello = function () {
  alert('hello');
}

  函数声明必须有标识符(函数名),函数表达式可以没有标识符。比如上面的函数表达式,其过程是先创建了一个匿名函数,再将该函数赋值给一个变量。(这里可能会联想到函数声明提升和变量声明提升的问题,本文暂不讨论。)

  不论是以函数声明还是函数表达式创建的函数,通常都是通过标识符来调用。比如上面两个示例,都会以 sayHello() 来调用。那么我们回头看文章开始提到的两种方式 (function() { //... }())  (function() { //... })() ,它们并没有标识符啊?其实这是两种常见的立即执行函数的方式。

立即执行函数

  假如我们想要定义一个匿名函数,然后立即执行。可能会这么写:function(){ //... }() ,前面已经看到了,我们在控制台执行会报错。为什么呢?因为JavaScript引擎会将这段代码解析为两部分:前面的 function(){ //... } 作为函数声明后面的 () 作为分组表达式。而函数声明括号前面缺少了标识符,所以给出 “Uncaught SyntaxError: Unexpected token ( 这样的错误提示。现在我们为其加上标识符试试看

  这次又提示后面的括号错误,这是因为后面的分组表达式里面为空。我们再为其添加一个表达式

  可以看到,现在终于可以正确执行了。现在我们再来看上面的两种立即执行函数,应该就比较好理解了。不论是 (function() { //... }()) 还是 (function() { //... })() ,其过程都是一个分组表达式返回一个函数再立即执行。现在,总算弄清楚zepto的源码中为什么会那样写,还有平时常用的写法 (function() { //... })()” 了。

  由此引申,想要实现立即执行函数,只要在函数表达式后面加上括号就行。而要将函数转换为函数表达式,就不仅仅局限于分组操作符,还可以用 !运算符,+/-运算符,~运算符等等。

  虽然都能达到转换函数表达式的目的,但是考虑到运算操作总会返回一个结果,和其他代码放在一起,就有可能出现意想不到的情况,所以还是优先使用 () 为好。

 

  (水平有限,欢迎指正~)

posted @ 2017-03-22 16:56  子.鱼  阅读(343)  评论(0编辑  收藏  举报