第一章 · JavaScript
JavaScript是一门用来与网页交互的脚本语言,包含三个组成部分:
-
核心(ECMAScript):由ECMA-262定义并提供核心功能;
-
文档对象模型(DOM):提供与网页内容交互的方法和接口;
-
浏览器对象模型(BOM):提供与浏览器交互的方法和接口。
JavaScript的这三个部分得到了五大Web浏览器(IE、Chrome、Safari和Opera)不同程度上的支持。所有浏览器基本上对ES5提供了完善的支持,而对ES6和ES7的支持度也在不断提升。这些浏览器对DOM的支持各不相同,但对Level3的支持日益趋于规范。HTML5中收录的BOM会因浏览器而异,不过开发者仍然可以假定存在很大一部分公共特性。
第二章 · HTML中的JavaScript
1、使用script元素
使用src属性的script元素不应该在script标签中包含其他JavaScript代码。如果两者都提供的话,则浏览器只会下载并执行脚本文件,忽略行内代码。src请求不受浏览器同源策略限制,但返回并被执行的JavaScript则受限制,受父页面HTTP/HTTPS协议的限制。
script元素在页面中出现顺序依次解析。
script标签位置建议放在body中页面内容的后面,这样页面会在处理JavaScript代码之前完全渲染页面,用户会感觉页面加载更快了,因为浏览器显示空白页面的时间短了。如果放到head里面会在DOMContentLoaded时间之前执行,需要设置defer属性,但是在HTML5中明确规定,支持HTML5的浏览器会忽略脚本的defer属性。对于XHTML文档,制定defer属性时应该写成defer="defer"。
异步执行脚本:HTML5为script元素定义了async属性。async不保证按照脚本出现顺序执行。
动态加载脚本:通过向DOM中动态添加script元素加载制定脚本,相当于添加了async属性。这种方式获取的资源对浏览器预加载器是不可见的,这会严重影响它们在资源获取队列中的优先级。要想让预加载器知道这些动态文件的存在,可以在文档head显示声明:
```html
<link rel="preload" href="gibberish.js">
XHTML已经退出历史舞台,不在详细说明。
2、行内代码与外部文件
使用外部文件:可维护性、缓存、适应未来。
3、文档模式
IE5.5发明了文档模式的概念,可以使用doctype切换文档模式。发展到现在,文档模式有三种:混杂模式(以省略文档开头的doctype声明作为开关)、标准模式(通过Strict来触发,HTML5中不标记进行声明)和准标准模式(通过过渡性文档类型Transitional和框架集文档类型Frameset来触发)。
前两种模式主要区别体现在CSS渲染的内容页面,但对javascript也有一些关联影响。第三种模式下得浏览器支持很多标准的特性,但是没有标准规定得那么严格。主要区别在于如何对待图片元素周围的空白(在表格中使用图片最明显)。
4、noscript元素
noscript元素可以包含任何出现在body中的HTML元素,除
浏览器显示包含在中的内容有两种情况:浏览器不支持脚本;浏览器对脚本的支持被关闭。
5、小结
JavaScript是通过
- 要包含外部JavaScript文件,必须将src属性设置为要包含文件的URL。文件可以跟网页在同一台服务器上,也可以位于完全不同的域。
- 所有
第三章 · 语言基础
1、语法
-
区分大小写。
-
标识符:第一个字符必须是一个字母、下划线_或者美元符号$;字母、下划线、美元符号或数字组成;关键字、保留字、true、false、null不能作为标识符。
-
注释
// 单行注释
/* 多行
注释*/
- 严格模式
// 在脚本开头加上一行
"use strict";
// 单独制定一个函数在严格模式下执行
function doSomething() {
"use strict";
}
- 语句
语句末尾加分号,便于压缩代码;代码块用{},减少出错的可能性。
2、关键字与保留字
保留的关键字和未来的保留字不能用作标识符或属性名。
ECMA-262第六版规定的关键字:break、do、in、typeof、case、else、instanceof、var、catch、export、new、void、class、extends、return、while、const、finally、super、with、continue、for、switch、yield、dubugger、function、this、default、if、throw、delete、import、try
未来保留字:始终保留(enum)、严格模式下保留(implements、package、public、interface、protected、static、let、private)、模块代码中保留(await)。
3、变量
var:在函数内部定义变量时不带var,可以创建一个全局变量(不推荐,严格模式下会抛出ReferenceError);存在声明提升;无块级作用域。
let:作用范围是块级作用域;不会声明提升(声明之前的执行瞬间被称为暂时性死区);let全局作用域下声明的变量不会称为window对象的属性(var会);for循环中迭代变量的作用域仅限于for循环块内部,使用let声明迭代变量时,JavaScript引擎在后台会为每个迭代循环声明一个新的迭代变量。
const:除了不能改变值(不能改变指向的变量的引用),其他和let一样。
var,let区别实例(闭包):
// 使用var
for(var i = 0; i < 5; i++) {
setTimeout(() => console.log(i), 0)
}
// 输出为5个5
// 使用let
for(let i = 0; i < 5; i++) {
setTimeout(() => console.log(i), 0)
}
// 输出为0/1/2/3/4
4、数据类型
-
简单数据类型:undefined、null、boolean、number(八进制字面量在严格模式下无效,会导致JavaScript引擎抛出语法错误)、string、symbol、NaN;复杂数据类型:object
-
typeof操作符:区分简单数据类型,函数和其他对象,typeof null == “object”。
-
值的范围:最小值(Number.MIN_VALUE),最大值(Number.MAX_VALUE),超出自动转换为Infinity(正无穷大),-Infinity(负无穷大),要确定一个值是不是在此范围内,可以使用isFinite()函数,isNaN()函数判断是否不是数值。
-
数值转换:Number()、parseInt()、parseFloat()。Number()是转型函数,可用于任何数据类型;后两个函数主要用于将字符串转换为数值。
parseInt(“0xAF”, 16)十六进制转换为数值, 如果加第二个参数16的话,0x可以省略:parseInt(“AF”, 16)。
第二个参数是获得的结果类型:2,8,10,16
parseFloat()函数和parseInt()函数类似,但是parseFloat()只解析十进制值,不能指定底数。
-
toString()转换为字符串:null和undefined值没有toString()方法,可以用String()强制类型转换,返回值为"null"、“undefined”。
在对数值调用这个方法时,toString()可以接收一个底数参数,即以什么底数来输出数值的字符串表示。
参数:2,8,10,16,不传的时候表示是10进制的。
-
模板字符串:嵌套的模板字符串无需转义。
模板字面量标签函数:标签函数接收到的参数依次是原始字符串数组和对每个表达式求值的结果。这个函数的返回值是对模板字面量求值得到的字符串。
let a = 6; let b = 9; function simpleTag(strings, aValExpression, bValExpression, sumExpression) { console.log(strings); console.log(aValExpression); console.log(bValExpression); console.log(sumExpression); return 'foobar'; } let untaggedResult = `${a} + ${b} = ${a + b}`; let taggedResult = simpleTag`${a} + ${b} = ${a + b}`; // 输出 // ["", " + ", " = ", ""] // 6 // 9 // 15 console.log(untaggedResult); // "6 + 9 = 15" console.log(taggedResult;) // "foobar"
原始字符串: String.raw标签函数,直接返回原始的模板字面量内容,而不是转换后的字符表示。
// Unicode示例 // \u00A9 是版权符号 console.log(`\u00A9`); // © console.log(String.raw`\u00A9`); // \u00A9
-
Symbol:符号是原始值,且符号实例是唯一的、不可变的。符号的用途是确保对象属性使用唯一标识符,不会发生属性冲突的危险。
符号没有字面量语法,这也是它们发挥作用的关键。按照规范,你只要创建Symbol()实例并将其用作对象的新属性,就可以保证它不会覆盖已有的对象属性,无论是符号属性还是字符串属性。
Symbol()函数不能与new关键字一起作为构造函数使用。这样做是为了避免符号包装对象,像使用Boolean、String或Number那样,它们都支持构造函数且可用初始化包含原始值的包装对象。如果确实想使用符号包装对象,可以借用Object()函数。Object(Symbol())
使用全局符号注册表:Symbol.for()方法;
Symbol.keyFor()来查询全局注册表,这个方法接收符号,返回该全局符号对应的字符串键。如果查询的不是全局符号,则返回undefined。
// 创建全局符号 let s = Symbol.for("foo"); console.log(Symbol.keyFor(s)); // foo // 创建普通符号 let s2 = Symbol("bar"); console.log(Symbol.keyFor(s2)); // undefined
如果传给Symbol.keyFor()到不是符号,则抛出TypeError。
凡是可以使用字符串或数值作为属性的地方,都可以使用符号。这就包括了字面量属性和Object.defineProperty()/Object.defineProperties()定义的属性。对象字面量只能在计算属性语法中使用符号作为属性。
类似于 Object.getOwnPropertyNames()返回对象实例的常规属性数组,Object.getOwnPropertySymbols()返回对象实例的符号属性数组。这两个方法的返回值彼此互斥。Object.getOwnPropertyDescriptors()会返回同时包含常规和符号属性描述符的对象。Reflect.ownKeys()会返回两种类型
的键。
因为符号属性是对内存中符号的一个引用,所以直接创建并用作属性的符号不会丢失。但是,如果没有显示的保存对这些属性的引用,那么必须遍历对象的所有符号属性才能找到对应的属性键。
Symbol.iterator: @@iterator内置符号。这个符号作为一个属性表示“一个方法,该方法返回对象默认的迭代器。有for-of语句使用”。
Symbol.asyncIterator表示实现异步迭代器API的函数。最新版本的浏览器支持。
Symbol.hasInstance:这个符号作为一个属性表示“一个方法,该方法决定一个构造器对象是否认可一个对象是它的实例。由instanceof操作符使用”。instanceof操作符可以用来确定一个对象实例的原型链上是否有原型。instanceof使用场景:在ES6中,instanceof操作符会使用Symbol.hasInstance函数来确定关系;这个属性定义在Function的原型上,因此默认在所有函数和类上都可以调用。
Symbol.isConcatSpreadable:这个符号作为一个属性表示“一个布尔值,如果是true,则意味着对象应该用Array.prototype.concat()打平其数组元素”。
Symbol.match:这个符号作为一个属性表示“一个正则表达式方法,该方法用正则表达式去匹配字符串。由String.prototype.match()方法使用”。
Symbol.replace:这个符号作为一个属性表示“一个正则表达式方法,该方法替换一个字符串中匹配的子串。由String.prototype.replace()方法使用”。
Symbol.search:这个符号作为一个属性表示”一个正则表达式方法,该方法返回字符串中匹配表达式的索引“。
Symbol.species:这个符号作为一个属性表示“一个函数值,该函数作为创建派生对象的构造函数”。
Symbol.split:这个符号作为一个属性表示“一个正则表达式方法,该方法在匹配正则表达式的索引位置拆分字符串。由String.prototype.split()方法使用”。
Symbol.toPrimitive:这个符号作为一个属性表示“一个方法,该方法将对象转换为相应的原始值。由ToPrimitive抽象操作使用”。
Symbol.toStringTag:这个符号作为一个属性表示“一个字符串,该字符串用于创建对象的默认字符串描述。有内置方法Object.prototype.toString()使用”。
Symbol.unscopables:这个符号作为一个属性表示“一个对象,该对象所有的以及继承的属性,都会从关联对象的width环境绑定中排除”。
5、操作符
数学操作符、关系操作符、逻辑操作符。
- 一元操作符:自增自减、一元加和减(加号放到非数值前面,会使用Number()转换,减号放到前面是负值);
- 位操作符:按位非~(对数值取反并减一)、按位与&、按位或|、按位异或^、左移<<、有符号右移>>、无符号右移>>>
- 布尔操作符:逻辑非!、逻辑与&&、逻辑或||
- 乘性操作符:乘法操作符*、除法操作符/、取模操作符%
- 指数操作符:Math.pow()、 **
- 加性操作符:加法操作符、减法操作符
- 关系操作符:<、>、<=、>=、、!=、=、!==
- 条件操作符:?:
- 赋值操作符:=、*=、/=、%=、+=、-=、<<=、>>=、>>>=
- 逗号操作符
6、语句
- if
- do-while
- while
- for
- for-in
- for-of
- 标签语句
- break和continue
- with:严格模式不能使用
- switch
7、函数
严格模式对函数也有一些限制:
函数不能以eval或者arguments作为名称;
函数的参数不能叫eval或arguments;
两个命名参数不能拥有同一个名称。