浏览器

Mosaic 是互联网历史上第一个获普遍使用和能够显示图片的网页浏览器。于 1993 年问世。

浏览器组成:

  1. shell (外形)部分
  2. 内核部分:渲染引擎(语法规则和渲染),js 引擎,其他模块

主流浏览器及其内核:

  1. IE -> Trident
  2. Chrome -> Blink
  3. Opera -> Blink
  4. Safari -> Webkit
  5. Firefox -> Gecko

2001 年的 IE6 浏览器,首次实现对 JavaScript 引擎的优化和分离。

2008 年 Google 发布最新浏览器 Chrome,它是采用优化后的 JavaScript 引擎,引擎代号 V8,因能把 JavaScript 代码直接转化为机械码来执行,进而以速度快而闻名。

了解 JavaScript

分类

编译型:C、C++ 等语言需要一个编译器(compiler)。编译器是一种程序,能够把用 Java 等高级语言编写出来的源代码翻译为直接在计算机上执行的文件。

解释型:不需要编译器,它们只需要解释器。对于 JavaScript,浏览器负责完成有关的解释和执行工作。

编程形式

  1. 面向过程:C

  2. 面向对象:Java、C++

  3. 既面向对象也面向过程:JavaScript

特点

  1. 解释型语言 — (不需要编译成文件)跨平台。

  2. 单线程 — 同一时间只能干一件事。

  3. 弱类型语言 — 存放的数据类型可变。

组成部分

我们把 JavaScript 中的核心部分称为 ECMAScript,加上 BOM(浏览器对象模型)与 DOM(文档对象类型),三者共同组成了 JavaScript。

  1. ECMA-262 标准规定了这门语言的如下组成部分:语法、类型、语句、关键字、保留字、操作符、对象。
  2. 浏览器对象模型(BOM,Browser Object Model),提供与浏览器交互的方法和接口。
  3. 文档对象内容(DOM,Document Object Model),提供访问和操作网页内容的方法和接口。

执行队列

执行队列(过程):轮转时间片。

  1. 单线程模拟多线程。
  2. 类似吃饭,吃一口米饭,吃一口茄子,再吃一口排骨,再吃一口米饭,再吃一口米饭,再吃一口茄子,顺序完全随机,在足够快的时间内,肉眼可见菜和饭在同时减少。
  3. 比如 js 引擎要执行任务 1 和任务 2,js 引擎会把任务 1 和任务 2 切成无数个片段,然后把这些片段随机排成一个队列送入引擎执行,直到被执行完。

异步(asynchronous):同时执行,类似于有很多条路一起走,可以同时出发。
同步(synchronous):分次执行,类似于只有一条路走,这个走完了下个才能走。

引入

引入方法:

  1. 页面内嵌<script></script>标签

  2. 外部引入<script src=location></script>

页面中,可以存在多个<script>标签,执行顺序从上到下。只要不存在 defer 和 async 属性,浏览器都会按照 它们在页面中出现的先后顺序依次进行解析。

传统的做法是所有<script>标签都放在<head>中,这意味着必须等到全部 js 代码都被下载、解析和执行完成以后,才能开始呈现页面的内容(浏览器在遇到<body>标签时才开始呈现内容)。

为了避免这个问题,现代 Web 应用程序一般都把全部 js 引用放在<body>中页面内容的后面。这样,在解析包含的 js 代码之前,页面的内容将完全呈现在浏览器中。而用户也会因为浏览器窗口显示空白页面的时间缩短而感到打开页面的速度加快了。

为符合 Web 标准中结构、样式、行为相分离的原则,通常会采用外部引入。

如果有外部 js 文件,那么这个 script 标签里如果再写 js 代码,也是不会执行的,会被直接忽略。
基于这个特性,在开发时偶尔会用来存储一些代码。
在下面再写一个 script 标签,然后里面写代码是可以的。

计算

JavaScript 可正常计算的范围:小数点前 16 位,后 16 位。

js 计算精度不准,是纯粹的 bug,所以在 js 中应尽量避免小数操作。

1
2
3
var num = 0.14 * 100;

console.log(num); // 14.000000000000002

如果需要计算,那么采用Math.floor()(向下取整)或Math.ceil()(向上取整)方法。

1
2
3
4
5
6
7
8
9
// 向上取整,无论小数是多少,都向前进 1
var num = Math.ceil(123.234);

console.log(num); // 124

// 向下取整,无论小数是多少,都不要了
var num1 = Math.floor(123.999);

console.log(num1); // 123

Math.random()方法可以随机产生一个 0 ~ 1 之间的开区间的数。

