javascript 高级程序设计第四版
什么是javascript
完整的JavaScript包含
语言定义(ECMAScript)、
ECMAScript,即 ECMA-262定义的语言,ECMA-262到底定义了什么?在基本的层面,它描述这门语言的如下部分: 语法 类型 语句 关键字 保留字 操作符 全局对象 ECMAScript 只是对实现这个规范描述的所有方面的一门语言的称呼。JavaScript 实现了 ECMAScript,而 Adobe ActionScript同样也实现了ECMAScript。
文档对象模型(DOM)
提供与网页内容交互的方法和接口
浏览器对象模型(BOM)
提供与浏览器交互的方法和接口
HTML 中的JavaScript
DOMContentLoaded
浏览器已经完全加载了HTML,并构建了DOM树,但是IMG和样式表这样的外部资源并未被加载完成,但其一定会等待script资源加载并运行完成
DOM 已经就绪,因此处理程序可以查找 DOM 节点,并初始化接口
DOMContentLoaded 和脚本
如果HTML文档中存在script标签是,就会等待script下载并运行完成,因为script脚本可能会修改DOM
DOMContentLoaded 和样式
外部样式表不会影响 DOM,因此 DOMContentLoaded 不会等待它们。
如果在样式后面有一个脚本,那么该脚本必须等待样式表加载完成:
<!doctype html><head>// 假设style.css编写了如下样式body {margin-top: 10px;}<link type="text/css" rel="stylesheet" href="style.css"></head><body><script>// 在样式表加载完成之前,脚本都不会执行alert(getComputedStyle(document.body).marginTop); // 10px</script></body>
原因是,脚本可能想要获取元素的坐标和其他与样式相关的属性,如上例所示。因此,它必须等待样式加载完成。
当 **DOMContentLoaded** 等待脚本时,它现在也在等待脚本前面的样式。
defer推迟执行脚本
当我们需要先加载 JavaScript 库,然后再加载依赖于它的脚本时,这可能会很有用。
defer告诉浏览器不需要等待此脚本,继续构建DOM,脚本会在后台下载,DOM构建完成后,脚本才会执行
- defer脚本不会阻塞DOM构建
```…content before script…
…content after script…
- 具有 `defer` 特性的脚本总是要等到 DOM 解析完毕,但在 `DOMContentLoaded` 事件之前执行。**会阻塞**`**DOMContentLoaded**`
…content before scripts…
…content after scripts…
- defer会并行下载,等都下载完成后再按顺序执行<a name="c0eab20f"></a>### [async](https://zh.javascript.info/script-async-defer#async)异步执行脚本> 将独立的第三方脚本集成到页面时,此时采用异步加载方式是非常棒的:计数器,广告等,因为它们不依赖于我们的脚本,我们的脚本也不应该等待它们:- 不会阻塞DOM- 脚本独立,互不等待- DOMContentLoaded也不会相互等待`async` 脚本会在后台加载,并在加载就绪时运行。DOM 和其他脚本不会等待它们,它们也不会等待其它的东西。`async` 脚本就是一个会在加载完成时执行的完全独立的脚本<a name="60e9906a"></a>## 语言基础<a name="ddc7d28b"></a>### 变量<a name="e0417c8d"></a>### var声明提升```javascript// 使用 var 时,下面的代码不会报错。这是因为使用这个关键字声明的变量会自动提升到函数作用域顶部function foo() {console.log(age); var age = 26;}foo();// undefined 之所以不会报错,是因为 ECMAScript 运行时把它看成等价于如下代码:function foo() {var age;console.log(age); age = 26;}foo(); // undefined
let声明
let和var的区别
- 作用域区别
- let声明的是块级作用域

age变量之所以不能在if块外部引用,是因为他的作用域仅限于该块内部
- var声明的是函数作用域

- 冗余声明区别
- let不允许同一块级作用域出现冗余声明
- var允许
作用域提升区别
let不会被提升
// age 不会被提升console.log(age); // ReferenceError:age 没有定义let age = 26;
var会被提升
// name 会被提升console.log(name); // undefinedvar name = 'Matt';
全局声明区别
string
- boolean
- Number
- undefined
- null
- symbol
一种复杂类型
- Object
函数在ECMAScript中被认为是对象,并不代表一种数据类型
typeof
typeof null // object这是因为,null被认为是一个对空对象的引用
值的范围
- 可以表示的最小,数值保存在 Number.MIN_VALUE 中,这个值在多数浏览器中是 5e324;
- 可以表示的最大数值保存在 Number.MAX_VALUE 中,这个值在多数浏览器中是 1.797 693 134 862 315 7e+308。
如果某个计算得到的 数值结果超出了 JavaScript 可以表示的范围,那么这个数值会被自动转换为一个特殊的 Infinity(无 穷)值。
-0/+0 // NaN
如果分子是非 0值,分母是有符号 0或无符号 0,则会返回 Infinity 或-Infinity:```javascriptconsole.log(5/0); // Infinityconsole.log(5/-0); // -Infinity
布尔类型转换
数字类型转换
标签语句
标签语句用于给语句加标签,语法如下: label: statement
下面是一个例子:
start: for (let i = 0; i < count; i++) {console.log(i);}
在这个例子中,start 是一个标签,可以在后面通过 break 或 continue 语句引用。标签语句的
典型应用场景是嵌套循环。
break
let num = 0;outermost:for (let i = 0; i < 10; i++) {for (let j = 0; j < 10; j++) {if (i == 5 && j == 5) {break outermost;}num++;}}console.log(num); // 55
continue ```javascript let num = 0; outermost: for (let i = 0; i < 10; i++) { for (let j = 0; j < 10; j++) { console.log(i, j) if (i == 5 && j == 5) {
continue outermost;
} num++; } } console.log(num); // 95
<a name="F4opa"></a>## 基本引用类型<a name="FSYGq"></a>### 引用类型```javascriptlet date = new Date()// Date()就是引用类型// date 就是实例
原始值包装类型
let a = new String('a')// String() 是原始值包装类型// a 是原始值包装对象
let value = "25";let number = Number(value); // 转型函数console.log(typeof number); // "number"let obj = new Number(value); // 构造函数console.log(typeof obj); // "object"
字符串操作方法
返回子字符串,第一个参数表示子字符串的开始位置,第二个参数表示子字符串的结束位置,,但对substr而言,是需要截取的子字符串数量,不传第二个参数表示截取到末尾
let stringValue = "hello world";console.log(stringValue.slice(3));// "lo world"console.log(stringValue.substring(3)); // "lo world"console.log(stringValue.substr(3));// "lo world"console.log(stringValue.slice(3, 7)); // "lo w"console.log(stringValue.substring(3,7)); // "lo w"console.log(stringValue.substr(3, 7)); // "lo worl" 从索引3开始算,有7个字符串,包含空格,包含索引3
当某个参数是负值时,这 3个方法的行为又有不同。比如,slice()方法将所有负值参数都当成字
符串长度加上负参数值。 而 substr()方法将第一个负参数值当成字符串长度加上该值,将第二个负参数值转换为 0。 substring()方法会将所有负参数值都转换为 0。看下面的例子:
let stringValue = "hello world";console.log(stringValue.slice(-3)); // "rld"console.log(stringValue.substring(-3)); // "hello world"console.log(stringValue.substr(-3)); // "rld"console.log(stringValue.slice(3, -4)); // "lo w"console.log(stringValue.substring(3, -4)); // "hel"console.log(stringValue.substr(3, -4)); // "" (empty string)
