一.<script>元素
首先需要确立一个观念:即js是浏览器的脚本,浏览器并不直接与javacript进行交互,浏览器也不认识js代码。其交互逻辑是:当DOM树生成后,其中有一类节点叫做<script>***</script>,当浏览器中的HTML解析器读取到这类节点后,则会自动调用js引擎解析并执行。翻译并执行js的过程是无法异步的(或者说无法真正意义上的异步,async和defer都只是声明某个script延迟加载而已),因此,在加载javacript资源时,HTML解释器有可能发生阻塞。(加载script资源时,浏览器无法同时做其他事)
根据上图的描述,我们可以知道:在加载script元素时,DOM树是未必完成创建了的。因此,在工程中,一类常见的js报错就是无法获取到DOM对象,这大多数是由于script元素在HTML中的位置所引起的。因此,在真正的开发工程中,为了避免以上两处黑体所描述的问题发生,我们提倡将script标签放在页面底部。这样做的好处是可以保证HTML解释器读取到script标签时,DOM树的构建一定已经完成。
1.<script>元素
简单讲,script标签就是在DOM树中存储javacript代码的地方。他具有六个基本属性:
① async:非必填;代表异步加载script(异步加载的意思在是不阻塞DOM树构建的前提下加载script元素),此属性只对外部引用有效。
② charset:非必填;指定字符集,定义外部js中所使用的字符集类目,例如UTF-8。
③ defer:非必填;与async类似,区别是defer代表的是要求浏览器将其他DOM部分完全解析后,再来加载本脚本。同样只对外部引用有效。
④ language:废弃。
⑤ src:外部js的引用位置。
⑥ type:现代浏览器中非必填;声明该script标签内内容的语言类型,不是很重要,默认值为text/javascript。
script标签有两种使用方式:内嵌或外部引用。外部引用必须通过src取得文件位置,可以是HTML链接(外部域),也可以是文件路径。当浏览器开始解析script标签时,其将自上向下依次解析(这与部分强类型语言不同,例如java,cpp会优先提取代码中的变量,将其升格到作用区域的顶端,再解析语句),在script整个标签的解析完成前,浏览器不会对外释放任何script修改或添加的内容。
另外,当使用外部引用作为script标签时,注意浏览器不会通过src中的后缀名识别js文件,因此,我们便可以通过server端的JSP,PHP动态生成js以供浏览器使用。
另外,当一个HTML文档中存在若干个<script>标签时,如果大家都没有async或defer属性修饰,那么浏览器会从上向下依次加载翻译script标签,换句话说,浏览器是个非常守规矩的学生:他只有把第一道题做完了(加载好一个script标签中的内容),浏览器才会来看第二道题(才来加载第二个script标签)。除非这道题右上角标注了:"这道是压轴题",或者"不做这道题也不影响你做其他题目"(用defer或async修饰)
1.1 script标签的位置
推荐在HTML文档中将script标签放置与<body>标签的底部,原因是浏览器只有加载到body标签时,才会向页面中填充内容,head标签则不会,如果将script标签置于body标签的底部,则会无形中让人们以为页面加载的速度变快了(实际没有,因为大部分script标签是在页面完全填充之后才开始翻译的);
1.2 延迟加载
详细解释一下script标签中defer属性的含义:立刻下载,但延迟翻译(先把理综卷子拿到手,但是其他科目都做完了再做理综)。其执行时间为先于DOMContentLoaded事件发生。同时,多个延迟脚本遵从FIFO的原则,先进先出。
1.3 异步脚本
async和defer的含义相近,但却并不完全相同,区别有以下几点:① 是async不保证多个延迟脚本FIFO,其加载过程是完全随机的。有可能先被执行的<script async = 'async'/>反而后被加载。② 是async一定会在页面的loaded事件前执行,但有可能在DOMContentLoaded事件前后发生。
剩余的1.4 XHTML中的使用以及1.5不推荐写法在工程中使用较少,不多做赘述。
2.嵌入代码与外部文件
一句话解释,建议使用外部文件而不是嵌入代码,理由有三:可维护性;可缓存(多个页面使用相同js,提升加载速度);适应XHTML;
3.文档模式与标准模式
时代的余晖,不多废话了。
4.nosscript标签
一句话解释,当一个浏览器不支持script时(21世纪了,还有浏览器不支持js嘛??),如何避免报错:使用<nosscript>。不支持script的浏览器会自动跳过此标签继续DOM树的加载。
第三章 基本概念
一&&二&&三.基础定义与概念
这部分因为比较简单,且语言与语言之间形态较为相近,我就大致总结一下不多废话了,主要有一下几点:
①js中区分大小写;
②js标识符必须以字母,下划线,美元符号($)开头.
③js建议使用驼峰命名(无论函数还是标识符,都首字母小写,剩下每个有意义的单词首字母大写,例如:hunterMonsterIceborn)
④js的注释为/* ** */ 和 //两种,分别代表块注释和行注释。
⑤严格模式
⑥js结尾不需要分号(当然,你也可以写)
⑦关键字与保留字:见下图(ES5标准)
⑧变量。js中的变量时松散模式,又称弱类型。js的变量仅仅只是一个占位符,他指明在系统内存中的某段地址,针对这段地址的值的分配没有任何要求。你可以将一个原本为string类型的变量随时修改为number,date,or any u want,当然,除非他是被const定义过的常量。
另外,在全局用var定义过的变量是全局变量,而在域内用var定义的变量是局部变量,在函数执行结束后,该变量将被js的垃圾回收机制收回销毁,同时释放内存地址。(这个含糊的写法已经在ES6中通过引入let完成了修正。)。但是同样的,你也可以通过在函数中省略var来直接定义变量,此时即便在函数内定义的变量仍然为全局变量,即便函数运行完成被销毁,该变量仍然可以在全局作用。
四.数据结构
js的数据结构非常简单,在ES3及以下定义中,js有且仅有Undefine,Null,Number,String,Boolean,以及复杂类型Object六种结构。其中Object的本质即是无序的键值对,(类似Python中的dict字典)类似Date,DOM,HTML都是通过这种结构的复杂组成得到的。对了,忘记说了,Array,Function在js中也都是Object。另外,js在ES5和ES6中又添加了一种新的数据结构:Set(当然了,本质也是Object)
1.检测手段typeof
typeof()是js中用来检测字符数据类型的工具函数。
undefine:该变量未定义,但是需要注意,定义了但没有赋值的变量=undefine,未定义的变量则会报错(未分配地址)
boolean/string/number:该变量为布尔型,字符串,数字型
object:该变量为类或Null,特殊值null本质上是一个空的类型引用
function:该变量为函数(函数也是类,暂且不表)
2.几种变量的特殊点
① null类型本质上是一个空对象指针,因此,如果将来想要将一个变量赋值为Object,那么风格建议我们将这个变量设为null;另外,null与undefine的值判断也是值得记录的点:
② boolean类型比较值得记录的是当发生强制类型转换时的转换法则,如下图所示:
③ Number类型可以表示整数和浮点数,其中整数又可以以八进制,十进制,十六进制来表示。但同时也要注意,八进制的写法在严格模式下是无效的。number类型支持用eN来代表科学计数法。有关浮点数,有以下几点可以学习:
<.1的写法是合法的,代表0.1>
<1.的写法是合法的,代表1(整型)>
<10.0的写法是合法的,代表10(整型)>
<浮点数的精度相当堪忧,能不用还是不要用>
④ NaN代表本来要返回一个数字类型,但是因为处理出错而没有正确返回的情况,NaN是一个非常特殊的类型,在js中,任何数字除以0都会返回NaN,除此之外,任何涉及到NaN的计算,都只会返回NaN;而且NaN不与任何值相等,包括他自己。
基于上述的特点,js开发了isNaN()函数,该函数的功能是判断任意一个变量能否转换为NaN,如果可以,返回True,否则返回false,我们可以利用这种特性来进行变量数据类型的确定。