1
2
3
4
5
var num = Math.random();

console.log(num); // 0.4322440432127299

console.log(num); // 0.5216225452503296

toFixed()方法可以把 Number 四舍五入为指定小数位数的数字。

1
2
3
4
5
var num = 123.45678;

demo = num.toFixed(2);

console.log(demo); // 123.46

变量(variable)

变量声明

1
2
3
4
5
6
7
// 声明、赋值分解
var a;
a = 1;

// 单一 var
var c = 2,
b = 4;

开发规范:单一 var 模式,每个变量用逗号隔开,同时换行。

命名规则:

  1. 变量名必须以英文字母_$开头
  2. 变量名可以包括英文字母_$数字
  3. 不可以用系统的关键字、保留字作为变量名。

语句基本规则

语句后面要用分号;结束。注意,下列三种语句不用加分号:

  1. 函数: function test() {}
  2. for 循环:for() {}
  3. if 语句:if() {}

一个 HTML 文件中可以放多个 JS 代码块,代码块内的规则可以互通。如果某个代码块内出现 JS 语法错误,会引发该代码块内的后续代码终止,但不会影响其他 JS 代码块,目前有两种错误:

  1. 低级错误:语法解析错误,整个代码块都不会执行。
    如:使用了中文标点符号:Uncaught Syntax Error: ……
  2. 逻辑错误:标准错误,会执行到该代码块最后一行正确代码再终止。
    如:没有声明变量,直接使用:Uncaught Reference Error: ……

书写格式要规范,= + / -两边都应该有空格。

运算符

算术运算符

+:

  • 数学运算。
  • 字符串连接:任何数据类型加字符串都等于字符串。
1
2
3
4
5
6
7
// 从左至右运算
// 1+1 数字运算,得 2
// 2+'a' 字符串连接,得 2a
// '2a'+1 字符串连接,得 2a1
// 同理可得 2a11
var result = 1 + 1 + 'a' + 1 + 1;
console.log(result); // 2a11

-、*、/、%、=、()

+=、-=、/=、*=、%=

++。先加加(减减)还是后加加(减减)是针对当前语句来说的。++放后面,意为先执行该条语句,然后再加加。++放前面,意为先加加,然后再执行该条语句。

1
2
3
4
5
6
7
var a = 10;

console.log(a++); // 10
// 意为先执行 console.log(a),执行完后 a++

//此时再看 a 的值,就是加完之后的了
console.log(a); // 11
1
2
3
4
5
6
7
8
9
10
11
var a = 10;
var b = ++a - 1 + a++;

// ++a 先加后执行,10 + 1 = 11,a 的值变为 11
// a++ 先执行后加,a 现在的值为 11 ,故 a++ = 11
// b = 11 - 1 + 11 = 21

console.log(b);// 21

// a 两次自增,故值为 12
console.log(a);// 12

--。注意:有前自增(自减)操作符时,要先加加(减减),再执行该条语句。

1
2
3
4
5
6
7
8
9
10
11
var a = 1;
var b = a-- + --a;

// 先算 --a,先减后执行,a = 1,自减后 a = 0
// 再算 a--,先执行后减,a = 0,故 a-- = 0
// b = 0 + 0 = 0

console.log(b);// 0

// a 两次自减,故值为 -1
console.log(a);// -1

比较运算符

><==>=<=!=

比较结果为 boolean 值:true / false。

==是等于,而=是赋值。

字符串的比较规则为 asc 码。如“A”的 asc 码为 65 ,“a”的 asc 码为 97。

字符串比较是按照顺序来的,如果运算符左边的字符串中顺位第一的字符小于右边字符串的第一位字符,那么左边直接就是小于右边;如果第一位相等,那就再看第二位。

1
2
3
4
5
6
7
8
9
10
// 读作字符串一零 > 字符串二
var result = '10' > '2';
console.log(result); // false

// 字符串‘1’的 asc 码为 49
// 字符串‘2’的 asc 码为 50
// 字符串‘3’的 asc 码为 51

var result = '3' > '20';
console.log(result); // true

逻辑运算符

&&||!

运算结果为真实的值

下面六个值转化为布尔值都是 false:undefined、null、NaN、""、0、flase

NaN(Not a Number):非数,是数字类型的一类值,意为不可表示的值。

