1.2 JavaScript的学习方法
“治大国若烹小鲜”,按照中国的传统文化来讲应该是一通百通。虽然上文介绍的是看地图的方法,但是同样适用于JavaScript以及其他知识和技术的学习。
对于学习JavaScript来说,大致也有跟看地图类似的三种学习方法。第一种是先找到像字典一样的JavaScript资料,然后从头到尾一点一点看;第二种是在遇到问题后直接寻找解决方案;第三种是先整体思考JavaScript是什么、怎么实现的及学习JavaScript的目的,然后再有目标地进行系统学习,最后在脑子里建立起一个整体的框架,并且弄明白每个地方的实现原理,这样就差不多了,当然更重要的是多实践多总结。
对于前两种方法,本书就不多说了。第三种方法虽然看起来很复杂,但是只要大家跟着本书来学习,应该会觉得很轻松,而且在学习完之后对JavaScript的认识应该也会有质的提升,再使用JavaScript的时候会得心应手。
对于第三种学习方法来说,首先要明白为什么需要JavaScript(或者说JavaScript是怎么提出来的)、JavaScript是什么、有什么用,以及它的结构是什么样的?对于这些问题本书将在接下来的两章中给大家介绍。这里先给大家介绍JavaScript的三点特性,让大家对JavaScript有一个整体的认识。
1.2.1 JavaScript是一种面向对象的语言
要理解面向对象首先要明白什么是对象。网页中的一段文字、一个文本框、一张图片、一个样式表规则以及浏览器的导航器等都是对象。另外,JavaScript中也有为了方便操作自身提供的对象,而且可以自定义对象,JavaScript中的函数其实也是一种对象。JavaScript的目的就是要操作这些对象,例如,“把某个文本框的内容清空”,这就是对这个文本框对象进行操作,再例如“返回上一页”就是对导航器这个对象进行操作。只不过JavaScript不是中国人开发的语言,所以它并不认识上面的语句,要想操作某个对象,就必须使用JavaScript所规定的语句才行。从这里可以看出学习JavaScript主要包含以下三方面内容。
▯ JavaScript怎么操作对象。
▯ JavaScript中都包含哪些对象,每一类对象都有些什么功能。
▯ 不同对象之间是什么关系。
1.2.2 JavaScript是一种脚本语言
脚本语言的功能是修改或者称为“操作”,而不是创造,所以,JavaScript并不能从无到有创建出来一个页面,而只能是对页面进行修改(有的读者可能会觉得JavaScript可以在一个空白页面上随意写内容,但那只是对页面进行修改,页面本身是由浏览器创建的,打开新页面也是类似的道理,如果没有浏览器,JavaScript自己是创建不出来页面的)。因此,JavaScript并没有类似于其他语言的入口函数main,真正的入口函数main在浏览器程序中。
脚本语言是一堆命令的集合,一般来说会有一个解释器,由其负责从头到尾一条一条语句进行解释,然后根据解释后的语句含义进行操作。例如“给页面内所有文本框添加一个内容变化监听函数XXX”,如果解释器可以理解这句话,那么它会找到所有文本框,然后添加监听函数,这就叫解释执行。它是由解释器将内容翻译后根据其含义进行相关操作的,即操作最终是由解释器来完成的,而不是将脚本编译为机器码来执行的。
JavaScript是一种比较复杂的脚本语言,它跟编译型语言一样也有自己的变量、函数,其执行过程跟编译器一样首先生成语法树,然后解释器生成一条一条的中间码(类似于“给页面内所有文本框添加一个内容变化监听函数XXX”这样的语句,当然不会是中文,甚至不一定使用文字,只要描述出来含义就可以),最后一条一条执行。
当然,随着前端的功能越来越复杂,如果纯粹按照上述方法来解释执行就会严重影响效率,所以后来有的解释器(这里严格来说已经不能称为解释器了,现在通用的叫法为JavaScript引擎),例如JavaScriptCore、SpiderMonkey会将使用得比较频繁的代码直接编译为CPU所执行的机器码,有的引擎(例如V8)甚至会将所有JavaScript代码全部编译为机器码,这样就类似于编译型语言了。不过,JavaScript引擎还是会在加载网页的时候直接下载源代码,然后编译,最后执行,这对编译速度的要求就更高了。对于我们来说,并不需要过分关注其底层是怎么实现的,只需要明白JavaScript脚本是用于表述对各种对象怎么操作的一种描述就可以了。
1.2.3 JavaScript是一种事件驱动的语言
事件驱动是指JavaScript引擎并不是在看到代码之后就会立即执行,而是会在合适的时间才去执行。这个合适的时间是指当某个事件发生之后(例如一个输入框的内容发生了变化,这就是一个事件)。只有当相应的事件发生了之后,相应的操作才会执行,这就是事件驱动。事件驱动在我们的日常生活中也是比较常见的一种模式。例如,银行的营业员处理业务就是一种事件驱动的模式,只有客户到来的时候才需要提供服务,客户到来就是一个事件。
事件驱动包含三个关键内容:事件、事主和处理方法。对于上述银行的例子来说,客户要办理的业务是事件,营业员是事主,而具体每项业务怎么办理就是处理方法。例如,一个客户找到营业员甲办理存款业务,那么事件是存款,事主是营业员甲,处理方法是营业员具体办理存款的操作,而客户只是触发了这一事件。对于每个营业员来说,在上岗前都需要进行培训,培训在事件模型里就是绑定事件。例如,营业员甲负责存取款业务,营业员乙负责开户办卡业务,这就相当于营业员甲绑定了存取款事件,营业员乙绑定了开户办卡事件,对于没有绑定的事件是无法处理的,就像找营业员甲开户是不可以的。另外,对于同一事件不同的营业员的处理方式也可能不一样,就像同样是开户,但是不同银行的营业员的开户方式可能就不一样。
在事件模型中,我们所要做的就是给需要处理事件的事主绑定处理方法,就像给营业员进行业务培训一样,绑定完事件之后,其他的事情就不需要我们参与了。虽然底层的实现不需要我们来参与,但是明白了底层的实现原理,可以让我们对事件驱动理解得更加深刻。
事件驱动模型在底层一般都是通过队列来实现的,这与在银行窗口前排队差不多。当发生一个事件时就会将其排入队列中,其中写清楚事件是什么、事主是谁,然后事件管理器定时查看队列,如果队列中有事件,那么事件管理器就会找跟事主相关的此类事件的处理方法,如果找不到,该事件就会被丢弃,如果找到就会执行相应的处理方法。这跟银行的排队稍微有点区别,银行的排队是直接排在各自事主(营业员)前面,而事件驱动模型中所有的事件都排在一个队列里,这就像到银行办业务的人都排成一个长队(类似于取号排队,但是不分业务,全部排在一起的那种),然后大堂经理负责安排业务,排队的人需要告诉大堂经理准备到哪个窗口、办理什么业务。当然,直接按照银行的排队模型来实现从技术上来说并非不可以,而且在有的地方确实就是这么实现的,这只是业务和设计的问题。另外,这里所说的只是原理,具体怎么实现还要看开发者是如何设计的,例如,也可以直接将事件处理方法的地址保存到队列中。
理解了事件模型,我们就能明白JavaScript中的代码虽然是用于描述怎么操作对象的,但是并不一定要立即操作对象。
现在从宏观上明白这三点就可以了,至于JavaScript具体是怎么描述对对象的操作、怎么创建对象、自身包含哪些内置对象、对象之间有些什么关系等内容,随后整本书将进行详细介绍。大家带着这些问题去学习接下来的内容,这样学起来会更加轻松,而且也能够理解得更加透彻。
当然,这里介绍的学习方法,接下来还需要大家自己去使用、实践,只有这样才能真正受益,否则仅是学了一种方法而已。例如,虽然笔者知道地图怎么看,但是因为没在这上面花太多精力,所以对很多具体的地图并不熟悉。