&&在运行时,在碰到表达式的布尔值为假时,返回该表达式的值。

  • 多个表达式时,先看第一个表达式转换成布尔值的结果,若结果为真,接着看第二个表达式的布尔值,若第二个也为真,接着看第三个,依此类推,直到表达式的布尔值为 false,直接返回该表达式的值。即看到假,返回假。如果全为真,则返回最后一个表达式的值。
  • 只有两个表达式时,若第一个表达式的布尔值为 true,返回第二个表达式的值。若第一个表达式为 false,直接返回第一个表达式原本的值。即一真返二。一假返一。
1
2
3
4
5
var a = 1 && 2;

console.log(a); // 2
// 1 转化为 true,判断为真
// 第一个为 true,直接返回第二个表达式的值

基于&&运算符的原理, 使它具备中断的作用,在实际开发中作为短路语句使用,它是 if 语句的简写形式,可以用来替代 if 语句:“如果…是真/假,那么…”

1
2
3
4
5
0 && document.write('a'); // 不会输出 a

// 如果前面的数据正确,那么执行后面的语句

2 > 1 && console.log('团子很可爱'); // 团子很可爱

||&&类似,只不过是碰到表达式的布尔值为真时,返回该表达式的值。

  • 多个表达式时,若第一个为假,则一直往下看,直到找到为真的表达式,然后返回该值。即看到真,返回真。如果全为假,则返回最后一个表达式的值。
  • 两个表达式时,若第一个为假,直接返回第二个表达式的值。
1
2
3
var num = 1 || 3;

console.log(num); // 1

!将表达式转换成布尔值再取反,然后输出布尔值。

其他:逗号运算符

形式:(表达式1,表达式2,表达式3………….)
作用:通常与小括号()一起使用,逗号,用于连接算式
运算规则:对每个操作对象求值(从左至右),返回最后一个操作对象的值。

1
2
3
4
5
6
7
var a = 10,
b = 20,
result = (a++, a + b);

console.log (result); // 31
console.log (a); // 11
console.log (b); // 20

查询运算符优先级

语句

if 条件语句

if (条件判断) {执行语句}

if () {} else if () {}

if () {}<—> &&转换

for 循环语句

for 循环执行顺序:

  • 先执行一遍 (1) :var i = 0
  • 判断 (2) -> 执行语句 (3):if(i < 10){console.log('a');}
  • 执行 (4):i++ -> i = 1
  • 判断 (2) -> 执行语句 (3)
  • 执行 (4):i++ -> i = 2
  • 判断 (2) -> 执行语句 (3)
  • 执行 (4):i++ -> i = 3
1
2
3
4
5
6
7
8
9
10
//       (1)      (2)   (4)
for (var i = 0; i < 10; i++) {
console.log('a'); // (3)
}

var i = 0; // (1)
for (; i < 10; ) { // (2)
console.log('a'); // (3)
i++; // (4)
}

无论 for 语句中写的是什么,都会按照这个执行顺序执行。

while

1
2
3
4
5
var i = 0;
while (i < 10) {
console.log(i);
i++;
}

do while(很少用)

1
2
3
4
5
var i = 0;
do {
console.log('a');
i++;
} while (i < 10)

switch 语句

格式:

1
2
3
4
5
6
7
8
9
10
11
12
13
switch (条件) {
case 结果1: // 结果与条件进行判断(比对)
执行语句; // 满足即执行该语句
break; // 执行后结束
case 结果2:
执行语句;
break;
case 结果3:
执行语句;
break;
default:
执行语句;
}

switch 的条件和 case 的结果比对,如果是一样的,就执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var date = window.prompt('input');
switch (date) {
case 'monday':
case 'tuesday':
case 'wednesday':
case 'thursday':
case 'friday':
console.log('working');
break;
case '周六':
case '周日':
console.log('relaxing');
break;
}

当 case 的结果是表达式时,比较的就是表达式的返回值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var age = 28,
greeting;

switch (true) { // 条件
case age < 18: // 结果1
greeting = '同学';
break;
case age >= 18 && age < 40: // 结果2
greeting = '先生';
break;
case age >= 40:
greeting = '前辈';
break;
default:
greeting = '你好';
}
console.log(greeting); // '先生'

补充

break:终止循环。

1
2
3
4
5
6
7
8
9
var sum = 0;
for (var i = 0; i < 100; i++){
sum += i;
console.log(i);
if (sum > 100) {
break;
// 这个 break 能执行是因为最外有一层 for 循环,如果只有 if 语句,是肯定报错的
}
}

break 必须写在循环里面,否则会报错。

continue:终止本次循环,直接进行下一次循环。

1
2
3
4
5
6
for (var i = 0; i < 100; i++) {
if (i % 7 === 0 || i % 10 === 7) {
continue;
}
console.log(i);
}