JavaScript基础 + 高级

JavaScript基础

01 JavaScript简介

起源

• JavaScript诞生于1995年,它的出现主要是用于处理网页中的前端验证。

• 所谓的前端验证,就是指检查用户输入的内容是否符合一定的规则。

• 比如:用户名的长度,密码的长度,邮箱的格式等。

简史

• JavaScript是由网景公司发明,起初命名为LiveScript,后来由于SUN公司的介入更名为了JavaScript。

• 1996年微软公司在其最新的IE3浏览器中引入了自己对JavaScript的实现JScript。

• 于是在市面上存在两个版本的JavaScript,一个网景公司的JavaScript和微软的JScript。

• 为了确保不同的浏览器上运行的JavaScript标准一致,所以几个公司共同定制了JS的标准名命名为ECMAScript

年份 事件
1995 网景公司开发了JavaScript
1996 微软发布和JavaScript兼容的JScript
1997 ECMAScript第1版(ECMA-262)
1998 ECMAScript第2版
1998 DOM Level1制定
1998 新型语言DHTML登场
1999 ECMAScript第3版
2000 DOM Level2制定
2002 ISO/IEC 16262:2002确立
2004 DOM Level3制定
2005 新型语言Ajax登场
2009 ECMAScript第5版
2009 新型语言HTML5登场

实现

  • ECMAScript是一个标准,而这个标准需要由各个厂商去实现。
  • 不同的浏览器厂商对该标准会有不同的实现。
浏览器 JavaScript实现方式
FireFox SpriderMonkey
Internet Explorer JScript/Chakra
Safari JavaScriptCore
Chrome v8
Carakan Carakan
  • 我们已经知道ECMAScript是JavaScript标准,所以一般情况下这两个词我们认为是一个意思。

  • 但是实际上JavaScript的含义却要更大一些。

  • 一个完整的JavaScript实现应该由以下三个部分组成:

    image-20210930161455485

学习内容

  • 我们已经知道了一个完整的JavaScript实现包括了三个部分:

    ECMAScriprt、DOM、BOM

  • 由此我们知道学习的内容也是这三个部分:

    • ECMAScript
    • DOM
    • BOM

特点

  • JS的特点
    • 解释型语言
    • 类似于C和Java的语法结构
    • 动态语法
    • 基于原型的面向对象

解释型语言

  • JavaS cript是一门解释型语言,所谓解释型值语言不需要被编译为机器码再执行,而是直接执行。
  • 由于缺少这一步骤,所以解释型语言开发起来尤为轻松,但是解释型语言运行较慢也是它的劣势。
  • 不过解释型语言中使用了JIT技术,使得运行速度得以改善。

类似于C和Java的语法结构

  • JavaScript的语法结构与C和Java很像,像for 、if 、while等语句和Java基本是一摸一样的
  • 所有有过C和Java基础的同学学习起来会轻松很多
  • 不过JavaScript和与Java的关系也仅仅只是看起来像而已

动态语言

  • JavaScript是一门动态语言,所谓的动态语言可以暂时理解为在语言中的一切内容是不确定的。比如,一个变量在这一时刻是一个整型,但是在下一刻可能就会变成字符串了。当然这个问题我们以后再谈。
  • 不过再补充一句,动态语言相比静态语言性能要差一点,不过由于JavaScript中应用了JIT,所以JS可能是运行速度最快的动态语言了

基于原型的面向对象

  • JavaScript是一门面向对象的语言,但是与Java不同,JavaScript是基于原型的面向对象。

02 HelloWorld案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>HelloWorld</title>
<script>
// JS代码要编写在script标签中
/* 控制浏览器弹窗 */
alert("你好啊!");
// 让页面输出一个内容
document.write("mk")
// 控制台输出
console.log("曾经沧海难为水")
</script>
</head>
<body>
</body>
</html>

03 js代码编写位置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>js编写位置</title>
<!-- 可以将js代码编写到js文件中,然后通过script标签引入
写到外部文件中可以在不同的页面中同时引入,也可以利用到浏览器的缓存机制
推荐使用的方式
注意:script标签一旦引入外部文件,就不能再编写代码了,即使写了,浏览器也会忽略,如果需要,则可以再创建一个新的script标签用于编写内部代码

代码执行为顺序执行
-->
<script src="./js/03js编写位置.js"></script>
<script>
alert("写在script标签上的代码")
</script>
</head>

<body>
<!-- 可以将js代码编写在标签的onclick属性上
点击后触发事件,js代码执行

虽然可以写在标签属性中,但是它们属于结构与行为耦合,不方便维护,不推荐使用,可以写在script标签里,还可以写在外部js文件中,然后通过script标签引入
-->
<button onclick="alert('js代码编写在标签的onclick属性')">点击</button>

<!-- 可以将js代码写在href属性中,这样当点击时,会执行js代码 -->

<a href="javascript:alert('你好啊');">点击超链接</a>
<a href="javascript:;">点击超链接</a>

</body>

</html>

04 基础语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>js基本语法</title>
<script>
/*
多行注释
JS注释
多行注释,注释中的内容不会执行,但是可以在源代码中查看
要养成编写注释的良好习惯,也可以通过注释来对代码进行一些简单的调试
*/

// 单行注释
/*
1. JS中严格区分大小写
2.JS中每一条语句以(;)结尾,如果不写浏览器会自动添加,但是会消耗一些系统资源.
而且有时候浏览器会加错分号,所以开发中最好写分号
3.JS中会自动忽略多个空格和换行,所以我们可以利用空格和换行进行格式化

*/
</script>
</head>
<body>
</body>
</html>

05 字面量和常量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>字面量和变量</title>
<script>
/*
字面量:都是一些不可改变的`值
比如:1 2 3 4 5 6
字面量都是可以直接使用,但是我们一般不会直接使用字面量

变量:可以用来保存字面量,而且变量的值是可以任意变化的
变量更加方便了我们使用,所以开发中都是使用变量去保存一个字面量,而很少直接使用字面量
可以通过变量对字面量进行描述
*/
// 声明变量
// 在js中使用var关键字来声明一个变量,并为它赋值
var a = 1;
console.log(a);
</script>
</head>
<body>
</body>
</html>

06 标识符

image-20211002165141986

image-20211002165156629

07 字符串String

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>字符串</title>
<script>
/*
数据类型指的是字面量的类型
在JS中一共有6种数据类型
String 字符串
Number 数值
Boolean 布尔值
Null 空值
Underfined 未定义
Object 对象

其中String Number Null Underfined Boolean属于基本数据类型,而Object属于引用数据类型
*/

/*
String字符串
- 在JS中使用字符串需要使用引号引起来
- 使用双引号或单引号都可以,但是不要混用
- 引号不能嵌套,双引号中不能放双引号,单引号中不能放单i引号;但是可以在单引号中放双引号,双引号中放单引号。
或者可以使用转义字符,当需要表示一些特殊符号时可以使用\进行转义
\n:换行符
\t:制表符
*/
var str = "hello";
// 输出变量
console.log(str);
// 输出字面量
console.log("str");

var welcome = "我说: \"你好\"";
console.log(welcome);

var str2 = "你好\n你快乐吗?";
var str3 = "1\t2\t3\t4\t5\t6";
console.log(str2, str3);

var str4 = "\\";
console.log(str4);
</script>
</head>
<body>
</body>
</html>

08 Number

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Number</title>
<script>
/*
- Number:在JS中所有的数值都是Number类型,
包括整数和浮点数(小数)

JS中可以表示数字的最值
MAX:1.7976931348623157e+308
MIN:5e-324(大于0的最小值)
如果结果超出表示范围:将会返回Infinity / -Infinity
注意:这里的Infinity是字面量,可以用于赋值,使用typeof检查,将返回Number
NaN是一个特殊的数字,表示Not a Number
使用typeof检查一个NaN也会返回number

- JS中,整数的计算基本可以保持精确
但是使用JS进行浮点运算,可能得到一个不精确的结果,这是二进制运算导致的,所以千万不要使用JS进行对精确度要求较高的运算

*/
var a = 123;
console.log(a);

var b = "3.1415926"
a = 3.1415926;
console.log(a);
console.log(b);

/*
可以使用一个运算符typeof来检查一个变量的类型
语法:typeof 变量
*/
console.log(typeof a); // number
console.log(typeof b); // string

// Number的最值
console.log(Number.MAX_VALUE); // 1.7976931348623157e+308
console.log(Number.MIN_VALUE); // 5e-324
console.log(Number.MAX_VALUE * Number.MAX_VALUE); // Infinity
console.log(typeof Infinity); //Number

var c = "abc" * "bcd";
console.log(c); //NaN,即Not a Number
console.log(typeof NaN); // Number

var d = 123 + 456;
console.log(d);

var e = 0.1 + 0.2;
console.log(e); // 0.30000000000000004

</script>
</head>

<body>

</body>

</html>

09 Boolean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Boolean</title>
<script>
/*
Boolean:布尔值
只有两个值:true / false,用来做逻辑判断
*/
var bool = true;
console.log(bool);
console.log(typeof bool); // boo;ean
</script>
</head>
<body>
</body>
</html>

010 Null 和 Undefined

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Null 和 Underfined</title>
<script>
/*
Null类型的值只有一个,就是nullnull这个值专门用来表示一个为空的对象,使用typeof 检查一个null值时,会返回object

Underfined类型的值只有一个,就是underfined
当声明一个变量,但是不给变量赋值,它的值就是undefined
使用typeof检查undefined,将会返回underfined
*/
console.log(typeof null); // 输出object

var a;
console.log(a); // undefined
console.log(typeof a);
</script>

</head>

<body>

</body>

</html>

011 强制类型转换-String

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>强制类型转换-String</title>    <script>        /*            强制类型转换                - 指将一个数据类型强制转换为其他数据类型                - 类型转换主要指,将其他数据类型转换为                        String Number Boolean        */        /*             将其他数据类型转换为String                方式一:                    - 调用被转换数据类型的toString()方法                    - 该方法不会影响到原变量,它会将转换的结果返回                    - 但是注意:null和undefined这两个值没有toString()方法,如果调用就会报错                方式二:                    - 调用String函数,并将被转换的数据作为参数传递给函数                    - 使用String()做强制类型转换时,                        对于Number和Boolean实际就是调用的toString()方法                        但是对于null 和 undefined,就不会调用toString()方法,它会直接转换为"null"和"undefined"        */        var a = 123;        console.log(typeof a);        // 调用a的toString()方法        // 调用xxxx的yyy()方法,就是xxx.yyy()        var b = a.toString();        console.log(b);        console.log(typeof b); // string        a = true;        a = a.toString();        console.log(a); // true        console.log(typeof a);        a = null;        // a = a.toString(); // 报错        a = undefined;        // a = a.toString(); // 报错        a = 123;        // 调用String()函数,来将a转换为字符串        a = String(a);        console.log(a);        console.log(typeof a); // string        a = null;        a = String(a);        console.log(a); // null        console.log(typeof a); // String        a = undefined;        a = String(a);        console.log(a); // undefined        console.log(typeof a); // string    </script></head><body></body></html>

012 强制类型转换-Number

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>强制类型转换-Number</title>    <script>        /*            将其他的数据类型转换为Number                - 转换方式一:                    使用Number()函数                     - 字符串 ===> 数字                        1. 如果是纯数字的字符串,则直接将其转换为数字                        2.如果字符串中有非数字的内容,则转换为NaN                        3.如果字符串是一个空串,或者是一个全是空格的字符串,则转换为0                    - 布尔值 === > 数字                        true 转换为 1                        false 转换为 0                    - Null ===> 数字0                    - undefined ===> 数字NaN                                - 转换方式二:                    - 这种方式专门用来对付字符串                    - parseInt() 把字符串转换为一个整数                    - parseFloat()把一个字符串转换为一个浮点数        */        var a = "123";        console.log(a);        console.log(typeof a);        // 调用函数Number()函数来将a转换为Number类型        a = Number(a);        console.log(a);        console.log(typeof a);        a = Number("abc");        console.log(a); // Number        console.log(typeof a);        a = "     ";        a = Number(a);        console.log(a); // 0        console.log(typeof a); // number        a = true;        a = Number(a);        b = false;        b = Number(b)        console.log(b);        console.log(a);        console.log(typeof a);        a = null;        console.log(typeof a); // object        a = Number(a);        console.log(a);        a = undefined;        a = Number(a);        console.log(a); // NaN        a = "123px12";        // 调用parseInt()函数将a转换为Number        /*             parseInt()可以将一个字符串中有效的整数内容取出,然后转换为Number            parseFloat()作用和parseInt类似,不同的是,它可以获取有效小数        */        a = parseInt(a);        console.log(a); // 123        console.log(typeof a);        a = "123.567px1222";        a = parseFloat(a);        console.log(a); // 123.567        console.log(typeof a);        /*             如果对非String使用parseInt()或parseFloat()                它会先将其转换为String,然后再操作        */        a = true;        a = parseInt(a);        console.log(a); // NaN        console.log(typeof a);        // parseInt()可以将一个字符串中的有效整数内容取出来        a = 198.123;        a = parseInt(a);        console.log(a);        console.log(typeof a);    </script></head><body></body></html>

013 其他进制的数字

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>其他进制的数字</title>    <script>        var a = 123;        console.log(a);        /*            在js中,如果需要表示16进制数字,则需要以0x开头                        如果需要表示8进制的数字,则需要以0开头                        如果要表示2进制数字,则需要以0b开头,但是不是所有浏览器都支持        */        a = 0x10;        console.log(a); // 16        a = 070;        console.log(a); // 56        a = 0b10;        console.log(a); // 2        // 像"070"这种字符串,有些浏览器会当成8进制解析,有些会当成10进制解析        a = "070";        // 可以在parseInt()中传递一个第二参数,来指定数字的进制,但是并不常用        a = parseInt(a, 10);        console.log(a); // 70        console.log(typeof a);        a = parseInt(a, 8);        console.log(a); // 56        console.log(typeof a);    </script></head><body></body></html>

014 转换为Boolean

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>转换为Boolean</title>    <script>        /*            将其他的数据类型转换为Boolean                - 使用Boolean()函数                - 数字 ===> 布尔值                    - 除了0和NaN,其余全是true                - 字符串 ===> 布尔值                    - 除了空串,其余的都是true                - null和undefined都会转换为false                - 对象也会转换为true        */        // 调用Boolean()函数来将a转换为布尔值        var a = 123;        a = Boolean(a);        console.log(a); // true        a = -123;        a = Boolean(a);        console.log(a); // true        a = Infinity;        a = Boolean(a);        console.log(a); // true        a = 0;        a = Boolean(a);        console.log(a); // false        a = null;        a = Boolean(a);        console.log(a); // false        a = undefined;        a = Boolean(a);        console.log(a); // false        a = NaN;        a = Boolean(a);        console.log(a); // false        a = "";        a = Boolean(a);        console.log(a); // false        a = "  ";        a = Boolean(a);        console.log(a); // true        a = "zhulan";        a = Boolean(a);        console.log(a); // true    </script></head><body></body></html>

015 算数运算符

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>算数运算符</title>    <script>        /*            运算符也叫操作符                通过运算符可以对一个或多个值进行运算,并获取运算结果                比如:typeof就是运算符,可以来获得一个值的类型                    它会将该值的类型以字符串的形式返回                    number boolean undefined object string                            算数运算符                + - * / %                当对非Number类型的值进行运算时,会将这些值转换成Number,然后将结果返回                    - 任何值和NaN做运算都得到NaN                    - 如果对两个字符串进行加法运算,则会做拼串,将两个字符串拼接为一个字符串,并返回                    - 任何的值和字符串做加法运算,都会先转换为字符串,然后再和拼串操作        */        var a = 123;        var res = typeof a;        console.log(res); // number        console.log(typeof res); // string        a = true + 1;        console.log(a); // 2        a = true + false;        console.log(a);// 0        a = null + 2;        console.log(a); // 2        a = 2 + NaN;        console.log(a); // NaN         a = "123" + "456";        console.log(a); //123456        console.log(typeof a); // string        a = 1 + "123";        console.log(a);        console.log(typeof a);        // 任何值和字符串相加都会转换为字符串,并做拼串操作        a = true + "123";        console.log(a); // true123        // 可以利用这一特点,来将一个任意的数据类型转换为String,我们只需要为任意的数据类型加一个"",即可将其转换为String,这是一种隐式的类型转换,由浏览器自动完成,实际上它也是调用String()函数,        a = 123 + ""; // 等价于a = String(a);        console.log(a);        console.log(typeof a);        a = 1 + 2 + "3";        console.log(a); // 33        a = 1 + "2" + "3";        console.log(a); // 123        /*            任何值做 - * / 运算时,都会自动转换为Number                我们可以利用这一特点做隐式的类型转换为Number                原理和Number()函数一样,使用起来更加简单        */        a = 100 - 5;        console.log(a); // 95        a = 100 - true;        console.log(a); // 99        a = 100 - "1";        console.log(a); // 99        a = "123" - 0;        console.log(a); // 123        console.log(typeof a); //number        a = 2 * "8";        console.log(a); // 16        a = 2 * null;        console.log(a); //0        a = 2 * undefined;        console.log(a); // NaN        a = 100 % 3;        console.log(a); // 1    </script></head><body></body></html>

016 一元运算符

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>一元运算符</title>    <script>        /*            一元运算符:只需要一个操作数                 + :不会对数字运算结果产生影响                 -  :符号可以对数字进行符号的取反            对于非Number类型,它会先将其转换为Number,然后再进行运算。            可以对一个其他的数据类型使用+,来将其转换为Number,原理和Number()函数一致        */        var a = 1;        a = +a;        console.log(a);        a = -a;        console.log(a);        a = true;        a = -a;        console.log(a); // -1        a = "18";        a = +a;        console.log(a); // +18        console.log(typeof a); // number        a = 1 + +"2" + 3;        console.log(a); // 6    </script></head><body></body></html>

017 自增和自减

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>自增和自减</title>    <script>        /*            自增                - 通过自增可以使得变量在自身基础上增加1                    - 自增分为两种:后++,和前++,a++ / ++a                    - 无论是++a / a++,都会立即使得原变量加1                        不同的是,a++和++a的值不同                    - a++的值等于原变量的值(自增前的值),a--的值等于(自增后的值)                - 通过自减可以使变量在自身的基础上减1                    - 类比自增        */        var a = 1;        a++; //使a自增1        console.log(a); // 2        ++a;        console.log(a); // 3        a--;        console.log(a); // 2        a = 1;        console.log(a++); // 1        console.log(++a);// 3        a = 100;        var res = a++ + ++a + a;        console.log(res); // 304        a = 1        a = a++;        console.log(a); //  1    </script></head><body></body></html>

019 逻辑运算符

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>逻辑运算符</title>    <script>        /*            JS中为我们提供了三种逻辑运算符                        ! 非:所谓非运算就是对一个布尔值进行取反操作,true变false,false变true,两次取反真假不变            我们可以利用该特点,来将一个数据类型转换为布尔值,可以对任意一个数据类型取反两次,来将其转换为布尔值原理和Boolean()函数一样            && 与:&&可以对符号两侧的值进行运算并返回结果            运算规则:有假得假,全真为真            JS中的“与”属于短路与,如果第一个值为false,则不会再看第二个值            || 或:||可以对符号两端的值进行运算并返回结果            运算规则:全真则真,一假则假            JS中的“或”属于短路或,如果第一个值为真,则不会再判定第二个值         */        var a = true;        a = !a;        console.log(a); // false         console.log(!10); // false        console.log(!null); // true        console.log(!undefined); // true        console.log(!""); // true        console.log(!"a"); // false        console.log(true && true); // true        console.log(true && false); // false        console.log(false && true); // false        console.log(false && false); // false        true && console.log("执行打印1") // 输出        false && console.log("执行打印2") // 没有输出        console.log(true || true); // true        console.log(true || false); // true        console.log(false || false); // false        true || console.log("执行打印3"); // 未输出        false || console.log("执行打印4"); // 输出    </script></head><body></body></html>

020 非布尔值的与或运算

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>非布尔值的与或运算</title>    <script>        /*            && || 非布尔值的情况                - 对于非布尔值进行与或运算时,会将其转换为布尔值,然后再进行运算,并且返回原值!!!                - 与运算:                    - 如果第一个值为true,则返回第二个值                    - 如果第一个值为false,则直接返回第一个值                - 或运算:                    - 如果第一个值为true,则直接返回第一个值                    - 如果第一个值为false,则直接返回第二个值        */        // 与运算:如果两个值均为true,则返回后面的        var res = 1 && 2;        console.log(res); // 2        // 与运算:如果两个值中有false,则返回靠前的false        res = 0 && 1;        console.log(res); // 0        res = NaN && 0;        console.log(res); // NaN        res = 0 && NaN;        console.log(res); // 0        // 或运算:如果第一个值为true,则直接返回第一个值        // 如果第一个值为false,则直接返回第二个值        res = 2 || 1;        console.log(res); // 2        res = NaN || 0;        console.log(res); // 0        res = 0 || NaN;        console.log(res); // NaN    </script></head><body></body></html>

021 赋值运算符

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>赋值运算符</title>    <script>        /*            =:可以将符号右侧的值赋值给符号左侧的变量            += / -= / *= / /= / %=:        */        var a = 0;        a += 5; // 等价于a = a+5        console.log(a); // 5         a %= 3;        console.log(a); // 2    </script></head><body></body></html>

022 关系运算符

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>关系运算符</title>    <script>        /*            通过关系运算符可以比较两个值之间的大小关系                如果关系成立则返回true,如果不成立,则返回false                        >            <            >=                        非数值的情况:                - 对于非数值进行比较时,会将其转换为数字,然后再比较                - 任何值和NaN做比较,结果都是false                - 如果符号两边的值都是字符串时,不会将其转换为数值进行比较,而会分别比较字符串中的Unicode编码        */        console.log(5 > 10); // false        console.log(5 > 4); // true        console.log(5 >= 5); // true        console.log(1 > true); // false        console.log(1 > "0"); // true        console.log(10 > null); // true        console.log(10 > undefined); //false        console.log(10 <= undefined); //false        console.log(10 > "hello"); // false        console.log(NaN == NaN); // false        console.log(NaN === NaN); // false        // 比较两个字符串时,比较的是字符串编码        // 比较字符串编码时,是一位一位进行比较的,如果两位一样,则比较下一位,可以对英文实现排序,比较中文时,没有意义        console.log("11" < "5"); // true        console.log("11" > "5"); // false        console.log("a" < "b"); // true        console.log("a" > "b"); // false        console.log("bbc" > "b"); // true        // 如果比较的两个字符串类型的数字,可能会得到不可预期的结果        // 注意:在比较两个字符串类型的数字时,一定一定要转型        console.log("11111111" < "5"); // true        console.log("11111111" < +"5"); // false    </script></head><body></body></html>

023 Unicode编码

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>Unicode编码</title>    <script>        /*             在字符串中使用转义字符输出Unicode编码            \u 四位编码,注意,此处的编码是16进制的,而在网页标签上使用,应该将他转换为10进制        */        console.log("\u0031"); // 1        console.log("\u2620"); // ☠        console.log("\u2623"); // ☣    </script></head><body>    <!-- 在网页中使用Unicode编码        &#编码;是十进制数字    -->    <h1>&#9763;</h1></body></html>

024 相等运算符

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>相等运算符</title>    <script>        /*            相等运算符用来比较两个值是否相等                如果相等,会返回true,否则返回false            使用 == 来表示相等运算                - 当使用 == 来比较两个值时,如果值的类型不同,则会自动进行类型转换,将其转换为相同类型的值,然后再进行比较            不相等                不相等用来判断两个值是否相等,如果不相等返回true,否则返回false                - 使用 != 来做不相等运算                - 不相等也会对变量进行自动的类型转换,如果转换后相等,也会返回false            ===                 全等                    - 用来判断是否全等,和相等类似,不同的是,它不会做自动的类型转换,如果两个值的类型不同,直接返回false            !==                 不全等                 - 用来判断两个值是否不全等,和不等类似,不同的是,它不会做自动类型转换,如果两个值类型不同,将直接返回true        */        console.log(1 == 1); // true        // 不同类型之间的比较        console.log("1" == 1); // true        console.log(true == "1"); // true        console.log(null == 0); // false        /*            undefined衍生自null,所以这两个值做相等判断时,将会返回true        */        console.log(null == undefined); // true        /*            NaN不和任何值相等,包括它本身        */        console.log(NaN == NaN); // false        var b = NaN;        // 需求:判断b的值是否是NaN        /*             可以利用isNaN()函数来判断一个值是否是NaN                是NaN,返回true;否则返回false        */        console.log(isNaN(b)); // true        console.log(10 != 5); // true        console.log(1 != 1); // false        console.log("1" != 1); // false        console.log("123" === 123); // false        console.log(null === undefined); // false    </script></head><body></body></html>

025 条件运算符

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>条件运算符</title>    <script>        /*            条件运算符也叫三元运算符                语法:条件表达式?语句1:语句2;            - 执行流程:                条件运算符在执行时,首先对表达式进行求值                    如果该值为true,则执行表达式1,并返回执行结果                    如果该值为false,则执行语句2,并返回执行结果                如果条件表达式的求值结果是一个非布尔值,会将其转换为布尔值,然后再运算        */        true ? console.log("执行语句1") : console.log("执行语句2");        false ? console.log("执行语句1") : console.log("执行语句2");        // 获取a b c 中的最大值        var a = 100, b = 200, c = 300;        var max; // 不推荐使用,但是不方便阅读        //         max = a > b ? (a > c ? a : c) : (b > c ? b : c); // 300        console.log(max);        "" ? console.log("执行语句1") : console.log("执行语句2"); // 2        "hello" ? console.log("执行语句1") : console.log("执行语句2"); // 1    </script></head><body></body></html>

026 运算符的优先级

image-20211006144431509

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>运算符的优先级</title>    <script>        /*            ,运算符                使用,可以分割多个语句,一般可以在声明多个变量时使用,可以同时声明多个变量值并赋值        */        // var a = 1, b = 2, c = 3;        /*            就和数学中一样,JS中运算符也有优先级                比如:先乘除后加减            在JS中,有一个运算符优先级的表,在表中,越靠上的优先级越高,优先级越高越先计算,如果优先级相同,则从左往右计算            但是该表我们不需要去记忆,遇到优先级不确定的情况,可以使用()来改变优先级!!!        */        var res = 1 + 2 * 3;        console.log(res); // 7        /*             如果||的优先级高,或者两个一样高,则返回 3            如果&&的优先级高,则返回1        */        res = 1 || 2 && 3;        console.log(res); // 1,说明&&优先级高    </script></head><body></body></html>

027 代码块

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>代码块</title>    <script>        /*            我们的程序是由一条一条语句构成的                语句是按照自上而下的顺序一条一条执行的                在JS中可以使用{}来为语句进行分组                    同一个{}中的语句我们称为是一组语句                    它们要么都执行,要么都不执行                    一个{}中的语句我们也称为一个代码块                    在代码块的后边就不用写分号了            JS中的代码块只具有分组的作用,没有其他的用途                代码块内的内容,在外部是完全可见的        */        {            alert("你好");            console.log("hello");            document.write("你好");            var a = 10;        }        console.log(a); // 10    </script></head><body></body></html>

028 if语句(一)

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>流程控制语句</title>    <script>        /*            流程控制语句            - JS中的程序是从上到下一行一行执行的            - 通过流程控制语句可以控制程序执行流程,使程序可以根据一定的条件来选择执行            - 语句的分类:                1.条件判断语句                2.条件分支语句                3.循环语句            条件判断语句                - 使用条件判断语句可以在执行某个语句之前进行判断,如果条件成立,才会执行语句,条件不成立就不执行语句            - if 语句                if(条件表达式)                    语句                if语句在执行是,会先对条件表达式进行求值判断,如果表达式的值为true,则执行if后的语句,如果表达式的值为false,则不会执行if后的语句                    if语句只能控制其紧随其后的语句,如果希望if语句可以控制多条语句,可以将这些语句统一放在一个代码块中                if语句后面的代码块不是必须的,但是开发中尽量写上代码块,即使if语句后只有一条语句        */        var a = 15;        if (a > 10 && a < 20) {            console.log(a);        }    </script></head><body></body></html>

029 if语句(二)

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>if语句</title>    <script>        /*            if语句                语法二:                    if(条件表达式){                        语句……                    }else{                        语句……                    }                if……else……语句                    当该语句执行时,会先对if后的条件表达式进行求值判断                        如果该值为true,则执行if后的语句                        如果该值为false,则执行else后的语句                语法三:                    if(条件表达式){                        语句……                    }else if(条件表达式){                        语句……                    }else{                        语句……                    }                    if……else if……else                        当该语句执行时,会自上而下依次对条件表达式进行求值判断                        如果为true,则执行当前语句;                        如果为false,则继续向下判断,                        如果所有条件都不满足,则执行最后一个else后的语句                    该语句中,只会有一个代码块被执行,一旦代码块被执行了,则直接结束语句        */        var age = 15;        if (age < 35 && age > 22) {            console.log("还要继续996");        } else if (age >= 35) {            console.log("可以退休了");        } else {            console.log("摆烂");        }    </script></head><body></body></html>

030 - 032 练习

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>练习</title>    <script>        /*             prompt()可以弹出一个提示框,该提示框会带有一个文本框,用户可以在文本框中输入一段内容,该函数需要一个字符串作为参数,该字符串将会作为该提示框的提示文字            用户输入的内容将会作为函数的返回值返回,可以定义一个变量来接收该变量        */        var scores;        scores = prompt("请输入期末成绩(0-100):");        if (isNaN(scores) || scores > 100 || scores < 0) {            console.log("输入不合法!");        } else if (scores === 100) {            console.log("奖励一辆BMW");        } else if (scores >= 80) {            console.log("奖励一台iphone13 pro Max");        } else if (scores >= 60) {            console.log("奖励一本资料");        } else {            console.log("没有奖励");        }    </script></head><body></body></html>
1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>练习二</title>    <script>        /*            注意prompt()函数的返回值一定是String类型的            在使用isNaN()函数时,对于字符串数字检查后也会返回false,所以可以利用+运算符将输入转换为数字        */        var a = +prompt("数字1:");        var b = +prompt("数字2:");        var c = +prompt("数字3:");        var a1, b1, c1;        if (isNaN(a) || isNaN(b) || isNaN(c)) {            console.log("输入不合法!");        } else {            console.log(a > b ? (a > c ? a : c) : (b > c ? b : c), a > b ? (b > c ? b : (a > c ? c : a)) : (b < c ? b : (a < c ? c : a)), a < b ? (a > c ? c : a) : (b > c ? c : b));        }    </script></head><body></body></html>

033 条件分支语句

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>条件分支语句</title>    <script>        /*            条件分支语句switch语句            switch(条件表达式){                case 表达式:                    语句……                    break;                case 表达式:                    语句……                    break;                case 表达式:                    语句……                    break;                default:                    语句……;                    break;            }            执行流程:                switch……case……语句                在执行时,会依次将case后面的表达式和switch后的条件表达式的值进行全等比较,如果比较结果为true,则从当前case处开始执行代码                    当前case后所有的代码,都会被执行,所以最好在每一个case语句后面使用break及时退出switch语句,这样可以确保只会执行当前case后的语句,而不会执行其他的语句                如果比较结果为false,则继续向下比较。                如果所有的比较结果都是false,则只会执行default之后的语句。            switch语句和if语句的功能有重复,使用switch可以实现if的功能,反之,使用if可以实现switch语句的功能,所以我们使用时,可以根据自己的习惯选择                    */        var num = 1;        switch (num) {            case 1:                console.log("壹");                break;            case 2:                console.log("贰");                break;            case 3:                console.log("叁");                break;            default:                console.log("芜湖~~");        }    </script></head><body></body></html>

034 switch练习

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>switch练习</title>    <script>        /*         */        var score = 80;        // 写法一:        // switch (parseInt(score / 10)) {        //     case 10:        //     case 9:        //     case 8:        //     case 7:        //     case 6:        //         console.log("及格");        //         break;        //     default:        //         console.log("不及格");        //         break;        // }        // 写法二: true和case中的表达式结果全等与否,全等比较!!!!!        switch (true) {            case score >= 60:                console.log("及格");                break;            default:                console.log("不及格");                break;        }    </script></head><body></body></html>

035 while循环

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>while循环</title>    <script>        /*            向页面输出连续的数字            循环语句:                通过循环语句可以反复的执行一段代码多次            while循环                - 语法:                    while(条件表达式){                        语句......(循环体)                    }                执行时,先对表达式进行求值判断,                    如果值为true,则执行循环体,循环体执行完毕后,继续对表达式进行判断,如果为true,则继续执行循环体,以此类推,直到表达式为false结束                    先判断,后执行                注意:                while(true){                    语句......                }                像这种将表达式写死为true的循环,叫做死循环,这种循环不会停止,除非浏览器关闭,开发中慎用死循环                可以使用break来终止循环                        do.......while循环                - 语法:                    do{                        语句......                    }while(条件表达式)            循环体执行完毕后,再对while后的表达式进行判断,如果结果为true,则继续执行循环体,执行完毕继续判断,以此类推            如果结果为false,则终止循环            先执行,再判断            do...while可以保证循环至少执行一次,而while不能        */        var a = 0;        while (a < 100) {            document.write(a++ + "<br/>");        }        // 创建一个死循环,往往需要三个步骤        // 1.创建一个初始化变量        // 2.在循环中设置一个条件表达式        // 3.定义一个更新表达式,每次更新初始化变量    </script></head><body></body></html>

036 while练习

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>while练习</title>    <script>        var years = 0, money = 1000;        while (money < 5000) {            money += money * 0.05;            years++;        }        document.write(years);    </script></head><body></body></html>

037 for循环

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>for循环</title>    <script>        /*                for语句,也是一个循环语句,也称为for循环                    for循环中,为我们提供了专门的位置来放三个表达式:                        1.初始化表达式                        2.条件表达式                        3.更新表达式                                    for循环语法:                    for(初始化表达式;条件表达式;更新表达式){                        语句.....                    }                                for循环的执行流程:                    1.执行初始化表达式,初始化变量(只执行一次)                    2.执行条件表达式,判断是否执行循环                        如果为true,则执行循环                        如果为false,则终止循环                    3.执行更新表达式,执行更新表达式完毕后,继续重复步骤2        */        for (var i = 0; i < 10; i++) {            console.log(i);        }        /* for循环中的三个部分都可以省略,也可以写在外部            如果在for循环中不写任何的表达式,只写两个;            此时循环是一个死循环,会一直执行下去,慎用        */    </script></head><body></body></html>

三道题

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>三道例题</title>    <script>        // 练习一        var sum = 0;        for (var i = 1; i <= 100; i++) {            if (i % 2 != 0)                sum += i        }        console.log(sum); // 2500        //练习二        var total = 0;        sum = 0;        for (i = 1; i < 100; i++) {            if (i % 7 == 0) {                sum += i;                total++;            }        }        console.log(sum, total); // 735 14        // 练习三        console.log("水仙花数--------------------");        var one, ten, hundred;        for (i = 100; i < 1000b ; i++) {            one = i % 10;            ten = ((i % 100) - one) / 10;            hundred = parseInt(i / 100);            if (one * one * one + ten * ten * ten + hundred * hundred * hundred == i)                console.log(i);        }        // 153 370 371 407    </script></head><body></body></html>

039 质数练习

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>质数练习</title>    <script>        /*        */        var num;        while (true) {            num = prompt("请输入数字(必须大于1的整数):");            if (num > 1 && parseInt(num) == num) {                break;            } else {                alert("输入非法!")            }        }        for (var i = parseInt(num / 2); i > 1; i--) {            // var i = Math.sqrt(num)性能更好            if (num % i == 0) {                console.log(num + "不是质数");                break;            }        }        if (i == 1) {            console.log(num + "是质数");        }    </script></head><body></body></html>

041 嵌套for循环

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>嵌套for循环</title>    <script>        // var str = "*";        // for (var i = 0; i < 6; i++) {        //     console.log(str);        //     str += "  *";        // }        // for (var i = 1; i <= 10; i++) {        //     for (var j = i; j > 0; j--) {        //         document.write("*  ");        //     }        //     document.write("<br/>");        // }        // 倒三角        for (var i = 10; i > 0; i--) {            for (var j = i; j > 0; j--) {                document.write("*  ");            }            document.write("<br/>");        }    </script></head><body></body></html>

042 两个练习

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>两个练习</title>    <script>        /*             99乘法表        */        for (var i = 1; i < 10; i++) {            for (var j = 1; i >= j; j++) {                document.write(j + "*" + i + "=" + i * j + "&nbsp;&nbsp;");            }            document.write("<br/>")        }    </script></head><body></body></html>

044 break和continue语句

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>break和continue</title>    <script>        /*             break关键字可以用来退出switch或循环语句,在if语句中使用会报错            多个循环嵌套时,只会对最内层循环起作用        */        /*             可以为循环语句创建一个label,来标识当前的循环            label:循环语句            使用break语句时,可以在break后跟上label,这样将会结束指定的循环,而不是最近的循环        */        outer:        for (var i = 1; i < 5; i++) {            console.log("外层循环");            for (var j = 1; j < 5; j++) {                console.log("内层循环");                console.log(j);                if (j == 2) {                    break outer;                }            }        }        /*             continue用来跳过当次循环            同样continue也是默认只会对离他最近的循环起作用            同样可以在后面跟上label,这样将会结束指定的循环,而不是最近的循环        */        for (var a = 1; a < 5; a++) {            if (a == 3) continue;            console.log(a);        }    </script></head><body></body></html>

测试程序性能:在程序执行前开启一个计时器console.time(),需要一个字符串作为参数,这个字符串将会作为计时器的标识。

console.timeEnd()用来停止一个计时器,需要一个计时器的标识作为参数。

45 质数练习改进

寻找到Math.sqrt(i)即可

46-47 对象简介、基本操作

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>对象简介</title>    <script>        /*                JS数据类型:                    - Number 数值                    - String 字符串                    - Null 空值                    - Undefined 未定义                    - Boolean 布尔值                        - 以上五种类型属于基本数据类型,以后我们看到的值只要不是上面五种,全都是对象                    - Object 对象(引用数据类型)                    基本的数据类型都是单一的值"hello" 123 true,值和值之间没有任何联系                    例如在JS中来表示一个人的信息(name、gender、age),如果使用基本数据类型,我们所创建的变量都是独立的,不能成为一个整体。                    对象属于复合数据类型,在对象中可以保存多个不同的数据类型的属性。                                        对象分类:                        1.内建对象                            - 由ES标准中定义的对象,在任何的ES的实现中均可使用                            - 比如:Math String Number Boolean Function Object……                        2.宿主对象                            - 由JS的运行环境提供的对象,目前来讲主要指由浏览器提供的对象                            - 比如BOM DOM,比如console对象和document对象                        3.自定义对象                            - 由开发人员自己创建的对象        */        // 创建对象        /*             使用new关键字调用的函数,是构造函数constructor            构造函数是专门用来创建对象的函数        */        var obj = new Object();        console.log(obj);        console.log(typeof obj); // object        /*            在对象保存的值称为属性            向对象添加属性                语法:对象.属性名 = 属性值;        */        obj.name = "张加林";        obj.age = 20;        obj.gender = "男";        console.log(obj);        /*            读取对象中的属性                语法:对象.语法            如果读取的对对象中没有属性,不会报错,而是会返回undefined        */        console.log(obj.name);        console.log(obj.what);        /*            修改对象的属性值                语法:对象.属性名 = 新值;        */        obj.name = "zl";        /*            删除对象属性                语法:delete 对象.属性名        */        delete obj.name;        console.log(obj);    </script></head><body></body></html>

048 属性名和属性值

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>属性名和属性值</title>    <script>        /*            向对象中添加属性                属性名:                    - 对象名不强制要求遵守标识符的规范                        什么乱七八糟的名字都可以使用,但是使用时尽量遵守标识符的规范去做。        */        var obj = new Object();        obj.name = "张加林";        /*            如果使用特殊的属性名,不能采用.的方式来操作                需要使用另一种方式:                    语法:对象["属性名"] = 属性值                读取时也需要采用这种方式            使用[]这种形式去操作属性,更加灵活,                在[]中可以直接传递一个变量,这样变量值是多少就会读取那个属性        */        obj["123"] = 789;        var str = "123";        console.log(obj[str]);        /*            属性值:JS对象的属性值,可以是任意的数据类型                甚至也可以是一个对象        */        obj.test = true;        console.log(obj);        obj.test = undefined;        console.log(obj);        obj.test = null;        console.log(obj);        // 对象的属性值为对象,可以无限套娃        var obj2 = new Object();        obj2.school = "UESTC";        obj.info = obj2;        console.log(obj);        // 检查对象中是否含有某个属性        /*            in运算符                - 通过该运算符,可以检查一个对象是否含有指定的属性                    如果有则返回true,没有则返回false                - 语法:                    "属性名" in 对象        */        console.log("info" in obj); // true        console.log("obj2" in obj); // false        console.log("obj3" in obj); // false    </script></head><body></body></html>

049 基本数据类型和引用数据类型

image-20211007142253251

image-20211007143043275

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>基本数据类型和引用数据类型</title>    <script>        //        /*            基本数据类型:Number、String、Null、Undefined、Boolean            引用数据类型:Object            JS中的变量都是保存到栈内存中的                基本数据类型都直接存储在栈内存中,值与值之间是相互独立的,修改一个变量不会影响到其他变量            对象是保存在堆内存中的,每创建一个新的对象,就会在堆内存中开辟出一个新的内存空间。而变量保存的是对象的内存地址(对象的引用),如果两个变量保存的是同一个对象引用,当通过一个变量修改属性时,另一个也会受到影响        */        var a = 123;        var b = a;        a++;        console.log("a = " + a); // 124        console.log("b = " + b); // 123        var obj = new Object();        obj.name = "张加林";        var obj2 = obj;        console.log(obj.name); //张加林        console.log(obj2.name); //张加林        // 修改obj属性        obj.name = "mk";        console.log(obj.name); //mk        console.log(obj2.name); //mk        /*             给对象赋值null等同于清空指针        */        obj = null;        console.log(obj); // null        console.log(obj2); // {name: 'mk'}        var obj3 = new Object();        var obj4 = new Object();        obj3.name = "zl";        obj4.name = "zl";        /*             当比较两个基本数据类型的值时,就是比较值            而比较两个引用数据类型,比较的是对象的内存地址                如果两个对象是一摸一样的,但是地址不同,它会返回false        */        console.log(obj3 == obj4); // false,因为内存地址不同    </script></head><body></body></html>

050 对象字面量

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>对象字面量</title>    <script>        // 创建一个对象        // var obj = new Object();        // 使用对象字面量来创建一个对象        var obj = {};        console.log(typeof obj);        obj.name = "张加林";        console.log(obj.name);        /*            使用对象字面量可以在创建对象时,直接指定对象中的属性                语法:{属性名:属性值,属性名:属性值……}                对象字面量的属性名可以加引号,也可以不加,建议不加                如果要使用一些特殊的名字,则必须加引号                属性名和属性值是一组一组的名值对结构                    名和值之间使用:连接,多个名值之间使用,隔开,如果一个属性之后没有其他属性了,则不要写,        */        var obj2 = {            name: "miketaylorjuly123.cn",            age: 20,            gender: "男"        };        console.log(obj2);    </script></head><body></body></html>

051 函数的简介

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>函数简介</title>    <script>        /*            函数                - 函数也是一个对象                - 函数中可以封装一些功能(代码),在需要时可以执行这些功能(代码)                - 函数中可以保存一些代码在需要的时候调用        */        // 创建一个函数对象        // 可以将要封装的代码以字符串的形式传递给构造函数        // 开发中,很少使用构造函数来创建一个函数,几乎不用        var fun = new Function("console.log('你好');");        // 封装到函数中的代码不会立即执行,函数中的代码会在函数调用的时候执行,调用函数语法,函数对象();        console.log(fun);        console.log(typeof fun);        // 当调用函数时,函数中封装的代码会按照顺序执行        fun();        fun.wuhu = "张加林";        console.log(fun.wuhu); // 函数是对象        /*             使用函数声明来创建一个函数            语法:                function 函数名([形参1,形参2,……,形参N]){                    函数体;                }        */        function printcsl() {            console.log("一");            console.log("二");            console.log("三");        }        printcsl();        /*            使用函数表达式创建一个函数            var 函数名 = function 函数名([形参1,形参2,……,形参N]){                    函数体;                }            创建一个匿名函数对象,然后将函数赋值给一个变量        */        var test = function () {            console.log("一");            console.log("二");            console.log("三");        }        test();    </script></head><body></body></html>

052 函数的参数

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>函数的参数</title>    <script>        /*            函数的参数                可以在函数的()中指定一个或多个形参(形式参数)                多个形参之间使用,隔开,声明形式参数就相当于在函数内部声明了对应的变量                在调用函数时,可以在()中指定实参(实际参数)                    实际参数会赋值给函数中对应的形参        */        var sum = function (a, b) {            console.log("和为" + (a + b));        }        sum(1, 3);        /*            调用函数时,解析器不会检查实参的类型                所以要注意,是否有可能会接收到非法的参数,如果有可能则需要对参数进行类型的检查            函数的实参可以是任意的数据类型        */        /*            调用函数时,解析器也不会检查实参数量                多余的实参不会被赋值            如果实参的数量少于形参,则没有对应实参的形参将是undefined            注意:数字 + undefined = NaN        */    </script></head><body></body></html>

053 函数返回值

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>函数的返回值</title>    <script>        /*            创建一个函数,用来计算三个数的和            设置函数返回值            返回结果:return 值;            return后的值将会作为函数的执行结果返回                可以定义变量接收返回值            在函数中,return后的语句都不会执行            return; 或者不写return,都将返回undefined            return后可以跟任意类型的值        */        function sum(a, b, c) {            return a + b + c;        }        console.log(sum(100, 200, 300));        console.log(alert("你好")); // 输出undefined,说明alert()函数没有返回值    </script></head><body></body></html>

054 实参可以是任何值

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>实参可以是任何值</title>    <script>        function isEvenNum(num) {            // if (num % 2 == 0)            //     return true;            // else return false;            return num % 2 == 0;        }        console.log(isEvenNum(302));        // 计算圆的面积        function circleArea(radius) {            return radius * radius * Math.PI        }        console.log(circleArea(5));        /*            创建一个函数,可以在控制台输出一个人的信息                可以输出人的name age gender address            实参可以是任意的数据类型,也可以是一个对象                当我们的参数过多时,可以将参数封装到一个对象中,然后通过对象传递        */        var person = {            name: "张加林",            age: 20,            school: "郫县男子职业技术学院"        }        function output(obj) {            console.log(obj);        }        output(person);        /*            实参可以是对象,也可以是函数        */        function hello() {            console.log("你好!");        }        function hello2(functionTest) {            console.log("套娃行为");            functionTest();        }        /*             hello()                - 调用函数,相当于使用函数的返回值            hello                - 函数对象,相当于直接使用函数对象        */        hello2(hello);        // 将一个匿名函数作为实参传递给函数        hello2(function () {            console.log("就是玩!");        })    </script></head><body></body></html>

055 返回值的类型

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>返回值的类型</title>    <script>        /*            break退出当前循环            continue用于跳过当次循环            return可以结束整个函数            返回值可以是任意数据类型,也可以是对象,函数也可以        */        function fun() {            // 在函数内部再声明一个函数            function fun2() {                alert("函数中的函数");            }            // 注意区分            return fun2; // undefined            // return fun2; // 函数对象         }        console.log(fun());        fun()();    </script></head><body></body></html>

056 立即执行函数

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>立即执行函数</title>    <script>        /*             立即执行函数                函数定义完后,立即调用,这种函数叫做立即执行函数,往往只会执行一次        */        // 匿名函数自调用        (function () {            alert("你好");        })();    </script></head><body></body></html>

057 方法

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>方法</title>    <script>        /*             创建对象        */        var obj = new Object();        // 向对象中添加属性        obj.name = "张加林";        obj.age = 20;        obj.sayName = function () {            console.log(obj.name);        };        obj.sayName(); // 调方法        /*            函数也可以称为对象的属性,                如果一个函数作为一个对象的属性保存,那么我们称这个函数是这个对象的方法,调用函数就说调用对象的方法(method),但是他只是名称上的区别而没有其他区别        */    </script></head><body></body></html>

057-2 枚举对象中的属性

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>枚举对象中的属性</title>    <script>        obj = {            name: "张加林",            age: 20,            school: "郫县男子职业技术学院"        };        /*            使用for……in 语句            语法:            for(var 变量 in 对象){                            }            for……in语句中,对象中有几个属性,循环体就会执行几次            每次执行时,会将变量中的一个属性名赋值给变量        */        for (var i in obj) {            console.log(obj[i]);        }    </script></head><body></body></html>

058 全局作用域(scope)

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>全局作用域</title>    <script>        /*            作用域                - 作用域指的是一个变量的作用范围                - 在JS中一共有两种作用域:                    1.全局作用域                        - 直接编写在script标签中的JS代码,都在全局作用域                        - 全局作用域在打开页面时创建,在页面关闭时销毁                        - 在全局作用域中有一个对象window,它代表一个浏览器窗口,它由浏览器创建,我们可以直接使用                        - 在全局作用域中                            创建的变量都会作为window对象的属性值保存                            创建的方法都会作为window对象的方法保存                    2.函数作用域        */        var a = 10, b = 20;        console.log(window.a, window.b, window.c);//千万注意,访问window上不存在的属性值,不会报错,而是返回undefined        function fun() {            console.log("你好");        }        window.fun(); // fun();        window.alert("你好啊");    </script></head><body></body></html>

058(二) 变量声明提前

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>变量声明的提前</title>    <script>        /*             变量声明的提前                - 使用var关键字的变量,会在所有代码执行之前被声明(但是不会赋值),但是如果如果声明变量时不使用var关键字,则变量不会被声明提前            函数的声明提前                - 使用函数声明形式创建的函数function 函数名(){}                    它会在所有代码执行之前就被创建,所以我们可以在函数声明前调用函数                - 使用函数表达式创建的函数不会被声明提前,所以不能在声明前使用                - 全局作用域中的变量都是全局变量                    在页面的任意部分都可以访问到        */        a = 1234; // 相当于window.a = 1234;        console.log(a); // 1234        console.log(b); // undefined        var b = 1;        // console.log(c); // 报错        // c = 1;        fun(); // 正常        fun2(); // 报错        // 函数声明会被提前        function fun() {            console.log("fun函数");        }        // var关键字使得fun2在代码执行前被声明,但是没有赋值,所有不能在声明前调用        var fun2 = function () {            console.log("fun2函数");        }    </script></head><body></body></html>

059 函数作用域(易错易混)

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>函数作用域</title>    <script>        /*            函数作用域                - 调用函数时创建函数作用域,函数执行完毕后,函数作用域销毁                - 每调用一次函数就会创建一个新的函数作用域,他们之间是相互独立的                - 在函数作用域中可以访问到全局作用域中的变量,在全局作用域中无法访问到函数作用域中的变量                - 当在函数作用域中操作一个变量时,它会先在自身作用域中寻找,如果有就直接使用,没有就向上一级作用域中寻找(不一定是全局作用域,因为可以多层嵌套),直到找到全局作用域为止                如果全局作用域中依然没有找到,则会报错                - 在函数中要访问全局变量,可以使用window对象        */        // 创建一个变量        var a = 10;        function fun() {            var a = 2;            var b = 1;            console.log(a); // 2            console.log(window.a);        }        fun();        console.log(a);        // console.log(b); // 报错        /*             在函数作用域中也有声明提前的特性                使用var关键字声明的变量,会在函数所有的代码执行之前被声明                函数声明也会在所有代码执行之前进行        */        function fun1() {            console.log(a); // undefined            var a = 100;        }        function fun2() {            console.log(a);// 10        }        fun1();        fun2();        function fun3() {            fun4();            var a = 35;            function fun4() {                console.log(a); //undefined            }        }        fun3();        /*             函数中不使用var声明的变量都会成为全局变量        */        var c = 33;        function fun5() {            // console.log("c = " + c);            // var c = 10;            console.log("c = " + c); // 33            c = 10;            d = 10;        }        fun5();        console.log(d); // 10        /*             定义形参就相当于在函数作用域中声明了变量        */        var e = 30;        function fun6(e) {            // var e;            alert(e);        }        fun6(); // 弹出undefined        fun6(20); // 弹出20    </script></head><body></body></html>

060 debug

vscode F5

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>debug</title>
<script>
// 易错1
var a = 123;
function fun() {
alert(a); //123
a = 456;
}
fun();
alert(a); // 456

// 易错2
var a = 123;
function fun(a) {
alert(a); // undefined
a = 456; //函数中有a,相当于将函数中的a赋值为456,而不改变全局的a
}
fun();
alert(a); // 123
</script>
</head>
<body>
</body>
</html>

061 this

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>this</title>
<script>
/*
解析器在调用函数时,每次都会向函数内部传递一个隐含的参数
这个隐含的参数是thisthis指向的是一个对象,这个对象我们称为函数执行的上下文对象,根据函数的调用方式的不同,this会指向不同的对象
1.以函数的形式调用时,this永远都是window
1.以方法的形式调用时,this就是调用方法的对象
*/
function fun(a, b) {
// console.log("a = " + a + " b = " + b);
console.log(this);
}
// fun(123, 456);
var obj = {
name: "张加林",
age: 20,
sayName: fun
}
console.log(fun == obj.sayName); // true
fun(); // window
obj.sayName(); // obj
</script>
</head>

<body>

</body>

</html>

062 this补充

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>this补充</title>
<script>
var name = "全局";
function fun() {
console.log(this.name);
}
var obj = {
name: "张加林",
age: 20,
sayName: fun
}
var obj2 = {
name: "zl",
age: 21,
sayName: fun
}
fun(); // 全局
obj.sayName(); // 张加林
obj2.sayName(); // zl
</script>
</head>
<body>
</body>
</html>

063 使用工厂方法创建对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>使用工厂方法创建对象</title>
<script>
/*
使用工厂方法创建对象
*/
function createPerson(myName, age, gender) {
// 创建一个新的对象,以下为简写,本质都是new Object();
return {
name: myName,
age: age,
gender: gender,
sayName: function () {
console.log(this.name);
}
}
}
var obj = createPerson("张加林", 20, "男");
var obj2 = createPerson("zl", 21, "女");

console.log(obj);
console.log(obj2);

obj.sayName();
obj2.sayName();
</script>
</head>
<body>
</body>
</html>

064 构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>构造函数</title>
<script>
/*
使用工厂方法创建的对象使用的构造函数都是Object
所以创建的对象都是Object这个类型,这就导致我们无法区分多种不同类型对象
*/
/*
创建构造函数,专门用来创建Person对象的构造函数就是一个普通的函数,创建方式和普通函数没有区别,
不同的是构造函数习惯上要首字母大写

构造函数和普通函数的区别就是调用方式不同
普通函数是直接调用,而构造函数需要使用new关键字来调用

构造函数执行流程
1.立即创建一个新的对象
2.将新建的对象设置为函数中的this,在构造函数中可以使用this来引用新创建的对象
3.逐行执行函数中的代码
4.将创建的对象作为返回值返回

我们将通过一个构造函数创建的对象,称为构造函数的实例

this的情况:
1.当以函数的形式调用时,thiswindow
2.当以方法的形式调用时,谁调用方法,this就是谁
3.当以构造函数调用时,this就是新创建的那个对象
*/
function Person(pName, age, gender) {
this.name = pName;
this.age = age;
this.gender = gender;
this.sayName = function () {
console.log(this.name);
}
}
function Dog(dName, age, gender) {
this.name = dName;
this.age = age;
this.gender = gender;
this.sayName = function () {
console.log(this.name);
}
}

var p = new Person("张加林", 20, "男");
var d = new Dog("小白", 3, "公");
console.log(p);
console.log(d);

/*
使用instanceof 可以检查一个对象是否是一个类的实例
语法:
对象 instanceof 构造函数
如果是,则返回true,否则返回false

所有对象都是Object的后代
所以任何对象和Objectinstanceof检查都会返回true
*/
console.log(p instanceof Person); // true
console.log(p instanceof Object); // true

console.log(d instanceof Person); // false
console.log(d instanceof Object); // true
</script>
</head>
<body>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>构造函数修改</title>
<script>
function Person(name, age, gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
// 向原型对象中添加sayName方法优化代码
Person.prototype.sayName = function () {
console.log(this.name);
}
var p = new Person("张加林", 20, "男");
var p2 = new Person("zl", 21, "nv");

p.sayName();
p2.sayName();
</script>
</head>
<body>
</body>
</html>

065 构造函数修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>构造函数修改</title>
<script>
/*
创建一个Person构造函数
在person构造函数中,为每一个对象都添加了一个sayName方法,目前我们的方法是在构造函数内部创建的,也就是构造函数每执行一次,就会创建一个新的sayName方法
也就是所有实例的sayName方法是唯一的,这样会导致构造函数每执行一次就会创建一个新的方法,这是完全没有必要的,完全可以使用所有的对象共享同一个方法
*/
function Person(name, age, gender) {
this.name = name;
this.age = age;
this.gender = gender;
}

/*
将函数定义在全局作用域,污染了全局作用域的命名空间
而且定义在全局作用域中也很不安全
*/
function sayName() {
console.log(this.name);
}

var p = new Person("张加林", 20, "男");
var p2 = new Person("zl", 21, "nv");
</script>
</head>
<body>
</body>
</html>

066 原型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>原型对象prototype</title>
<script>
/*
原型prototype

我们所创建的每一个函数,解析器都会向函数中添加一个属性prototype,这个对象就是我们所谓的prototype原型对象,不同的函数有自己不同的prototype
如果函数作为普通函数调用prototype没有任何作用
当函数通过构造函数的形式调用时,他所创建的对象都会有一个隐含的属性,指向该构造函数的原型对象,可以通过__proto__来访问该属性

原型对象就相当于一个公共的区域,所有同一类的实例都可以访问到这个原型对象
我们可以将对象中共有的内容,统一设置到原型对象中

当我们访问对象中的一个属性方法时,它会先在对象自身寻找,如果有则直接使用;如果没有,则会去原型对象中寻找,如果找到则直接使用

以后我们创建构造函数时,可以将这些对象共有的属性和方法统一添加到构造函数的原型对象中,这样不用分别为每一个对象添加,也不会影响到全局作用域,就可以使每个对象都具有这些方法和属性了
*/
function Person() {

}
function MyClass() {

}
console.log(Person.prototype);
console.log(MyClass.prototype);
console.log(MyClass.prototype == Person.prototype); // false

var mc = new MyClass();
var mc2 = new MyClass();
console.log(mc.__proto__);
console.log(mc.__proto__ == MyClass.prototype); // true,说明构造函数指向的原型对象和实例对象指向的原型对象是同一个
console.log(mc.__proto__ == mc2.__proto__); // true

// 向MyClass的原型中添加属性a
MyClass.prototype.a = 123;
console.log(mc.a);

// 向mc中添加a属性
mc.a = "我是mc中的中的a";

// 向MyClass原型中添加一个方法
MyClass.prototype.sayHello = function () {
console.log("hello");
}
mc.sayHello();

</script>
</head>
<body>
</body>
</html>
image-20211008160045997

067 原型对象

image-20211008160238280

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>原型对象</title>    <script>        /*            创建一个构造函数        */        function MyClass() {        }        // 向MyClass的原型中添加一个name属性        MyClass.prototype.name = "我是原型中的名字";        var mc = new MyClass();        console.log(mc.name);        /*             使用in检查对象中是否含有某个属性时,对象中如果没有,但是原型中有的,也会返回true        */        console.log("name" in mc); // true,语法见048        // 可以使用对象的hasOwnProperty()来检查对象自身是否含有该属性,使用该方法只有当对象自身含有属性时,才会返回true        console.log(mc.hasOwnProperty("name")); // false        console.log(mc.hasOwnProperty("hasOwnProperty")); // false        console.log(mc.__proto__.hasOwnProperty("hasOwnProperty")); // false        /*            原型对象也是对象,所以它也有原型                当我在使用一个对象的属性或方法时,会先在自身中寻找                    自身中如果有,则直接使用,                    如果没有,则会去原型对象中寻找,如果原型对象中有则使用,                    如果没有,则回去原型的原型中去寻找,直到找到Object对象的原型,而Object对象的原型没有原型,如果Object中依然没有找到,则返回undefined        */        console.log(mc.__proto__.__proto__.hasOwnProperty("hasOwnProperty")); // true         console.log(mc.__proto__.__proto__); // 其实就是Object对象        console.log(mc.__proto__.__proto__.__proto__); // null    </script></head><body></body></html>

068 toString()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>toString()</title>
<script>
/*

*/
function Person(name, age, gender) {
this.name = name;
this.age = age;
this.gender = gender;
}

// 创建一个Person实例
var per = new Person("张加林", 20, "男");

// 当我们直接在页面中打印一个对象时,实际上输出的是对象的toString()方法的返回值
// 如果我们希望输出对象时不输出[object Object],可以给对象添加一个toString()方法
console.log(per);
console.log(per.toString()); // [object Object]
console.log(per.__proto__.__proto__.hasOwnProperty("hasOwnProperty")); // true

// 修改原型的toString()方法
Person.prototype.toString = function () {
return "Person[name=" + this.name + ",age = " + this.age + ",gender=" + this.gender + "]"
}
console.log(per.toString()); // 你好
console.log(per); //
</script>
</head>
<body>
</body>
</html>

069 垃圾回收

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>垃圾回收</title>
<script>
/*
垃圾回收(GC)
- 就像人的生活中会产生垃圾一样,程序运行过程中也会产生垃圾,这些垃圾积攒过多,会导致程序运行过慢
所以我们需要一个垃圾回收机制,来处理程序运行过程中产生的垃圾
- 当一个对象没有任何变量或属性对它进行引用,此时我们将永远无法操作该对象,此时这种对象就是一种垃圾,这种对象过多会占用大量的内存空间,导致程序运行变缓,必须进行清理
- JS中有自动的垃圾回收机制,会自动将这些;垃圾对象从内存中销毁,我们不需要也不能进行垃圾回收的操作,不同的浏览器回收机制不同
- 我们只需要将不再使用的对象设置为null即可
*/
var obj = new Object();

// 对对象进行一系列操作

obj = null; // 指针断开,堆内存会剩下对象数据,该数据成为垃圾,会被自动回收
</script>
</head>
<body>
</body>
</html>

070 数组

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>数组</title>    <script>        /*            内建对象            宿主对象            自定义对象            数组(Array)                - 数组也是一个对象                - 它和我们普通对象功能类似,也是用来存储一些值的                - 不同的是普通对象是使用字符串作为属性名,而数组是使用数字作为索引来操作元素的                - 索引:                    从0开始的整数就是索引                - 数组的存储性能要优于对象,所以开发中我们经常使用数组来存储一些数据        */        //创建数组对象        var arr = new Array();        // 使用typeof检查数组,将会返回object        console.log(typeof arr);        console.log(arr);        /*            向数组中添加元素            语法:数组[索引] = 值        */        arr[0] = 10;        arr[1] = 110;        arr[2] = 1110;        console.log(arr);        /*            读取数组中的元素            语法:数组[索引]        */        console.log(arr[3]); // 读取不存在索引处的数据,返回undefined        /*             获取数组的长度            可以使用length来获取数组的长度                语法:数组.length            对于连续的数组,使用length可以获取到数组的长度(元素的个数)            对于非连续的数组,使用length会获取数组的最大索引值+1            也可以使用length设置数组的长度            如果修改的length大于原长度,则多余部分会空出来            如果修改的length小于原长度,则多余的元素会被删除        */        console.log(arr.length); // 3        // arr[10] = 32;        console.log(arr.length); // 11        // console.log(arr); // (11) [10, 110, 1110, 空 ×7, 32]        arr.length = 10;        console.log(arr); //(10) [10, 110, 1110, 空 ×7]        // 向数组的最后一个位置添加元素        // 语法:数组[数组.length] = 值;        arr[arr.length] = 11;        console.log(arr); //(11) [10, 110, 1110, 空 ×7, 11]    </script></head><body></body></html>

071 数组字面量

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>数组字面量</title>    <script>        /*            数组字面量        */        // 使用字面量创建一个数组        // 使用字面量创建数组,可以在创建时就指定数组中的元素        var arr = [1, 2, 3, 4, 5, 6];        console.log(typeof arr); // object        /*             使用构造函数创建数组时,也可以同时添加元素,将要添加的元素作为构造函数的参数传递            元素之间使用,隔开        */        var arr2 = new Array(2, 3, 4);        console.log(arr2);        // 创建一个数组,元素只有1个10        arr = [10];        console.log(arr);        arr2 = new Array(10); // 创建一个长度为10的数组        /*             当使用Array()创建数组时,如果只传入一个正整数参数,将创建一个长度为该正整数大小的空数组        */        console.log(arr2); // (10) [空 ×10]        /*             数组中的数据类型可以是任意数据类型,包括对象,函数        */        arr = ["hello", 1, null, undefined, true];        console.log(arr);        arr = [function () { }, function () { }];        console.log(arr);        // arr[0]();        arr = [[1, 3, 4], [2, 23, 45], [3, 34, 434]]; // 二维数组        console.log(arr);        console.log(arr[0][1]);    </script></head><body></body></html>

072 数组的四个方法

image-20211008191530168

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>数组的四个方法</title>    <script>        /*             - push()方法                该方法可以向数组的末尾添加一个或多个元素,并返回数组新的长度                可以将要添加的元素作为方法的参数传递,这样这些元素将会自动添加到数组的末尾        */        var arr = ["a", "b", "c"];        var length = arr.push("d", "e", "f");        console.log(arr, length); // ['a', 'b', 'c', 'd', 'e', 'f'] 6        /*            - pop()方法                该方法可以删除数组的最后一个元素,并将该元素作为返回值返回        */        console.log(arr.pop(), arr.length); // f 5        /*            - unshift()                该方法可以向数组的开头添加一个或多个元素,并返回数组新的长度                向前插入元素后,其他元素索引会依次调整        */        length = arr.unshift("x", "y", "z");        console.log(arr, arr.length); // ['x', 'y', 'z', 'a', 'b', 'c', 'd', 'e'] 8        /*            - shift()                删除并返回数组的第一个元素        */        console.log(arr.shift(), arr.length); // x 7    </script></head><body></body></html>

073 数组的遍历

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>数组的遍历</title>    <script>        // 创建一个数组        var arr = ["a", "b", "c"];        // 所谓遍历数组,就是将数组中所有的元素都取出来        for (var i = 0; i < arr.length; i++) {            console.log(arr[i]);// 遍历        }        for (var i = arr.length; i > 0; i--) {            console.log(arr[i - 1]);// 反向遍历        }    </script></head><body></body></html>

074 练习

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>练习</title>
<script>
function Person(name, age) {
this.name = name;
this.age = age;
}

var p = new Person("a", 8);
var p1 = new Person("b", 18);
var p2 = new Person("c", 28);
var p3 = new Person("d", 38);
var p4 = new Person("e", 15);
var per = [p, p1, p2, p3, p4];

function isAdult(arr) {
var res = [];
for (var i = 0; i < arr.length; i++) {
if (arr[i].age >= 18)
res.push(arr[i]);
}
return res;
}
console.log(isAdult(per));
</script>
</head>
<body>
</body>
</html>

075 forEach

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>forEach</title>    <script>        /*             一般我们都是使用for循环去遍历数组            JS中还为我们提供了一个方法,来遍历数组            forEach()                - 这个方法只支持IE8以上的浏览器                    IE8以下的浏览器不支持该方法,所以如果需要兼容IE8,则最好使用for循环来遍历        */        var arr = ["a", "b", "c", "d", "e", "f"];        /* forEach() 方法需要一个函数作为参数            - 像这种函数,由我们创建但是不由我们调用的,我们称之为回调函数            - 数组中有几个元素,函数就会执行几次,每次执行时,浏览器会将遍历到的元素以实参的形式传递进来,我们可以定义形参来接收这些内容            - 浏览器会在回调函数中传递三个参数                第1个参数:当前正在遍历的元素                第2个参数:当前正在遍历元素的索引                第3个参数:当前正在遍历数组        */        arr.forEach(function (value, index, arr) {            console.log(value, index, arr);        })    </script></head><body></body></html>

076 splice和slice

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>splice和slice</title>    <script>        /*             slice(start,end)                - 可以用来从数组中提取指定的元素,并返回                - 该方法不会改变原数组,而是将截取到的元素封装到一个新的数组中返回                - 参数 [a,b)                    1.截取开始位置的索引,包含开始索引                    2.截取结束位置的索引,不包含结束索引                        -结束索引可以省略不写,此时会截取从开始索引往后的所有元素                    - 索引还可以传递负值,则从后往前计算                        -1倒数第一个                        -2倒数第二个                        ……        */        var arr = ["a", "b", "c", "d", "e", "f"];        console.log(arr.slice(0, 2));        console.log(arr.slice(0, -1)); // ['a', 'b', 'c', 'd', 'e']        console.log(arr.slice(0, -2)); // ['a', 'b', 'c', 'd']        /*             splice()                - 可以删除数组中的指定元素                - 使用splice()方法会影响到原数组,会将指定元素从原数组中删除                    并将被删除元素作为返回值返回                - 参数                 第一个参数:表示开始位置的索引                 第二个参数:表示删除的数量                 第三个参数及其以后:                    可以传递一些新的参数,这些参数会自动插入到开始位置索引前面        */        arr.splice(0, 2, "替换内容1", "替换内容2"); // ['替换内容1', '替换内容2', 'c', 'd', 'e', 'f']        console.log(arr);    </script></head><body></body></html>

077 数组去重练习

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>练习</title>    <script>        var arr = [1, 2, 3, 4, 5, 6, 3, 7, 5, 6, 4, 0, 4, 5, 6, 7, 3, 3, 5];        function deleteRepeat(a) {            for (var i = 0; i < arr.length; i++) {                for (var j = i + 1; j + 1 < arr.length; j++) {                    if (arr[i] == arr[j]) {                        arr.splice(j, 1);                        j--;                    }                }            }        }        deleteRepeat(arr);        console.log(arr);    </script></head><body></body></html>

078 数组的剩余方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>数组剩余方法</title>
<script>
/*
concat()可以连接连接两个或多个数组,并将新的数组返回
- 该方法不会对原数组产生影响
*/

var arr1 = [1, 2, 3, 4, 5];
var arr2 = [3, 4, 5, 6, 7];
var arr3 = [31, 43, 54, 65, 72];
var res = arr1.concat(arr2, arr3, "张加林", "噜噜噜");
console.log(res);

/*
join()将数组所有元素放入一个字符串,元素通过指定的分隔符进行分割
- 该方法可以将数组转换为字符串
- 该方法不会影响原数组,而是将转换后的字符串作为结果返回
- 在join()方法中可以指定一个字符串作为参数,这个字符串将会成为数组中元素的连接符;如果不使用连接符,则默认使用,作为连接符,不想有连接符可以传递空串""作为参数
*/
var res = arr1.join("——");
console.log(res);
console.log(typeof res, typeof arr1);

/*
reverse()颠倒数组中元素的顺序
- 该方法用于反转数组
- 该方法会直接修改原数组
*/
arr1.reverse();
console.log(arr1);

/*
sort():可以用来对原数组进行排序
- 会影响原数组,默认按照unicode编码进行排序
-
*/
arr = ["d", "z", "c", "x", "e"];
arr.sort();
console.log(arr); // ['c', 'd', 'e', 'x', 'z']

/*
即使对于纯数字的数字,使用sort(),也会按照Unicode编码进行排序。
所以对数字进行排序时,可能会得到错误的结果;

我们可以自己指定排序规则
我们可以在sort()中添加一个回调函数,来指定排序规则
回调函数中我们需要定义两个形参,浏览器将会分别使用数组中的元素作为实参去调用回调函数
- 浏览器会根据回调函数的返回值来决定元素的位置顺序位置,
如果返回一个大于0的值,则元素将会交换位置
如果返回一个小于0的值,则位置不变
如果返回一个等于0的值,则认为两个元素相等,也不交换位置

- 如果升序排,返回a-b
如果降序排列,返回b-a
*/
arr = [4, 5];
arr.sort(function (a, b) {
console.log(a);
console.log(b);
});

arr = [3, 5, 6, 11, 4, 2];
arr.sort();// [11, 2, 3, 4, 5, 6]

arr = [3, 5, 6, 11, 4, 2];
arr.sort(function () {
return -1; // [2, 4, 11, 6, 5, 3],相等于reverse
// return 1; // [3, 5, 6, 11, 4, 2],顺序不变
});

arr = [3, 5, 6, 11, 4, 2];
arr.sort(function (a, b) {
// //从小到大排序
// if (a > b) return 1;
// else if (a < b) return -1;
// else return 0;
return a - b; // 简写
});
console.log(arr);
</script>
</head>

<body>

</body>

</html>

079 call()和apply()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>call和apply</title>
<script>
/*
call()和apply()
- 这两个方法都是函数对象的方法,需要通过函数对象来调用
- 当对函数调用call()和apply(),都会调用函数
- 在调用call()和apply()可以将对象指定一个对象为第一参数
此时这个对象将会成为函数执行时的this
- call()方法可以将实参在对象之后依次传递
- apply()方法需要将实参封装到一个数组中统一传递

- this的情况:
1.以函数的形式调用时,this永远都是window
2.以方法的形式调用,this是调用方法的对象
3.以构造函数的方式调用,this是新创建对象
4.使用call和apply调用时,this是指定的对象
*/
function fun() {
console.log(this);
}
fun(); // window
fun.call(); // window
fun.apply(); // window

var obj = {};
fun.call(obj); //obj
fun.apply(obj); // obj

obj = {
name: "张加林",
sayName: function () {
console.log(this.name);
}
};
obj2 = {
name: "zl"
};
obj.sayName(); // 张加林
obj.sayName.apply(obj2); //zl

function fun2(a, b) {
console.log(a);
console.log(b);
}
fun2.call(obj, 2, 3); // 第一个参数往后,剩余的是实参
// fun2.apply(obj, 2, 3); // CreateListFromArrayLike called on non-object
fun2.apply(obj, [2, 3]); // 将参数封装成数组
</script>
</head>
<body>
</body>
</html>

080 arguments

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>argument</title>
<script>
/*
在调用函数时,浏览器每次都会传递两个隐含参数
1.函数的上下文,this
2.封装实参的arguments
- arguments是一个"类"数组对象,它可以通过索引来操作数据,也可以获取长度
- 在调用函数时,我们所传递的实参都会封装到arguments中保存
- arguments.length获取实参的长度,表示传递实参的数目
- 即使不定义形参,也可以通过arguments来使用实参,只是比较麻烦
arguments[0]为第一个实参,依次类推,与定义形参与否无关
- arguments中有一个属性叫callee,
- 这个属性对应一个函数对象,就是当前正在执行的函数的对象
*/
function fun() {
// 检查一个变量是否是数组
console.log(arguments instanceof Array); // false
console.log(Array.isArray(arguments));// false

console.log(arguments.length);
console.log(arguments[0]);
console.log(arguments.callee == fun); //
}
fun(2, 3, 4, 4); // 4j
</script>
</head>
<body>
</body>
</html>

081 Date对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Date对象</title>
<script>
/*
Date对象
- 在JS中使用Date对象来表示一个时间
- 如果直接使用构造函数创建一个Date对象,则会封装为当前代码执行的时间
- 创建一个指定的时间对象,需要在构造函数中传递一个表示时间的字符串作为参数
mm/dd/yyyy hh:mm:ss
*/

// 创建Date对象

var d = new Date();
console.log(d); // Sat Oct 09 2021 21:56:49 GMT+0800

// 创建一个指定的时间对象
var d2 = new Date("10/11/2021 23:11:11");
console.log(d2);// Sun Oct 10 2021 23:11:11 GMT+0800

/*
getDate()
- 获取当前日期对象是几日
*/
var date = d2.getDate();
console.log("date = " + date);

/*
getDay()
- 获取当前日期对象是周几(返回周日0 周一1 周二2 周三3 周四4 周五5 周六6)
*/
var day = d2.getDay();
console.log("day = " + day);

/*
getMonth()
- 获取当前时间对象的月份
- 返回一个0-11的值
0表示月份
1表示2月
……
11表示12月份
*/
var month = d2.getMonth();
console.log(month); // 返回准确月份需要+1

/*
getFullYear()
- 获取当前日期对象的年份
- getYear()废弃
*/
var year = d2.getFullYear();
console.log(year);

/*
getHours()
getMinutes()
getSeconds()
getMillseconds()
getTime()
- 获取当前时间对象的时间戳
- 时间戳timestamp:格林威治标准时间的1970年1月1日0时0分0秒,到当前日期时间所花费的毫秒数
- 1s = 1000ms
- 计算机顶层在保存时间时,使用的都是时间戳
*/
var d3 = new Date("1/1/1970 0:0:0");
console.log(d3.getTime()); // -28800000,误差原因:因为该时间是北京时间,北京时间与格林威治时间有差别

// 获取当前时间戳 Date.now()
// 可以利用当前时间戳来测试代码执行性能,达到console.time()和console.timeEnd()的效果
var startTtime = Date.now();
/*
测试代码块
*/
var endTime = Date.now();
console.log(startTtime - endTime);
</script>
</head>
<body>
</body>
</html>

082 Math对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Math对象</title>
<script>
/*
Math
- Math和其他的对象不同,不是一个构造函数
它属于一个工具类,不用创建对象,里面封装了数学相关的属性和方法
*/
console.log(Math); // Math {abs: ƒ, acos: ƒ, acosh: ƒ, asin: ƒ, asinh: ƒ, …}

/*
Math对象属性
E 返回算数常数e,即自然对数的底数(约等于2.718)
LN2 返回2的自然对数(约等于0.693)
LN10 返回2的自然对数(约等于2.302)
LOG2E 返回以2为底的e的对数(约等于1.414)
LOG10E 返回以10为底的e的对数(约等于0.434)
PI 返回圆周率(约等于3.14159)
SQRT1_2 返回2的平方根的倒数(约等于0.707)
SORT2 返回2的平方根(约等于1.414)
*/

/*
Math.abs()计算一个数的绝对值
Math.ceil() 对一个数进行向上取整,小数位有值就向上进1
Math.floor() 对一个数进行向下取整,小数位部分会被舍弃
相比parseInt()来说,效率高得多,但是处理不了"123px"这种类似的字符串
Math.round() 对数字进行四舍五入取整
Math.random()
- 可以用来生成一个0-1之间的随机数,(0,1)开区间
-
*/
console.log(Math.abs(-1));
console.log(Math.ceil(1.0001)); // 2
console.log(Math.ceil(-1.0001)); // -1
console.log(Math.floor(1.99999)); // 1
console.log(Math.floor(-1.99999)); // -2
console.log(Math.floor("1.99")); // -1
console.log(Math.floor("1.99px")); // NaN

// 生成 0-10 之间的随机数
console.log(Math.round(Math.random() * 10));
// 生成 1-10 之间的随机数
console.log(Math.round(Math.random() * 9) + 1);
console.log(Math.ceil(Math.random() * 10));
/*
生成一个x到y之间的随机数
Math.round(Math.random() * (y - x)) + x
Math.floor(Math.random() * (y - x + 1)) + x
*/
console.log(Math.ceil(Math.random() * 10 + 90));

/* 返回多个值中的最值,
max(x,y)
min(x,y)
*/
console.log(Math.max(1, 3, 64, 545, 545, 45545, 1));

/*
Math.pow(x,y)
返回x的y次幂
Math.sqrt(x)
返回x的平方根
*/
console.log(Math.pow(2, 3));
</script>
</head>
<body>
</body>
</html>

083 包装类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>包装类</title>
<script>
/*
基本数据类型
String Number Boolean Undefined Null
引用数据类型
Object

在Js中为我们提供了包装类,通过包装类,可以将基本数据类型转换为对象
String
- 可以将基本数据类型字符串转换为String对象
Boolean
- 可以将基本数据类型的布尔值转换为布尔值
Number
- 可以将基本数据类型的数字转换为Number对象

注意:我们在实际开发过程中,基本不会使用基本数据类型的对象
如果使用基本数据类型的对象,在做一些比较的时候可能会带来一些不可预料的后果
*/
// 创建一个Number类型的对象
var num = new Number(3);
console.log(num); // Number {3}
console.log(typeof num); // object

var str = new String("你好");
console.log(str);
console.log(typeof str);

var bool = new Boolean(true);
console.log(bool);
console.log(typeof bool);

num.hello = "abcdefghijklmnopqrstuvwxyz";
console.log(num); // {3, hello: 'abcdefghijklmnopqrstuvwxyz'}

var num2 = new Number(3);
console.log(num == num2); // false

var bool2 = true;
console.log(bool == bool2); // true
console.log(bool === bool2); // false

// 自动进行了类型转换,而对象转换为布尔值都是true
var b = new Boolean(false);
if (b) {// 成功执行
console.log("执行");
}

/*
方法和属性只能添加给对象,不能添加给基本数据类型
当我们对一些基本数据类型调用属性和方法,浏览器会临时使用包装类将其转换为对象,然后再调用对象的属性和方法
调用完成后,再将其转换为基本数据类型

由此说明:可以通过基本数据类型直接调用对象的方法
*/
var b = 1234;
b = b.toString();
console.log(b);

b.hello = "你好";
/*
此处由基本数据类型转换为对象,添加hello给对象1,但是添加完毕后,对象1就被销毁了;读取b的hello属性,先将基本数据类型转换为对象2,然后寻找hello属性,但是对象2中没有hello属性,所以返回undefined
*/
console.log(b.hello);
</script>
</head>
<body>
</body>
</html>

084 字符串的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>字符串方法</title>
<script>
var str = "Hello";
/*
在底层字符串是以数组的形式保存的
["H";"e","l","l","o"]
*/
console.log(str.length);
console.log(str[0]); // H

/*
length属性
- 可以用来获取字符串的长度
charAt()
- 可以返回字符串中指定位置的字符
- 根据索引获取指定的字符
- 和[]获取类似
charCodeAt()
- 返回指定位置的Unicode编码
fromCharCode()
- 可以根据字符编码获取字符
concat()
- 用于连接两个或多个字符串
- 不会影响原字符串
- 作用和+号相同
indexOf()
- 该方法可以检索一个字符串中是否含有指定的内容
- 如果含有该字符串,返回其第一次出现的位置
如果没有找到指定的内容,返回-1
- 可以使用第二参数指定开始检索位置
lastIndexOf()
- 该方法的用法和IndexOf()一样
不同的是,indexOf是从前往后检索
lastIndexOf是从后往前检索
- 也可以指定开始检索位置
*/
var zero = str.charAt(0);
console.log(zero); // H

zero = str.charCodeAt(0);
console.log(zero); // 72

var result = String.fromCharCode(12036);// 也可以使用十六进制0x13234
console.log(result); // 乙

result = str.concat("张加林", "zl");
console.log(result); // Hello张加林zl

result = str.indexOf("l");
console.log(result); // 2
result = str.indexOf("l", 3);
console.log(result); // 3

result = str.lastIndexOf("l");
console.log(result); // 3

/*
match()
replace()
search()
三者用于正则表达式部分

slice()
- 可以用于从字符串中截取指定的内容
- 不会影响原字符串,而是将截取到的内容返回
- 参数:
第一个参数,开始位置的索引(包括开始位置)
第二个参数,结束位置的索引(不包括结束位置)
- 如果省略,则会截取到后面所有的字符串
- 也可以传递一个负数作为参数,负数的话会从后边计算
substring()
- 可以用来截取一个字符串,与slice()类似
- 参数:
第一个参数,开始位置的索引(包括开始位置)
第二个参数,结束位置的索引(不包括结束位置)
- 不同的是,substring()不能接收负值作为参数,如果传递负值,则默认使用0
- 而且会自动调整参数的位置,如果第二个参数小于第一个,则自动交换
substr()
- 用来截取字符串
- 参数:
1.截取开始位置的索引
2.截取的长度
small()/big() 用于把字符串显示为大号 / 小号字体
toLocaleLowerCase()/toLocaleUpperCase() 不会改变原字符串,针对地区
toLowerCase()/toUpperCase() 不会改变原字符串
toSource() 返回对象的源代码
toString()
split()
- 可以将一个字符串拆分为一个数组
- 参数:
- 需要一个字符串作为参数,将会根据该字符串拆分数组拆分符号会被删除
- 传递一个空串作为参数,则会将每个字符都拆分为数组中的一个元素
valueOf() 可返回 String 对象的原始值,通常由 JavaScript 在后台自动进行调用,而不是显式地处于代码中
*/
result = str.slice(0, 2);
console.log(result); // He
result = str.slice(2, -1);
console.log(result); // ll

result = str.substring(1, 2);
console.log(result); // e
result = str.substring(1, 0);
console.log(result); // H

result = str.substr(3, 2);
console.log(result, str);

var str2 = "aadf,sdf,fdsafds,fsdsgffg,gdsf";
result = str2.split(",");
console.log(result); // ['aadf', 'sdf', 'fdsafds', 'fsdsgffg', 'gdsf']
console.log(Array.isArray(result)); // true
console.log(str.toLocaleUpperCase()); // HELLO
</script>
</head>
<body>
</body>
</html>

085 正则表达式简介

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<!DOCTYPE html>
<html lang="en">

<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>正则表达式简介</title>
<script>
/*
正则表达式用于定义一些字符串规则:
计算机可以根据正则表达式,来检查一个字符串是否符合规则,
获取将字符串中符合规则的内容提取出来
语法:
var reg = new RegExp("正则表达式","匹配模式");
使用typeof检查正则表达式,将会返回object

正则表达式方法:
- test()
- 使用该方法可以检查一个字符串是否符合正则表达式规则
符合返回true,否则返回false;严格区分大小写
构造函数中可以传递一个匹配模式作为第二参数
可以是
- i 忽略大小写
- g 全局匹配模式
*/
var str = "bab";
var reg = new RegExp("a");

console.log(reg);
console.log(typeof reg); // object
console.log(reg.test(str));
</script>
</head>
<body>
</body>
</html>

086 正则语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>正则语法</title>
<script>
/*
使用字面量创建正则表达式
语法:var 变量 = /正则表达式/匹配模式
使用字面量创建正则表达式更加简单,使用构造函数创建更加灵活(可以传入变量)
*/
// var reg = new RegExp("a","i");
var reg = /a/i;
console.log(typeof reg); // object
console.log(reg.test("abc")); // true

// 创建一个正则表达式来判断一个字符串中是否有a或b或c
/*
使用|来表示或者的意思
*/
reg = /a | b | c/i;
console.log(reg.test("miketaylor")); // true

// 创建一个正则表达式判断字符串中是否有字母
/*
[]里的内容也是或的关系
[a-z]
[A-Z]
[0-9]
*/
reg = /[a-z]/i;
console.log(reg.test("3105085561")); //false

/*
[^ ]除了
*/
reg = /[^ab]/i;
console.log(reg.test("abababABBA")); // false
</script>
</head>
<body>
</body>
</html>

087 字符串和正则相关的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>字符串和正则相关的方法</title>
<script>
/*
search()
- 搜索字符串是否含有指定字符串
- 如果搜索到指定内容返回第一次出现的索引;没有搜索到返回-1
- 可以接收一个正则表达式作为参数,然后根据正则表达式去检索字符串
- search()只会查找第一个,即使设置全局匹配也没用
match()
- 可以根据正则表达式,从一个字符串中,将符合条件的内容提取出来
- 默认情况下我们的match只会找到第一个符合要求的内容,找到以后就停止检索;为此我没可以设正则表达式为全局匹配模式,这样就会匹配到所有内容
可以为一个正则表达式设置多个匹配模式,且顺序无所谓
- match()会将匹配到的内容封装到一个数组中,即使只返回一个结果
- 默认情况下,我们的match()只会找到第一个符合条件的内容,找到以后就会停止检索,所以我们可以设置正则表达式为全局匹配模式,这样就可以匹配到所有的内容
- 可以为一个正则表达式设置多个匹配模式,且顺序无所谓
replace()
- 可以将字符串中指定内容替换为新的内容
- 参数:
1.被替换的内容,可以接收一个正则表达式作为参数
2.新的内容
- 默认只会替换第一个,可以设置全局匹配模式
split()
- 根据一个规则将一个字符串拆分为一个数组
- 方法中可以传递一个正则表达式作为参数去拆分字符串
- 该方法即使不指定全局匹配模式,也会全都拆分
*/
var str = 'das1fdsa4d2gsfds1af2gdd2sdgfdsf';
var res = str.split(/[a-z]+/);
console.log(res);

str = "abc adc abf adc alc apl afi aef";
console.log(str.search(/a[de]c/));
console.log(str.match(/a[de]c/g));

res = str.replace(/a[de]c/g, "@@@@@@");
console.log(res);
</script>
</head>
<body>
</body>
</html>

088 正则表达式语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>正则表达式语法</title>
<script>
/*
量词:
- 通过量词可以设置一个内容出现的次数
{a,b}:出现a次到b次之间
{c}:刚好出现c次
{m,}:m次以上
n+:匹配任何包含至少一个n的字符串
n*:匹配任何包含0个或多个的字符串
n?:匹配任何包含零个或一个的字符串
n$:匹配任何结尾为n的字符串
^n:匹配任何开头为n的字符串
如果在正则表达式中同时使用^$,则要求字符串必须完全符合正则表达式
?=n:匹配任何其后紧接字符串n的字符串
?!n:匹配任何其后没有紧接指定字符串n的字符串
- 量词只对前面的一个内容起作用
原子组
*/
</script>
</head>
<body>
</body>
</html>

089 正则表达式语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>正则表达式(二)</title>
<script>
/*
.:表示除换行符外的其他任何字符
可以使用转义字符\
\. 表示.
\\ 表示\

注意:使用构造函数时,由于它的参数是一个字符串,而\则需要使用\\来代替。例如,使用构造函数检查字符串是否含有.:new RegExp("\\.");

\w:英文字母数字下划线
\W:英文字母数字下划线
\d:任意数字
\D:除了数字
\s:任意一个空白字符匹配,如空格,制表符\t,换行符\n
\S:除了空白符外任意一个字符匹配
\b:单词边界
\B:除了单词边界
*/
var reg = /\./;
console.log(reg); // /\./
reg = /\\/;

console.log(reg.test("b.\\")); // true,注意:字符串中的\也需要进行转义

reg = new RegExp("\.");
console.log(reg); // /./

reg = new RegExp("\\.");
console.log(reg); // /\./

reg = /\bchild\b/;
console.log(reg.test("hello children")); //false

// 去除前后空格
var str = " mike taylor ";
str = str.replace(/^\s+/g, "");
str = str.replace(/\s+$/g, "");
// str = str.replace(/^\s+ | \s+$/g, "");
console.log(str);
</script>
</head>
<body>
</body>
</html>

090 邮件的正则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>邮件正则</title>
<script>
/*
规则:
- 任意字母数字下划线 . 任意字母数字下划线 @ 任意字母数字. (com|edu|org|net……).cn
*/
var reg = /^\w{3,}(\.\w+)*@[A-z0-9]+(\.[A-z]{2,5}){1,2}$/;
var str = "3105085561@qq.com";
console.log(reg.test(str));
</script>
</head>
<body>
</body>
</html>

091 DOM简介

DOM树

image-20211018031802691

image-20211018031627903 image-20211018031837875 image-20211018031954554 image-20211018032046035 image-20211018112343559 image-20211018112404106 image-20211018112429710 image-20211018112447401
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DOM简介</title>
</head>

<body>
<button id="btn">我是一个按钮</button>
<script>
/*
DOM:全称Document Object Model文档对象模型
JS中通过DOM来对HTML文档进行操作。只要理解了DOM就可以随心所欲的操作WEB界面了。
文档:文档表示的是整个的HTML网页文档
对象:对象表示将网页中的每一个部分都转换为了一个对象(包括注释)
模型:使用模型来表示对象之间的关系,这样方便我们获取对象
*/

/*
浏览器已经为我们提供了文档节点对象,这个对象是window的属性,可以直接在页面中使用,文档节点代表的是整个网页。
*/
// console.log(document); // #document

// 获取button对象
var btn = document.getElementById("btn");
console.log(btn);

// 修改按钮文字,innerHTML代表btn内部的button代码
btn.innerHTML = "你好";
</script>
</body>

</html>

092 事件简介

image-20211018083614594 image-20211018084515816 image-20211018112934366
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>事件的简介</title>

<body>
<!-- 我们可以在事件对应的属性中设置一些js代码,这样当事件被触发时,这些代码将会执行
-->
<button id="miketaylor" onclick="">这是一个button</button>
<script>
/*
事件,就是用户和浏览器之间的交互行为
比如:点击按钮、鼠标移动、关闭窗口……
*/

// 获取按钮对象
var btn = document.getElementById("miketaylor");
/*
可以为按钮对应的事件绑定处理函数的形式来响应事件
这样当事件被触发时,其对应的函数将会被调用
*/
// 绑定一个单击事件
// 像这种单击事件绑定的函数,我们称为单击响应函数
console.log(btn);
btn.onclick = function () {
console.log("按钮事件触发");
}
</script>
</body>

</html>

093 文档的加载

image-20211018103808551 image-20211018103910552

因为浏览器在加载一个页面时,是按照自上而下的顺序加载的,读取到一行就运行一行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>文档的加载</title>
<script>
/*
浏览器在加载一个页面时,是按照自上而下的顺序加载的,读取到一行就运行一行,如果将script标签写到页面的上边,在代码执行时,页面还没有加载,页面没有加载DOM对象也没有加载会导致无法获取DOM对象
*/

/*
onload事件会在整个页面加载完成后才触发
window绑定一个onload事件
该事件对应的响应函数将会在页面加载完成后执行,这样可以确保我们的代码执行时所有的DOM对象已经加载完毕
*/
window.onload = function () {
var btn = document.getElementById("miketaylor");
console.log(btn);
btn.onclick = function () {
console.log("按钮事件触发");
}
}
</script>
</head>

<body>
<button id="miketaylor" onclick="">这是一个button</button>
<!-- <script>
/*
将js代码写到页面的下部就是为了,可以在页面加载完毕以后再执行js代码
性能相对写在onload中较好
*/

/*
浏览器在加载一个页面时,是按照自上而下的顺序加载的,读取到一行就运行一行,如果将script标签写到页面的上边,在代码执行时,页面还没有加载
*/
var btn = document.getElementById("miketaylor");
console.log(btn);
btn.onclick = function () {
console.log("按钮事件触发");
}
</script> -->
</body>
</html>

094 DOM查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>DOM查询</title>
<link rel="stylesheet" type="text/css" href="css/css.css" />
<script type="text/javascript">

window.onload = function () {

//为id为btn01的按钮绑定一个单击响应函数
var btn01 = document.getElementById("btn01");
btn01.onclick = function () {
//查找#bj节点
var bj = document.getElementById("bj");
//打印bj
//innerHTML 通过这个属性可以获取到元素内部的html代码
alert(bj.innerHTML);
};


//为id为btn02的按钮绑定一个单击响应函数
var btn02 = document.getElementById("btn02");
btn02.onclick = function () {
//查找所有li节点
//getElementsByTagName()可以根据标签名来获取一组元素节点对象
//这个方法会给我们返回一个类数组对象,所有查询到的元素都会封装到对象中
//即使查询到的元素只有一个,也会封装到数组中返回
var lis = document.getElementsByTagName("li");

//打印lis
//alert(lis.length);

//变量lis
for (var i = 0; i < lis.length; i++) {
alert(lis[i].innerHTML);
}
};


//为id为btn03的按钮绑定一个单击响应函数
var btn03 = document.getElementById("btn03");
btn03.onclick = function () {
//查找name=gender的所有节点
var inputs = document.getElementsByName("gender");

//alert(inputs.length);

for (var i = 0; i < inputs.length; i++) {
/*
* innerHTML用于获取元素内部的HTML代码的
* 对于自结束标签,这个属性没有意义
*/
//alert(inputs[i].innerHTML);
/*
* 如果需要读取元素节点属性,
* 直接使用 元素.属性名
* 例子:元素.id 元素.name 元素.value
* 注意:class属性不能采用这种方式,读取class属性时需要使用 元素.className !!!
*/
alert(inputs[i].className);
// alert(inputs[i].value);
// alert(inputs[i].name);
// alert(inputs[i].id);
}
};

//查找#city下所有li节点
//返回#city的所有子节点
//返回#phone的第一个子节点
//返回#bj的父节点
//返回#android的前一个兄弟节点
//读取#username的value属性值
//设置#username的value属性值
//返回#bj的文本值
};


</script>
</head>

<body>
<div id="total">
<div class="inner">
<p>
你喜欢哪个城市?
</p>

<ul id="city">
<li id="bj">北京</li>
<li>上海</li>
<li>东京</li>
<li>首尔</li>
</ul>

<br>
<br>

<p>
你喜欢哪款单机游戏?
</p>

<ul id="game">
<li id="rl">红警</li>
<li>实况</li>
<li>极品飞车</li>
<li>魔兽</li>
</ul>

<br />
<br />

<p>
你手机的操作系统是?
</p>

<ul id="phone">
<li>IOS</li>
<li id="android">Android</li>
<li>Windows Phone</li>
</ul>
</div>

<div class="inner">
gender:
<input class="hello" type="radio" name="gender" value="male" />
Male
<input class="hello" type="radio" name="gender" value="female" />
Female
<br>
<br>
name:
<input type="text" name="name" id="username" value="abcde" />
</div>
</div>
<div id="btnList">
<div><button id="btn01">查找#bj节点</button></div>
<div><button id="btn02">查找所有li节点</button></div>
<div><button id="btn03">查找name=gender的所有节点</button></div>
<div><button id="btn04">查找#city下所有li节点</button></div>
<div><button id="btn05">返回#city的所有子节点</button></div>
<div><button id="btn06">返回#phone的第一个子节点</button></div>
<div><button id="btn07">返回#bj的父节点</button></div>
<div><button id="btn08">返回#android的前一个兄弟节点</button></div>
<div><button id="btn09">返回#username的value属性值</button></div>
<div><button id="btn10">设置#username的value属性值</button></div>
<div><button id="btn11">返回#bj的文本值</button></div>
</div>
</body>
</html>

095 图片切换练习

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=\
, initial-scale=1.0">
<title>图片切换练习</title>
<style>
* {
margin: 0;
padding: 0;
}

.container {
width: 500px;
margin: 50px auto;
text-align: center;
background-color: rgb(122, 161, 240);
padding: 10px;
}

img {
width: 100%;
}
</style>
<script>
window.onload = function () {
/*
点击按钮切换图片
*/
var imgArr = ["./img/1.png", "./img/2.png", "./img/3.png", "./img/4.png"], index = 0;
// 获取按钮
var prev = document.getElementById("prev");
var next = document.getElementById("next");

/*
要切换图片就是要修改img标签的src属性
要修改一个元素的属性:元素.属性 = 属性值
*/
// 取出img标签
var img = document.getElementsByTagName("img")[0];
prev.onclick = function () {
img.src = imgArr[(index - 1 < 0) ? (index = imgArr.length - 1) : (--index)];
}
next.onclick = function () {
img.src = imgArr[(index + 1 == imgArr.length) ? (index = 0) : (++index)];
}
}
</script>
</head>

<body>
<div class="container">
<img src="./img/1.png" alt="1">
<button id="prev">上一张</button>
<button id="next">下一张</button>
</div>
</body>

</html>

096-097 DOM查询

image-20211018165105237

getElementById

innerHTML

innerText

getElementsByTagName:可以根据标签名来获取一组元素节点对象

getElementsByName:根据name属性获取一组元素节点对象

childNodes:属性会获取包括文本节点在内的所有节点

children:属性可以获取当前元素的所有子元素

firstChild:firstChild可以获取到当前元素的第一个子节点(包括空白文本节点)

firstElementChild:获取当前元素的第一个子元素

parentNode:父节点

previousSibling

nextSibling

nextElementSibling:previousElementSibling获取前一个兄弟元素,IE8及以下不支持

nodeValue:获取文本节点的文本内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>DOM查询</title>
<link rel="stylesheet" type="text/css" href="css/css.css" />
<script type="text/javascript">

/*
* 定义一个函数,专门用来为指定元素绑定单击响应函数
* 参数:
* idStr 要绑定单击响应函数的对象的id属性值
* fun 事件的回调函数,当单击元素时,该函数将会被触发
*/
function myClick(idStr, fun) {
var btn = document.getElementById(idStr);
btn.onclick = fun;
}

window.onload = function () {

//为id为btn01的按钮绑定一个单击响应函数
var btn01 = document.getElementById("btn01");
btn01.onclick = function () {
//查找#bj节点
var bj = document.getElementById("bj");
//打印bj
//innerHTML 通过这个属性可以获取到元素内部的html代码
alert(bj.innerHTML);
};


//为id为btn02的按钮绑定一个单击响应函数
var btn02 = document.getElementById("btn02");
btn02.onclick = function () {
//查找所有li节点
//getElementsByTagName()可以根据标签名来获取一组元素节点对象
//这个方法会给我们返回一个类数组对象,所有查询到的元素都会封装到对象中
//即使查询到的元素只有一个,也会封装到数组中返回
var lis = document.getElementsByTagName("li");

//打印lis
//alert(lis.length);

//变量lis
for (var i = 0; i < lis.length; i++) {
alert(lis[i].innerHTML);
}
};


//为id为btn03的按钮绑定一个单击响应函数
var btn03 = document.getElementById("btn03");
btn03.onclick = function () {
//查找name=gender的所有节点
var inputs = document.getElementsByName("gender");

//alert(inputs.length);

for (var i = 0; i < inputs.length; i++) {
/*
* innerHTML用于获取元素内部的HTML代码的
* 对于自结束标签,这个属性没有意义
*/
//alert(inputs[i].innerHTML);
/*
* 如果需要读取元素节点属性,
* 直接使用 元素.属性名
* 例子:元素.id 元素.name 元素.value
* 注意:class属性不能采用这种方式,
* 读取class属性时需要使用 元素.className
*/
alert(inputs[i].className);
}
};

//为id为btn04的按钮绑定一个单击响应函数
var btn04 = document.getElementById("btn04");
btn04.onclick = function () {

//获取id为city的元素
var city = document.getElementById("city");

//查找#city下所有li节点
var lis = city.getElementsByTagName("li");

for (var i = 0; i < lis.length; i++) {
alert(lis[i].innerHTML);
}

};

//为id为btn05的按钮绑定一个单击响应函数
var btn05 = document.getElementById("btn05");
btn05.onclick = function () {
//获取id为city的节点
var city = document.getElementById("city");
//返回#city的所有子节点
/*
* childNodes属性会获取包括文本节点在内的所有节点
* 根据DOM标签标签间空白也会当成文本节点
* 注意:在IE8及以下的浏览器中,不会将空白文本当成子节点,
* 所以该属性在IE8中会返回4个子元素而其他浏览器是9个
*/
var cns = city.childNodes;

//alert(cns.length);

/*for(var i=0 ; i<cns.length ; i++){
alert(cns[i]);
}*/

/*
* children属性可以获取当前元素的所有子元素
*/
var cns2 = city.children;
alert(cns2.length); //4
};

//为id为btn06的按钮绑定一个单击响应函数
var btn06 = document.getElementById("btn06");
btn06.onclick = function () {
//获取id为phone的元素
var phone = document.getElementById("phone");
//返回#phone的第一个子节点
//phone.childNodes[0];
//firstChild可以获取到当前元素的第一个子节点(包括空白文本节点)
// 子节点包括文本节点,子元素不包括文本节点
var fir = phone.firstChild;

//firstElementChild获取当前元素的第一个子元素
/*
* firstElementChild不支持IE8及以下的浏览器,
* 如果需要兼容他们尽量不要使用
*/
//fir = phone.firstElementChild;

alert(fir);
};

//为id为btn07的按钮绑定一个单击响应函数
myClick("btn07", function () {

//获取id为bj的节点
var bj = document.getElementById("bj");

//返回#bj的父节点,一定是元素节点,不可能是文本节点;而且只有唯一一个返回元素节点
var pn = bj.parentNode;

alert(pn.innerHTML);

/*
* innerText
* - 该属性可以获取到元素内部的文本内容
* - 它和innerHTML类似,不同的是它会自动将html去除
*/
//alert(pn.innerText);
});


//为id为btn08的按钮绑定一个单击响应函数
myClick("btn08", function () {

//获取id为android的元素
var and = document.getElementById("android");

//返回#android的前一个兄弟节点(也可能获取到空白的文本)
var ps = and.previousSibling;

//previousElementSibling获取前一个兄弟元素,IE8及以下不支持
//var pe = and.previousElementSibling;

alert(ps);

});

//读取#username的value属性值
myClick("btn09", function () {
//获取id为username的元素
var um = document.getElementById("username");
//读取um的value属性值
//文本框的value属性值,就是文本框中填写的内容
alert(um.value);
});


//设置#username的value属性值
myClick("btn10", function () {
//获取id为username的元素
var um = document.getElementById("username");

um.value = "今天天气真不错~~~";
});


//返回#bj的文本值
myClick("btn11", function () {

//获取id为bj的元素
var bj = document.getElementById("bj");

//alert(bj.innerHTML);
//alert(bj.innerText);

//获取bj中的文本节点
/*var fc = bj.firstChild;
alert(fc.nodeValue);*/

alert(bj.firstChild.nodeValue);
});

};


</script>
</head>

<body>
<div id="total">
<div class="inner">
<p>
你喜欢哪个城市?
</p>

<ul id="city">
<li id="bj">北京</li>
<li>上海</li>
<li>东京</li>
<li>首尔</li>
</ul>

<br>
<br>

<p>
你喜欢哪款单机游戏?
</p>

<ul id="game">
<li id="rl">红警</li>
<li>实况</li>
<li>极品飞车</li>
<li>魔兽</li>
</ul>

<br />
<br />

<p>
你手机的操作系统是?
</p>

<ul id="phone">
<li>IOS</li>
<li id="android">Android</li>
<li>Windows Phone</li>
</ul>
</div>

<div class="inner">
gender:
<input class="hello" type="radio" name="gender" value="male" />
Male
<input class="hello" type="radio" name="gender" value="female" />
Female
<br>
<br>
name:
<input type="text" name="name" id="username" value="abcde" />
</div>
</div>
<div id="btnList">
<div><button id="btn01">查找#bj节点</button></div>
<div><button id="btn02">查找所有li节点</button></div>
<div><button id="btn03">查找name=gender的所有节点</button></div>
<div><button id="btn04">查找#city下所有li节点</button></div>
<div><button id="btn05">返回#city的所有子节点</button></div>
<div><button id="btn06">返回#phone的第一个子节点</button></div>
<div><button id="btn07">返回#bj的父节点</button></div>
<div><button id="btn08">返回#android的前一个兄弟节点</button></div>
<div><button id="btn09">返回#username的value属性值</button></div>
<div><button id="btn10">设置#username的value属性值</button></div>
<div><button id="btn11">返回#bj的文本值</button></div>
</div>
</body>

</html>

098 - 100 全选练习

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>全选练习</title>
<script type="text/javascript">

window.onload = function () {
/*
全选按钮:
- 点击按钮后,四个多选框全都被选中
*/

//1.#checkedAllBtn
// 为id为checkedAllBtn的按钮绑定一个单击响应函数
var checkedAllBox = document.getElementById("checkedAllBox");
var checkAllBtn = document.getElementById("checkedAllBtn");
checkedAllBtn.onclick = function () {
// 获取四个多选框items
var items = document.getElementsByName("items");
// alert(items.length);

// 遍历items
for (var i = 0; i < items.length; i++) {
// 设置四个多选框1变为选中状态
// 通过多选框的checked属性可以来获取或设置多选框的选中状态
items[i].checked = true;
}
checkedAllBox.checked = true;
}


//2.#checkedNoBtn
var checkedNoBtn = document.getElementById("checkedNoBtn");
checkedNoBtn.onclick = function () {
var items = document.getElementsByName("items");
for (var i = 0; i < items.length; i++) {
items[i].checked = false;
}
checkedAllBox.checked = false;
}

//3.#checkedRevBtn
var checkedRevBtn = document.getElementById("checkedRevBtn");
checkedRevBtn.onclick = function () {
var items = document.getElementsByName("items");
for (var i = 0; i < items.length; i++) {
items[i].checked = items[i].checked ? false : true;
}
}

//4.#sendBtn
var sendBtn = document.getElementById("sendBtn");
sendBtn.onclick = function () {
var items = document.getElementsByName("items");
for (var i = 0; i < items.length; i++) {
if (items[i]) {
alert(items[i].value);
}
}
}

//5.#checkedAllBox
/*
全选/全不选
- 当它选中时,其余的也选中;当它取消时,其余的也取消

在事件的响应函数中,响应函数是给谁绑定的,this就是谁
*/
checkedAllBox.onclick = function () {
// 设置多选框的选中状态
var items = document.getElementsByName("items");
for (var i = 0; i < items.length; i++) {
items[i].checked = checkedAllBox.checked;
}

console.log(this === checkedAllBox); // true
};

//6.items
// 如果四个多选框都选中,则checkedAllBox也应该选中;如果四个多选框都没选中,则checkedAllBox也不应该选中
var items = document.getElementsByName("items");
for (var i = 0; i < items.length; i++) {
items[i].onclick = function () {
checkedAllBox.checked = true;

for (var j = 0; j < items.length; j++) {
// 判断四个多选框是否全选
// 只要有一个未选中就不是全选
if (!items[j].checked) {
// 一旦进入判断,则证明不是全选状态,将checkedAllBox设置为未选中状态
checkedAllBox.checked = false;
break;
}
}
}
}
}
</script>
</head>

<body>

<form method="post" action="">
你爱好的运动是?<input type="checkbox" id="checkedAllBox" />全选/全不选

<br />
<input type="checkbox" name="items" value="足球" />足球
<input type="checkbox" name="items" value="篮球" />篮球
<input type="checkbox" name="items" value="羽毛球" />羽毛球
<input type="checkbox" name="items" value="乒乓球" />乒乓球
<br />
<input type="button" id="checkedAllBtn" value="全 选" />
<input type="button" id="checkedNoBtn" value="全不选" />
<input type="button" id="checkedRevBtn" value="反 选" />
<input type="button" id="sendBtn" value="提 交" />
</form>
</body>
</html>

101 DOM查询的剩余方法

document.allimage-20211018212538651

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DOM查询剩余方法</title>
<script>
/*

*/
window.onload = function () {
// 获取body标签
var body1 = document.getElementsByTagName("body")[0];
console.log(body1);

/*
document中有一个属性body,它保存的是body的引用
*/
var body2 = document.body;
console.log(body1 === body2); // true

/*
body.documentElement保存的是html的根标签
*/
var html = document.documentElement;
console.log(html);

/*
document.all代表页面中的所有元素,但是目前已废弃
*/
var all1 = document.all;
console.log(all1, all1.length); // HTMLAllCollection(8) 8
var all2 = document.getElementsByTagName("*");// 和document.all差不多,都是代表页面中的所有元素,可以使用它代替all的效果

/*
根据元素的class属性值查询一组元素节点对象
getElementsByClassName()可以根据class属性值获取一组元素节点对象,但是该方法不支持IE8及其以下版本浏览器
*/
var box1 = document.getElementsByClassName("mk");
console.log(box1.length); // 3

/*
querySelector()
- 需要一个选择器的字符串作为参数,可以根据一个CSS选择器!!!来查询一个元素节点对象
- 虽然IE8中没有getElementsByClassName()但是可以使用querySelector()代替
- 注意:使用该方法总会返回唯一的一个元素,如果有多个元素满足条件,则只会返回第一个满足的对象
*/
var s_div = document.querySelector(".ycy");
console.log(s_div);

/*
document.querySelectorAll()该方法和querySelector()用法相似,不同的是它会将符合条件的元素封装为一个数组,即使返回的数组只有一个元素
*/
var mk_div = document.querySelectorAll(".mk");
console.log(mk_div.length);

}
</script>
</head>
<body>
<div class="mk ycy">
<div></div>
</div>
<div class="mk"></div>
<div class="mk"></div>
</body>
</html>

102 DOM增删改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>DOM增删改</title>
<link rel="stylesheet" type="text/css" href="css/css.css" />
<script type="text/javascript">

window.onload = function () {

//创建一个"广州"节点,添加到#city下
myClick("btn01", function () {
//创建广州节点 <li>广州</li>
//创建li元素节点
/*
* document.createElement()
* 可以用于创建一个元素节点对象,
* 它需要一个标签名作为参数,将会根据该标签名创建元素节点对象,
* 并将创建好的对象作为返回值返回
*/
var li = document.createElement("li");

//创建广州文本节点
/*
* document.createTextNode()
* 可以用来创建一个文本节点对象
* 需要一个文本内容作为参数,将会根据该内容创建文本节点,并将新的节点返回
*/
var gzText = document.createTextNode("广州");

//将gzText设置li的子节点
/*
* appendChild()
* - 向一个父节点中添加一个新的子节点
* - 用法:父节点.appendChild(子节点);
*/
li.appendChild(gzText);

//获取id为city的节点
var city = document.getElementById("city");

//将广州添加到city下
city.appendChild(li);
});

//将"广州"节点插入到#bj前面
myClick("btn02", function () {
//创建一个广州
var li = document.createElement("li");
var gzText = document.createTextNode("广州");
li.appendChild(gzText);

//获取id为bj的节点
var bj = document.getElementById("bj");

//获取city
var city = document.getElementById("city");

/*
* insertBefore()
* - 可以在指定的子节点前插入新的子节点
* - 语法:
* 父节点.insertBefore(新节点,旧节点);
*/
city.insertBefore(li, bj);
});


//使用"广州"节点替换#bj节点
myClick("btn03", function () {
//创建一个广州
var li = document.createElement("li");
var gzText = document.createTextNode("广州");
li.appendChild(gzText);

//获取id为bj的节点
var bj = document.getElementById("bj");

//获取city
var city = document.getElementById("city");

/*
* replaceChild()
* - 可以使用指定的子节点替换已有的子节点
* - 语法:父节点.replaceChild(新节点,旧节点);
*/
city.replaceChild(li, bj);
});

//删除#bj节点
myClick("btn04", function () {
//获取id为bj的节点
var bj = document.getElementById("bj");
//获取city
var city = document.getElementById("city");

/*
* removeChild()
* - 可以删除一个子节点
* - 语法:父节点.removeChild(子节点);
*
* 子节点.parentNode.removeChild(子节点);
*/
//city.removeChild(bj);

bj.parentNode.removeChild(bj);
});


//读取#city内的HTML代码
myClick("btn05", function () {
//获取city
var city = document.getElementById("city");

alert(city.innerHTML);
});

//设置#bj内的HTML代码
myClick("btn06", function () {

//获取bj
var bj = document.getElementById("bj");
bj.innerHTML = "昌平";
});

myClick("btn07", function () {
/*
createElement()创建元素节点,使用innerHTML添加文本节点,然后appendChild()
*/

//向city中添加广州
var city = document.getElementById("city");

/*
* 使用innerHTML也可以完成DOM的增删改的相关操作
* 一般我们会两种方式结合使用
*/
//city.innerHTML += "<li>广州</li>";

//创建一个li
var li = document.createElement("li");
//向li中设置文本
li.innerHTML = "广州";
//将li添加到city中
city.appendChild(li);
});
};

function myClick(idStr, fun) {
var btn = document.getElementById(idStr);
btn.onclick = fun;
}

</script>
</head>

<body>
<div id="total">
<div class="inner">
<p>
你喜欢哪个城市?
</p>
<ul id="city">
<li id="bj">北京</li>
<li>上海</li>
<li>东京</li>
<li>首尔</li>
</ul>
</div>
</div>
<div id="btnList">
<div><button id="btn01">创建一个"广州"节点,添加到#city下</button></div>
<div><button id="btn02">将"广州"节点插入到#bj前面</button></div>
<div><button id="btn03">使用"广州"节点替换#bj节点</button></div>
<div><button id="btn04">删除#bj节点</button></div>
<div><button id="btn05">读取#city内的HTML代码</button></div>
<div><button id="btn06">设置#bj内的HTML代码</button></div>
<div><button id="btn07">创建一个"广州"节点,添加到#city下</button></div>
</div>
</body>
</html>

document.createElement

document.createTextNode

appendChild:

​ 父节点.appendChild(节点);

insertBefore:

​ 父节点.insertBefore(新节点,旧节点);

​ 旧节点.parentNode.insertBefore(新节点,旧节点);

replaceChild:

​ 父节点.replaceChild(新节点,旧节点);

​ 旧节点.parentNode.replaceChild(新节点,旧节点);

removeChild:

​ 子节点.parentNode.removeChild(子节点);

​ 父节点.removeChild(子节点);

103-106 添加删除记录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>添加删除记录练习</title>
<link rel="stylesheet" type="text/css" href="css/1.css" />
<script type="text/javascript">

window.onload = function () {
/*
点击超链接删除一个员工信息
*/
// 获取所有超链接
var allA = document.getElementsByTagName("a");
// 为每个超链接都绑定一个单击响应函数
for (var i = 0; i < allA.length; i++) {
allA[i].onclick = function () {
/*
点击超链接之后需要删除超链接所在行

注意:在事件的响应函数中,响应函数是给谁绑定的,this就是谁
*/

/*
点击超链接会跳转页面,这是超链接的默认行为,但是此时不希望出现默认行为,可以通过return false来取消默认行为。
或者可以使用:<a href="javascript:;"></a>来取消默认行为
*/

// 删除之前弹出提示框
/*
confirm用于弹出一个带有确认和取消按钮的提示框,需要字符串作为参数,该参数将会作为提示文字显示出来

用户点击确认返回true,如果点击取消返回false
*/
var parentTr = this.parentNode.parentNode;
if (confirm("确认删除" + parentTr.getElementsByTagName("td")[0].innerHTML + "吗?")) {
// 获取当前tr
parentTr.parentNode.removeChild(parentTr);
}
return false;
}
}

/*
添加员工信息功能
- 点击按钮后,将员工的信息添加到表格中
*/
// 为提交按钮以后,将员工的信息添加到表格中
var addEmpButton = document.getElementById("addEmpButton");
addEmpButton.onclick = function () {
// 获取表单内容
var name = document.getElementById("empName").value;
var email = document.getElementById("email").value;
var salary = document.getElementById("salary").value;
var tableList = document.getElementById("employeeTable");

/*
<tr>
<td>Tom</td>
<td>tom@.com</td>
<td>5000</td>
<td><a href="deleteEmp?id=001">Delete</a></td>
</tr>
需要将获取到的信息保存到tr中

向a标签中添加href属性:a.href = 属性值
*/
var tr = document.createElement("tr");
var td1 = document.createElement("td");
td1.innerHTML = name;
var td2 = document.createElement("td");
td2.innerHTML = email;
var td3 = document.createElement("td");
td3.innerHTML = salary;
var td4 = document.createElement("td");
td4.innerHTML = `<a href="deleteEmp?id=001">Delete</a>`;
tr.appendChild(td1);
tr.appendChild(td2);
tr.appendChild(td3);
tr.appendChild(td4);
tableList.children[0].appendChild(tr);

// 为新信息添加点击事件
td4.children[0].onclick = function () {
var parentTr = this.parentNode.parentNode;
if (confirm("确认删除" + parentTr.getElementsByTagName("td")[0].innerHTML + "吗?")) {
parentTr.parentNode.removeChild(parentTr);
}
return false;
}
}

};


</script>
</head>

<body>

<table id="employeeTable">
<tr>
<th>Name</th>
<th>Email</th>
<th>Salary</th>
<th>&nbsp;</th>
</tr>
<tr>
<td>Tom</td>
<td>tom@.com</td>
<td>5000</td>
<td><a href="deleteEmp?id=001">Delete</a></td>
</tr>
<tr>
<td>Jerry</td>
<td>jerry@sohu.com</td>
<td>8000</td>
<td><a href="deleteEmp?id=002">Delete</a></td>
</tr>
<tr>
<td>Bob</td>
<td>bob@tom.com</td>
<td>10000</td>
<td><a href="deleteEmp?id=003">Delete</a></td>
</tr>
</table>

<div id="formDiv">

<h4>添加新员工</h4>

<table>
<tr>
<td class="word">name: </td>
<td class="inp">
<input type="text" name="empName" id="empName" />
</td>
</tr>
<tr>
<td class="word">email: </td>
<td class="inp">
<input type="text" name="email" id="email" />
</td>
</tr>
<tr>
<td class="word">salary: </td>
<td class="inp">
<input type="text" name="salary" id="salary" />
</td>
</tr>
<tr>
<td colspan="2" align="center">
<!-- 不会有提交表单的功能,因为没有form表单,所以不需要取消默认行为 -->
<button id="addEmpButton">
Submit
</button>
</td>
</tr>
</table>

</div>

</body>
</html>

浏览器生成了tbody包裹了tr,所以需要往tbody中添加image-20211019212957501

image-20211019214711538

image-20211019214829676

106 a的索引问题

在上面练习中事件回调函数中,不使用this,而是使用allA[i],会报错,因为allA[i]undefined,这是i的问题。

1
2
3
4
5
6
7
8
9
for (var i = 0; i < allA.length; i++) {
allA[i].onclick = function () {
/*
for循环会在页面加载完成后立即执行,而响应函数在超链接被点击时执行,所以当响应函数执行时,for循环早就执行完成了,当for循环执行时,i = 3,以3为索引的值为undefined
*/
alert(allA[i]);
return false;
}
}

107 操作内联样式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>操作内联样式</title>
<style>
#box1 {
width: 100px;
height: 100px;
background-color: #8080ff;
}
</style>
<script>
window.onload = function () {
// 为单击按钮绑定响应函数
var btn01 = document.getElementsByTagName("button")[0];
var btn02 = document.getElementsByTagName("button")[1];
var box1 = document.getElementById("box1");
btn01.onclick = function () {
// 修改box1的高度
/*
通过JS修改元素的样式
语法:元素.style.样式名 = 样式值;
注意:如果CSS的样式名中含有-,这种名称在JS中是不合法的,比如:background-color
需要将这种样式修改为驼峰命名法
去掉-,然后将-后面的字母大写
backgroundColor
borderTopWidth

我们通过style属性设置的样式都是内联样式,而内联样式有较高的优先级,所以通过JS修改的样式往往会立即显示

但是如果在样式中使用了!important,则此时会有较高的优先级,即使通过JS也不能覆盖该样式,此时将会导致JS修改样式失效
所以尽量不要为样式添加!important
*/
box1.style.width = "300px";
box1.style.height = "300px";
box1.style.backgroundColor = "cyan";
}

// 点击按钮2之后,读取元素的样式
btn02.onclick = function () {
// 读取box1的样式
/*
语法:元素.style.样式名
通过style属性设置和读取的都是内联样式
无法读取样式表中的样式
*/

console.log(box1.style);
console.log(typeof box1.style); //object
alert(box1.style.backgroundColor);
alert(typeof box1.style.backgroundColor); // string
}
}
</script>
</head>

<body>
<button>效果切换</button>
<button>读取效果</button>
<div id="box1"></div>
</body>
</html>

108 获取元素的样式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>获取元素内联样式</title>
</head>
<style>
#box1 {
width: 100px;
height: 100px;
background-color: #8080ff;
}
</style>
<script>
window.onload = function () {
/*
background-color默认值为transparent
*/
// 点击按钮读取box1的样式
var box1 = document.getElementById("box1");
var btn01 = document.getElementById("btn01");
btn01.onclick = function () {
// 读取box1的宽度
// alert(box1.style.width);

/*
读取元素的当前显示样式
语法:元素.currentStyle.样式名
它可以用来读取当前正在显示的样式
如果当前元素没有设置该样式,则获取它的默认值
注意:currentStyle只有IE浏览器支持,其他浏览器不支持!
*/
// alert(box1.currentStyle.width);
// alert(box1.currentStyle.backgroundColor);

/*
在其他浏览器中可以使用
getComputedStyle()这个方法来获取元素当前显示的样式
这个方法是window的方法,可以直接使用

需要两个参数
第一个:要获取样式的元素
第二个参数:可以传递一个伪元素,一般传递null

该方法会返回一个对象,对象中封装了当前元素对应的样式
可以通过对象.样式名来读取样式
如果获取的样式没有设置,则会获取到真实的值,而不是默认值
比如:没有设置width,他不会获取auto,而是一个长度
但是不支持IE8及其以下浏览器
注意:通过currentStyle和getComputedStyle()读取到的样式都是只读的,不能修改,如果要修改只能通过style属性来修改!!!
*/

var obj = getComputedStyle(box1, null);

console.log(obj);
console.log(typeof obj); // object
console.log(obj.height);
console.log(obj.backgroundColor); // rgb(128, 128, 255)
}

/*
定义一个函数来指定元素的当前样式,兼容不同浏览器
参数:
obj:要获取样式的元素
name:要获取的样式名
*/
function getStyle(obj, name) {
// 正常浏览器的方式,具有getComputedStyle()方法
if (window.getComputedStyle) {
/*
这里window.属性 用的很巧妙,因为属性不存在返回undefined
而不加window代表变量,层层寻找没有后会报错
*/
return getComputedStyle(obj, null)[name];
} else {
return obj.currentStyle[name];
}

/*
方案二:
if(obj.currentStyle)
{
return obj.currentStyle[name];
}
else{
return getComputedStyle(obj, null)[name];
}

方案一改进:
return window.getComputedStyle?getComputedStyle(obj, null)[name]:obj.currentStyle[name]
*/
}

}
</script>

<body>
<button id="btn01">点击</button>
<div id="box1"></div>
</body>

</html>

109 getStyle()方法

见108

110 其他样式相关属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>其他样式相关属性</title>
<style>
#box1 {
width: 100px;
height: 100px;
background-color: #8080ff;
/* 撑开元素 */
padding: 10px;
border: 10px solid cyan;
}

#box2 {
margin: 100px;
background-color: yellowgreen;
}

#box4 {
height: 200px;
width: 200px;
background-color: lightpink;
overflow: auto;
}

#box5 {
height: 400px;
width: 400px;
background-color: black;
}
</style>
<script>
window.onload = function () {
var btn01 = document.getElementById("btn01");
var box1 = document.getElementById("box1");
var box4 = document.getElementById("box4");
btn01.onclick = function () {
/*
clientWidth
clientHeight
- 这两个属性可以获取元素的可见宽度和高度
- 这些属性都是不带px的,返回的都是一个数字,可以直接进行计算
- 会获取元素宽度和高度,包括内容区和内边距
- 注意:这些属性都是只读的,不能修改

offsetHeight
offsetWidth
- 获取元素的整个高度和宽度,包括内容区、内边距和边框

offsetParent
- 可以用来获取当前元素的定位父元素
- 获取到离当前元素最近的开启了定位的祖先元素(定位默认为static,不算做开启定位,absolute/relative才算),如果所有的祖先元素都没有开启定位,则返回body

offsetLeft
- 当前元素相对于其定位元素的水平偏移量
offsetTop
- 当前元素相对于其定位元素的垂直偏移量

scrollHeight
scrollWidth
- 可以获取元素整个滚动条区域的高度或长度

scrollLeft
- 获取水平滚动条滚动的距离
scrollTop
- 获取垂直滚动条滚动的距离

*/
console.log(box1.clientWidth); //120
console.log(box1.clientHeight);

console.log(box1.offsetWidth); // 140
console.log(box1.offsetHeight);

var op = box1.offsetParent;
console.log(op);

console.log(box1.offsetLeft); // 100
console.log(box1.offsetTop); //0

console.log(box4.clientHeight); // 200
console.log(box4.scrollHeight);// 400
console.log(box4.scrollWidth);// 400
console.log(box4.clientHeight);// 183,因为滚动条的为17px

/*
当满足了scrollHeight - scrollTop == clientHeight
说明了垂直滚动条滚动到底了

当满足了scrollWidth - scrollLeft == clientWidth
说明了水平滚动条滚动到底了
*/
console.log(box4.scrollHeight - box4.scrollTop);
}
}

</script>
</head>


<body>
<button id="btn01">点击</button>
<br /><br />
<div id="box4">
<div id="box5"></div>
</div>

<div id="box3" style="position:relative;">
<div id="box2">
<div id="box1"></div>
</div>
</div>
</body>

</html>

110(2)练习

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>练习</title>
<style>
#content {
width: 200px;
height: 200px;
overflow: auto;
background-color: #8080ff;
color: cyan;
}
</style>
<script>
window.onload = function () {

var content = document.getElementById("content");
var checkBox = document.getElementById("check");
var submitButton = document.getElementById("submit");
content.onscroll = function () {
console.log(content.scrollHeight - content.scrollTop);
if (Math.round(content.scrollHeight - content.scrollTop) == content.clientHeight) {
checkBox.disabled = false;
subm.disabled = false;
}
}
}
</script>
</head>

<body>
<h3>注册须知</h3>
<p id="content">
ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼ycy羽川翼
</p>
<input type="checkbox" disabled="disabled" id="check">
<input type="submit" value="提交" disabled="disabled" id="subm">
</body>
</html>

111 事件对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>事件对象</title>
<style type="text/css">
#areaDiv {
border: 1px solid black;
width: 300px;
height: 50px;
margin-bottom: 10px;
}

#showMsg {
border: 1px solid black;
width: 300px;
height: 20px;
}
</style>
<script type="text/javascript">

window.onload = function () {
/*
* 当鼠标在areaDiv中移动时,在showMsg中来显示鼠标的坐标
*/
//获取两个div
var areaDiv = document.getElementById("areaDiv");
var showMsg = document.getElementById("showMsg");

/*
* onmousemove
* - 该事件将会在鼠标在元素中移动时被触发
*
* 事件对象
* - 当事件的响应函数被触发时,浏览器每次都会将一个事件对象作为实参传递进响应函数,
* 在事件对象中封装了当前事件相关的一切信息,比如:鼠标的坐标 键盘哪个按键被按下 鼠标滚轮滚动的方向。。。
*/
areaDiv.onmousemove = function (event) {

/*
* 在IE8中,响应函数被触发时,浏览器不会传递事件对象,
* 在IE8及以下的浏览器中,是将事件对象作为window对象的属性保存的
*/
/*if(!event){
event = window.event;
}*/

//解决事件对象的兼容性问题
event = event || window.event;

/*
* clientX可以获取鼠标指针的水平坐标
* cilentY可以获取鼠标指针的垂直坐标
*/
var x = event.clientX;
var y = event.clientY;

//alert("x = "+x + " , y = "+y);

//在showMsg中显示鼠标的坐标
showMsg.innerHTML = "x = " + x + " , y = " + y;

};

};

</script>
</head>

<body>
<div id="areaDiv"></div>
<div id="showMsg"></div>
</body>
</html>

112 div跟随鼠标移动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>div跟随鼠标移动</title>
<style>
* {
margin: 0;
padding: 0;
}

#move {
background-color: #8080ff;
width: 100px;
height: 100px;
}
</style>
<script>
window.onload = function () {
var move = document.getElementById("move");
document.onmousemove = function (event) {
event = event || window.event;

/*
clientX、clientY
用于获取鼠标在当前的可见窗口的坐标
*/
var x = event.clientX;
var y = event.clientY;

/*
pageX、pageY
用于获取鼠标相对于当前页面的坐标
但是该属性在IE8中不支持,如果需要兼容IE8,就需要其他方法

var x = event.pageX;
var y = event.pageY;
*/
var st1 = document.documentElement.scrollTop;
var st2 = document.documentElement.scrollLeft;

move.style.marginLeft = x + st2 + "px";
move.style.marginTop = y + st1 + "px";

}
}
</script>
</head>

<body style="height:1000px;">
<div id="move"></div>

</body>
</html>

113 事件冒泡

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
#box1{
width: 200px;
height: 200px;
background-color: yellowgreen;
}

#s1{
background-color: yellow;
}

</style>
<script type="text/javascript">

window.onload = function(){

/*
* 事件的冒泡(Bubble)
* - 所谓的冒泡指的就是事件的向上传导,当后代元素上的事件被触发时,其祖先元素的相同事件也会被触发
* - 在开发中大部分情况冒泡都是有用的,如果不希望发生事件冒泡可以通过事件对象来取消冒泡
*
*/

//为s1绑定一个单击响应函数
var s1 = document.getElementById("s1");
s1.onclick = function(event){
event = event || window.event;
alert("我是span的单击响应函数");

//取消冒泡
//可以将事件对象的cancelBubble设置为true,即可取消冒泡
event.cancelBubble = true;
};

//为box1绑定一个单击响应函数
var box1 = document.getElementById("box1");
box1.onclick = function(event){
event = event || window.event;
alert("我是div的单击响应函数");

event.cancelBubble = true;
};

//为body绑定一个单击响应函数
document.body.onclick = function(){
alert("我是body的单击响应函数");
};
};
</script>
</head>
<body>
<div id="box1">
我是box1
<span id="s1">我是span</span>
</div>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
#box1 {
width: 100px;
height: 100px;
background-color: red;
/*
* 开启box1的绝对定位
*/
position: absolute;
}
</style>

<script type="text/javascript">
window.onload = function () {

/*
* 使div可以跟随鼠标移动
*/

//获取box1
var box1 = document.getElementById("box1");
//绑定鼠标移动事件
document.onmousemove = function (event) {

//解决兼容问题
event = event || window.event;

//获取滚动条滚动的距离
var st = document.documentElement.scrollTop;
var sl = document.documentElement.scrollLeft;

//获取到鼠标的坐标
/*
* clientX和clientY
* 用于获取鼠标在当前的可见窗口的坐标
* div的偏移量,是相对于整个页面的
*
* pageX和pageY可以获取鼠标相对于当前页面的坐标
* 但是这个两个属性在IE8中不支持,所以如果需要兼容IE8,则不要使用
*/
var left = event.clientX;
var top = event.clientY;

//设置div的偏移量
box1.style.left = left + sl + "px";
box1.style.top = top + st + "px";

};

var box2 = document.getElementById("box2");
box2.onmousemove = function (event) {
event = event || window.event;

event.cancelBubble = true;
};
};


</script>
</head>
<body style="height: 1000px;width: 2000px;">
<div id="box2" style="width: 500px; height: 500px; background-color: #bfa;"></div>
<div id="box1"></div>
</body>
</html>

114 事件的委派

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script type="text/javascript">

window.onload = function(){

var u1 = document.getElementById("u1");

//点击按钮以后添加超链接
var btn01 = document.getElementById("btn01");
btn01.onclick = function(){
//创建一个li
var li = document.createElement("li");
li.innerHTML = "<a href='javascript:;' class='link'>新建的超链接</a>";

//将li添加到ul中
u1.appendChild(li);
};


/*
* 为每一个超链接都绑定一个单击响应函数
* 这里我们为每一个超链接都绑定了一个单击响应函数,这种操作比较麻烦,
* 而且这些操作只能为已有的超链接设置事件,而新添加的超链接必须重新绑定
*/
//获取所有的a
var allA = document.getElementsByTagName("a");
//遍历
/*for(var i=0 ; i<allA.length ; i++){
allA[i].onclick = function(){
alert("我是a的单击响应函数!!!");
};
}*/

/*
* 我们希望,只绑定一次事件,即可应用到多个的元素上,即使元素是后添加的
* 我们可以尝试将其绑定给元素的共同的祖先元素
*
* 事件的委派
* - 指将事件统一绑定给元素的共同的祖先元素,这样当后代元素上的事件触发时,会一直冒泡到祖先元素
* 从而通过祖先元素的响应函数来处理事件。
* - 事件委派是利用了冒泡,通过委派可以减少事件绑定的次数,提高程序的性能
*/

//为ul绑定一个单击响应函数
u1.onclick = function(event){
event = event || window.event;

/*
* target
* - event中的target表示的触发事件的对象
*/
//alert(event.target);


//如果触发事件的对象是我们期望的元素,则执行否则不执行
if(event.target.className == "link"){
alert("我是ul的单击响应函数");
}

};

};

</script>
</head>
<body>
<button id="btn01">添加超链接</button>

<ul id="u1" style="background-color: #bfa;">
<li>
<p>我是p元素</p>
</li>
<li><a href="javascript:;" class="link">超链接一</a></li>
<li><a href="javascript:;" class="link">超链接二</a></li>
<li><a href="javascript:;" class="link">超链接三</a></li>
</ul>

</body>
</html>

115 事件的绑定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<script type="text/javascript">

window.onload = function(){

/*
* 点击按钮以后弹出一个内容
*/
//获取按钮对象
var btn01 = document.getElementById("btn01");

/*
* 使用 对象.事件 = 函数 的形式绑定响应函数,
* 它只能同时为一个元素的一个事件绑定一个响应函数,
* 不能绑定多个,如果绑定了多个,则后边会覆盖掉前边的
*/

//为btn01绑定一个单击响应函数
/*btn01.onclick = function(){
alert(1);
};*/

//为btn01绑定第二个响应函数
/*btn01.onclick = function(){
alert(2);
};*/

/*
* addEventListener()
* - 通过这个方法也可以为元素绑定响应函数
* - 参数:
* 1.事件的字符串,不要on
* 2.回调函数,当事件触发时该函数会被调用
* 3.是否在捕获阶段触发事件,需要一个布尔值,一般都传false
*
* 使用addEventListener()可以同时为一个元素的相同事件同时绑定多个响应函数,
* 这样当事件被触发时,响应函数将会按照函数的绑定顺序执行
*
* 这个方法不支持IE8及以下的浏览器
*/
/*btn01.addEventListener("click",function(){
alert(1);
},false);

btn01.addEventListener("click",function(){
alert(2);
},false);

btn01.addEventListener("click",function(){
alert(3);
},false);*/

/*
* attachEvent()
* - 在IE8中可以使用attachEvent()来绑定事件
* - 参数:
* 1.事件的字符串,要on
* 2.回调函数
*
* - 这个方法也可以同时为一个事件绑定多个处理函数,
* 不同的是它是后绑定先执行,执行顺序和addEventListener()相反
*/
/*btn01.attachEvent("onclick",function(){
alert(1);
});

btn01.attachEvent("onclick",function(){
alert(2);
});

btn01.attachEvent("onclick",function(){
alert(3);
});*/

/*btn01.addEventListener("click",function(){
alert(this);
},false);*/

/*btn01.attachEvent("onclick",function(){
alert(this);
});*/

bind(btn01 , "click" , function(){
alert(this);
});
};

//定义一个函数,用来为指定元素绑定响应函数
/*
* addEventListener()中的this,是绑定事件的对象
* attachEvent()中的this,是window
* 需要统一两个方法this
*/
/*
* 参数:
* obj 要绑定事件的对象
* eventStr 事件的字符串(不要on)
* callback 回调函数
*/
function bind(obj , eventStr , callback){
if(obj.addEventListener){
//大部分浏览器兼容的方式
obj.addEventListener(eventStr , callback , false);
}else{
/*
* this是谁由调用方式决定
* callback.call(obj)
*/
//IE8及以下
obj.attachEvent("on"+eventStr , function(){
//在匿名函数中调用回调函数
callback.call(obj);
});
}
}
</script>
</head>
<body>
<button id="btn01">点我一下</button>
</body>
</html>

117 事件的传播

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">

#box1{
width: 300px;
height: 300px;
background-color: yellowgreen;
}

#box2{
width: 200px;
height: 200px;
background-color: yellow;
}

#box3{
width: 150px;
height: 150px;
background-color: skyblue;
}

</style>

<script type="text/javascript">

window.onload = function(){

/*
* 分别为三个div绑定单击响应函数
*/
var box1 = document.getElementById("box1");
var box2 = document.getElementById("box2");
var box3 = document.getElementById("box3");

/*
* 事件的传播
* - 关于事件的传播网景公司和微软公司有不同的理解
* - 微软公司认为事件应该是由内向外传播,也就是当事件触发时,应该先触发当前元素上的事件,
* 然后再向当前元素的祖先元素上传播,也就说事件应该在冒泡阶段执行。
* - 网景公司认为事件应该是由外向内传播的,也就是当前事件触发时,应该先触发当前元素的最外层的祖先元素的事件,
* 然后在向内传播给后代元素
* - W3C综合了两个公司的方案,将事件传播分成了三个阶段
* 1.捕获阶段
* - 在捕获阶段时从最外层的祖先元素,向目标元素进行事件的捕获,但是默认此时不会触发事件
* 2.目标阶段
* - 事件捕获到目标元素,捕获结束开始在目标元素上触发事件
* 3.冒泡阶段
* - 事件从目标元素向他的祖先元素传递,依次触发祖先元素上的事件
*
* - 如果希望在捕获阶段就触发事件,可以将addEventListener()的第三个参数设置为true
* 一般情况下我们不会希望在捕获阶段触发事件,所以这个参数一般都是false
*
* - IE8及以下的浏览器中没有捕获阶段
*/

bind(box1,"click",function(){
alert("我是box1的响应函数")
});

bind(box2,"click",function(){
alert("我是box2的响应函数")
});

bind(box3,"click",function(){
alert("我是box3的响应函数")
});

};


function bind(obj , eventStr , callback){
if(obj.addEventListener){
//大部分浏览器兼容的方式
obj.addEventListener(eventStr , callback , true);
}else{
/*
* this是谁由调用方式决定
* callback.call(obj)
*/
//IE8及以下
obj.attachEvent("on"+eventStr , function(){
//在匿名函数中调用回调函数
callback.call(obj);
});
}
}

</script>
</head>

<body>

<div id="box1">
<div id="box2">
<div id="box3"></div>
</div>
</div>

</body>
</html>

118 拖拽

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">

#box1{
width: 100px;
height: 100px;
background-color: red;
position: absolute;
}

#box2{
width: 100px;
height: 100px;
background-color: yellow;
position: absolute;

left: 200px;
top: 200px;
}

</style>

<script type="text/javascript">

window.onload = function(){
/*
* 拖拽box1元素
* - 拖拽的流程
* 1.当鼠标在被拖拽元素上按下时,开始拖拽 onmousedown
* 2.当鼠标移动时被拖拽元素跟随鼠标移动 onmousemove
* 3.当鼠标松开时,被拖拽元素固定在当前位置 onmouseup
*/

//获取box1
var box1 = document.getElementById("box1");
//为box1绑定一个鼠标按下事件
//当鼠标在被拖拽元素上按下时,开始拖拽 onmousedown
box1.onmousedown = function(event){
event = event || window.event;
//div的偏移量 鼠标.clentX - 元素.offsetLeft
//div的偏移量 鼠标.clentY - 元素.offsetTop
var ol = event.clientX - box1.offsetLeft;
var ot = event.clientY - box1.offsetTop;

//为document绑定一个onmousemove事件
document.onmousemove = function(event){
event = event || window.event;
//当鼠标移动时被拖拽元素跟随鼠标移动 onmousemove
//获取鼠标的坐标
var left = event.clientX - ol;
var top = event.clientY - ot;

//修改box1的位置
box1.style.left = left+"px";
box1.style.top = top+"px";

};

//为document绑定一个鼠标松开事件
document.onmouseup = function(){
//当鼠标松开时,被拖拽元素固定在当前位置 onmouseup
//取消document的onmousemove事件
document.onmousemove = null;
//取消document的onmouseup事件
document.onmouseup = null;
};
};
};
</script>
</head>
<body>
<div id="box1"></div>
<div id="box2"></div>
</body>
</html>

119 拖拽

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
#box1 {
width: 100px;
height: 100px;
background-color: red;
position: absolute;
}

#box2 {
width: 100px;
height: 100px;
background-color: yellow;
position: absolute;

left: 200px;
top: 200px;
}
</style>

<script type="text/javascript">

window.onload = function () {
var box1 = document.getElementById("box1");
var box2 = document.getElementById("box2");
box1.onmousedown = function (event) {

//设置box1捕获所有鼠标按下的事件
/*
* setCapture()
* - 只有IE支持,但是在火狐中调用时不会报错,
* 而如果使用chrome调用,会报错
*/
/*if(box1.setCapture){
box1.setCapture();
}*/
box1.setCapture && box1.setCapture();

event = event || window.event;
var ol = event.clientX - box1.offsetLeft;
var ot = event.clientY - box1.offsetTop;

document.onmousemove = function (event) {
event = event || window.event;
var left = event.clientX - ol;
var top = event.clientY - ot;

box1.style.left = left + "px";
box1.style.top = top + "px";

};
document.onmouseup = function () {
document.onmousemove = null;
document.onmouseup = null;
box1.releaseCapture && box1.releaseCapture();
};

/*
* 当我们拖拽一个网页中的内容时,浏览器会默认去搜索引擎中搜索内容,
* 此时会导致拖拽功能的异常,这个是浏览器提供的默认行为,
* 如果不希望发生这个行为,则可以通过return false来取消默认行为
*
* 但是这招对IE8不起作用
*/
return false;
};
};
</script>
</head>

<body>
我是一段文字
<div id="box1"></div>
<div id="box2"></div>
</body>

</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8">
<title></title>
<script type="text/javascript">

window.onload = function () {
//分别为两个按钮绑定单击响应函数
var btn01 = document.getElementById("btn01");
var btn02 = document.getElementById("btn02");

btn01.onclick = function () {
alert(1);
};

btn02.onclick = function () {
alert(2);
};

//设置btn01对鼠标按下相关的事件进行捕获
//当调用一个元素的setCapture()方法以后,这个元素将会把下一次所有的鼠标按下相关的事件捕获到自身上
btn01.setCapture(); // 只在IE中生效
};

</script>
</head>

<body>
<button id="btn01">按钮01</button>
<button id="btn02">按钮02</button>
</body>

</html>

121 滚轮事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>滚轮的事件</title>
<style>
#box1 {
width: 100px;
height: 100px;
background-color: #8080ff;
}
</style>
<script>
window.onload = function () {
/*
当滚轮向下滚动时,box1变长
当滚轮向上滚动时,box1变短
*/
var box1 = document.getElementById("box1");

// 为box1绑定一个鼠标滚动事件
/*
onmousewheel鼠标滚轮滚动的事件,会在滚轮滚动时触发,但是火狐浏览器不支持该属性

在火狐中需要使用DOMMouseScroll来绑定滚动事件
注意该事件需要通过addEventListener()函数来绑定
*/
box1.onmousewheel = function (event) {
event = event || window.event;
// 判断滚轮滚动方向
/*
event.wheelDelta 可以获取鼠标滚轮滚动的方向
向上滚动120,向下滚动-120
这个值不看大小,只看正负

event.wheelDelta属性火狐不支持,火狐中使用event.detail来获取滚动方向
向上-3,向下3
*/

// 判断鼠标滚轮滚动的方向
if (event.wheelDelta > 0 || event.detail < 0) {
// 向上滚动,box1变短
box1.style.height += box1.clientHeight - 10;
} else {
// 向下滚动,box1边长
box1.style.height += box1.clientHeight + 10;
}
/*
使用addEventListener()方法绑定响应函数,取消默认行为不能使用return false
需要使用event来取消默认行为
但是IE8不支持event.preventDefault();如果直接调用会报错
*/
event.preventDefault || event.preventDefault();

/*
当滚轮滚动时,如果浏览器有滚动条,滚动条会随之滚动,这是浏览器的默认行为,如果不希望发生,则可以取消默认行为
*/
return false;
};

// 为火狐绑定滚动事件
bind(box1, "DOMMouseScroll", box1.onmousewheel);

function bind(obj, eventStr, callback) {
if (obj.addEventListener) {
// 大部分浏览器兼容
obj.addEventListener(eventStr, callback, false);
} else {
obj.attachEvent("on" + eventStr, function () {
// 在匿名函数中调用回调函数
callback.call(obj);
});
}
}
}
</script>
</head>
<body style="height:2000px;">
<div id="box1"></div>
</body>
</html>

122 键盘事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>键盘事件</title>
<script>
window.onload = function () {
/*
键盘事件:
onkeydown
- 按键被按下
- 对于onkeydown来说,如果一直按着某个键不松开,则事件会一直连续触发
- onkeydown连续触发时,第一次和第二次之间间隔会非常大,其他的会非常快,这种设计是为了防止误操作
onkeyup
- 按键被松开

键盘事件一般绑定给一些可以获取焦点的对象或者document
*/
// document.onkeydown = function (event) {
// event = event || window.event;
// /*
// 可以通过event.key获取按键的字符串
// keyCode已经弃用

// 事件对象中的其他几个属性:
// alterKey
// ctrlKey
// shiftKey
// - 这三个用来判断alt、ctrl、shift是否被按下,按下返回true,否则返回false
// */
// console.log(event.key);
// if (event.key == " ") {
// console.log("按下空格");
// }

// /*
// 判断一个y是否按下
// 判断y和ctrl是否同时按下
// */
// if (event.key === "y" && event.ctrlKey) {
// console.log("同时按下ctrl和y");
// }
// }
// document.onkeyup = function () {
// console.log("按键被松开!");
// }

// 获取input

var input = document.getElementsByTagName("input")[0];
var check = document.getElementById("check");
input.onkeyup = function () {
console.log(this);
/*
在文本框中输入内容,属于onkeydown的默认行为,如果在onkeydown中取消了默认行为,则输入的内容,不会出现在文本框中

return false;
*/
// 功能:文本框中只能输入数字
check.innerHTML = this.value.match(/\D/) ? "错误" : "正确";
}

}

</script>
</head>

<body>
<input type="text" />
<span id="check"></span>
</body>

</html>

注意到底是绑定keydown还是keyup

123 键盘移动div

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>键盘移动div</title>
<style>
#box {
height: 100px;
width: 100px;
background-color: #8080ff;
position: relative;
}
</style>
<script>
window.onload = function () {
var box = document.getElementById("box");
document.onkeydown = function (event) {
event = event || window.event;
// 获取当前位置
var x = box.offsetLeft;

var y = box.offsetTop;
console.log(box);

switch (event.key) {
case "ArrowLeft":
box.style.left = x - 20 + "px";
break;
case "ArrowRight":
box.style.left = x + 10 + "px";
break;
case "ArrowDown":
box.style.top = y + 10 + "px";
break;
case "ArrowUp":
box.style.top = y - 20 + "px";
break;
}
}
}
</script>
</head>

<body>
<div id="box"></div>
</body>

</html>

124 Navigator

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>navigator</title>
<script>
/*
BOM
- 浏览器对象模型
- BOM可以使我们通过JS来操作浏览器
- 在BOM中为我们提供了一组对象,用来完成对浏览器的操作
Window
- 代表的是整个浏览器
Navigator
- 代表的是当前浏览器的信息,通过该对象可以识别不同的浏览器
Location
- 代表当前浏览器的地址栏信息,通过Location可以获取地址栏信息,或者操作浏览器跳转页面
History
- 代表的浏览器的历史记录,可以通过该对象来操作浏览器向前或向后翻页
而且该操作只在当次访问有效
Screen
- 代表的是用户屏幕的信息,通过该对象可以获取到用户显示器的相关信息

这些BOM对象在浏览器中都是作为window对象的属性保存的。
可以通过window对象来使用,也可以直接使用
*/
console.log(navigator, window.navigator);
console.log(location, window.location);
console.log(history, window.history);
console.log(screen, window.screen);

/*
Navigator
- 代表的当前浏览器的信息,通过该对象可以识别不同的浏览器
- 由于历史原因,Navigator中大部分属性都已经不能帮助我们识别浏览器了
- 一般我们只会使用userAgent来判断浏览器的信息
userAgent是一个字符串,这个字符串中包含有用来描述浏览器信息的内容,不同的浏览器会有不同的userAgent
*/
console.log(navigator.appName);// EDGE-Netscape chrome-Netscape
console.log(navigator.userAgent);
/*
EDGE
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36 Edg/94.0.992.50

Chrome
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36

IE11
Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729; InfoPath.3; rv:11.0) like Gecko
*/
// 使用正则匹配即可

/*
如果通过UserAgent不能判断,还可以通过一些浏览器特有的对象,来判断浏览器的信息
比如:
ActiveXObject IE特有(IE8-11都有,8-10 window.ActiveObject返回true,但是IE11返回false,有一说一真恶心)
所以需要使用("ActiveXObject" in window) 来判断

*/

</script>
</head>
<body>
</body>
</html>

125 history

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>History</title>
<script>
window.onload = function () {

/*
History
- 对象可以用来操作了浏览器向前或者向后翻页
history.length属性可以获取到当前访问的链接数量
*/

console.log(history);
console.log(history.length);

var btn1 = document.getElementsByTagName("button")[0];
var btn2 = document.getElementsByTagName("button")[1];
btn1.onclick = function () {
/*
back()
- 用来回退到上一个页面,作用与浏览器的回退按钮一致。
*/
history.back();
}
btn2.onclick = function () {
/*
forward()
- 用来跳转到下一个页面,作用与前进按钮一致。
*/
history.forward();
}
/*
go
- 可以用来跳转到指定的页面
- 它需要一个整数作为参数
1.表示向前跳转一个页面
2.表示向前跳转两个页面
-1.表示向后跳转一个页面
-2.表示向后跳转两个页面
*/
}

</script>
</head>

<body>
<h1>测试History</h1>
<button>跳转回上一个页面</button>
<button>跳转到下一个页面</button>
</body>
</html>

126 location

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Location</title>
<script>
window.onload = function () {

/*
Location对象
- 该对象中封装了浏览器中地址栏的信息
*/

var btn1 = document.getElementsByTagName("button")[0];
btn1.onclick = function () {
// 如果直接打印location,则可以获取到地址栏的信息(当前页面的完整路径)
console.log(location);

/*
如果直接将location属性修改为一个完整的路径,或相对路径,则页面回自动跳转到该路径,并会生成相应的历史记录
*/
// location = `https://miketaylorjuly123.cn`;

/*
assign
- 用来跳转到其他的页面,作用和直接修改location一样
*/
location.assign("https://miketaylorjuly123.cn");

/*
reload()
- 用于重新加载当前文档,作用与刷新按钮一致,但是火狐会有缓存,可以通过指定参数true进行强制清空缓存刷新
- 如果在方法中传递一个参数true,作为参数,则会强制清空缓存刷新页面
*/
// location.reload(true);

/*
replace
- 可以使用一个新的页面来替换当前页面,调用完毕后也会跳转页面
- 但是注意,他不会生成历史记录,无法进行回退
*/
// location.replace("https://miketaylorjuly123.cn");
}
}

</script>
</head>

<body>
<h1>Location</h1>
<button>测试</button>
</body>
</html>

127 定时器简介

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>定时器简介</title>
<style>
</style>
<script>
/*
setInterval()
- 开启定时器,可以将一个函数每隔一段时间执行一次
- 可以将一个函数,每隔一段时间执行一次
- 参数:
- 1.回调函数,该函数会每隔一段时间被调用一次
2.每次调用间隔的时间,单位为毫秒
- 返回值
返回一个Number类型的数据
返回值用来作为定时器的唯一标识
clearInterval()
- 用于关闭定时器
- 方法中需要一个定时器的标识作为参数,这样将关闭标识对应的定时器
*/
window.onload = function () {

// 获取count
var count = document.getElementById("count");
// 使count中的内容自动切换
/*
如果希望一段程序每间隔一段时间调用,可以使用定时器调用
*/
var num = 1;
var timer = setInterval(function () {
count.innerHTML = num++;
if (num == 99) {
count.innerHTML = "羽川翼!";
clearInterval(timer);
}
}, 20);

};
</script>
</head>
<body>
<h2 id="count">1</h2>
</body>
</html>

128 切换图片练习

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>切换图片练习</title>
<script>
var imgArray = ["./img/1.png", "./img/2.png", "./img/3.png", "./img/4.png"];
var index = 0;
var timer;
window.onload = function () {
var img = document.getElementsByTagName("img")[0];
var btn01 = document.getElementsByTagName("button")[0];
var btn02 = document.getElementsByTagName("button")[1];
btn01.onclick = function () {
/*
每点击一次就会开启一个定时器,而且定时器标识被覆盖,导致关不掉除最后一个定时器外的定时器
*/
// 开启定时器之前,需要停止当前元素上的其他定时器
clearInterval(timer);

timer = setInterval(() => {
index = (index + 1) % imgArray.length;
img.src = imgArray[index];
}, 3000);
btn02.onclick = function () {
// 点击按钮后,停止图片的自动切换,关闭定时器
/*
clearInterval()可以接收任意的参数
如果参数是一个有效的定时器标识,则停止对应的定时器
如果参数不是一个有效的标识,则什么也不会发生,不会报错
*/
clearInterval(timer);
console.log(timer);
}
}
}
</script>
<style>
* {
margin: 0;
padding: 0;
}

div {
width: 600px;
margin: 0 auto;
}

img {
width: 100%;
}

button:last-child {
float: right;
}
</style>
</head>

<body>
<div>
<img src="./img/1.png" alt="">
<button id="btn01">开始</button>
<button id="btn02">暂停</button>
</div>
</body>

</html>

129 修改div练习

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>键盘移动div</title>
<style>
#box {
height: 100px;
width: 100px;
background-color: #8080ff;
position: relative;
}
</style>
<script>
window.onload = function () {
/*
问题:长按后,连续移动前有明显的卡顿情况
*/
var box = document.getElementById("box");

// 创建一个变量表示方向
var direction = null;
// 通过修改dir来影响移动的方向
setInterval(() => {
switch (direction) {
case "ArrowLeft":
box.style.left = box.offsetLeft - 20 + "px";
break;
case "ArrowRight":
box.style.left = box.offsetLeft + 10 + "px";
break;
case "ArrowDown":
box.style.top = box.offsetTop + 10 + "px";
break;
case "ArrowUp":
box.style.top = box.offsetTop - 20 + "px";
break;
}
}, 30);

document.onkeydown = function (event) {
event = event || window.event;
// 获取当前位置
direction = event.key;
}
document.onkeyup = function () {
direction = null;
}
}
</script>
</head>

<body>
<div id="box"></div>
</body>

</html>

130 延时调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>延时调用</title>
<script>
var num = 1;

// 开启定时器
setInterval(function () {
console.log(num++);
}, 3000);

/*
setTimeout
- 延时调用:一个函数不是马上执行,而是隔一段时间执行,而且只会执行一次
- 定时调用执行多次,延时调用执行一次
延时调用和定时调用实际上是可以相互转换代替的,开发中可以根据自己的需要选择
*/
var timer = setInterval(function () {
console.log(num++);
}, 3000);

// 使用clearTimeout()来关闭一个延时调用
clearTimeout(timer);

</script>
</head>

<body>

</body>

</html>

131 定时器的应用(一)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
* {
margin: 0;
padding: 0;
}

#box1 {
width: 100px;
height: 100px;
background-color: red;
position: absolute;
left: 0;
}
</style>

<script type="text/javascript">

window.onload = function () {

//获取box1
var box1 = document.getElementById("box1");
//获取btn01
var btn01 = document.getElementById("btn01");

//定义一个变量,用来保存定时器的标识
var timer;

//点击按钮以后,使box1向右移动(left值增大)
btn01.onclick = function () {

//关闭上一个定时器
clearInterval(timer);

//开启一个定时器,用来执行动画效果
timer = setInterval(function () {

//获取box1的原来的left值
var oldValue = parseInt(getStyle(box1, "left"));

//在旧值的基础上增加
var newValue = oldValue + 10;

//判断newValue是否大于800
if (newValue > 800) {
newValue = 800;
}

//将新值设置给box1
box1.style.left = newValue + "px";

//当元素移动到800px时,使其停止执行动画
if (newValue == 800) {
//达到目标,关闭定时器
clearInterval(timer);
}


}, 30);


};

};


/*
* 定义一个函数,用来获取指定元素的当前的样式
* 参数:
* obj 要获取样式的元素
* name 要获取的样式名
*/
function getStyle(obj, name) {

if (window.getComputedStyle) {
//正常浏览器的方式,具有getComputedStyle()方法
return getComputedStyle(obj, null)[name];
} else {
//IE8的方式,没有getComputedStyle()方法
return obj.currentStyle[name];
}
}
</script>
</head>

<body>
<button id="btn01">点击按钮以后box1向右移动</button>
<br /><br />
<div id="box1"></div>
<div style="width: 0; height: 1000px; border-left:1px black solid; position: absolute; left: 800px;top:0;"></div>
</body>

</html>

132 定时器的应用(三)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">

*{
margin: 0;
padding: 0;
}

#box1{
width: 100px;
height: 100px;
background-color: red;
position: absolute;
left: 0;
}

</style>

<script type="text/javascript">

window.onload = function(){

//获取box1
var box1 = document.getElementById("box1");
//获取btn01
var btn01 = document.getElementById("btn01");

//获取btn02
var btn02 = document.getElementById("btn02");


//点击按钮以后,使box1向右移动(left值增大)
btn01.onclick = function(){
move(box1 , 800 , 10);
};


//点击按钮以后,使box1向左移动(left值减小)
btn02.onclick = function(){
move(box1 , 0 , 10);
};

};

//定义一个变量,用来保存定时器的标识
var timer;

//尝试创建一个可以执行简单动画的函数
/*
* 参数:
* obj:要执行动画的对象
* target:执行动画的目标位置
* speed:移动的速度(正数向右移动,负数向左移动)
*/
function move(obj , target ,speed){
//关闭上一个定时器
clearInterval(timer);

//获取元素目前的位置
var current = parseInt(getStyle(obj,"left"));

//判断速度的正负值
//如果从0 向 800移动,则speed为正
//如果从800向0移动,则speed为负
if(current > target){
//此时速度应为负值
speed = -speed;
}

//开启一个定时器,用来执行动画效果
timer = setInterval(function(){

//获取box1的原来的left值
var oldValue = parseInt(getStyle(obj,"left"));

//在旧值的基础上增加
var newValue = oldValue + speed;

//判断newValue是否大于800
//从800 向 0移动
//向左移动时,需要判断newValue是否小于target
//向右移动时,需要判断newValue是否大于target
if((speed < 0 && newValue < target) || (speed > 0 && newValue > target)){
newValue = target;
}

//将新值设置给box1
obj.style.left = newValue + "px";

//当元素移动到0px时,使其停止执行动画
if(newValue == target){
//达到目标,关闭定时器
clearInterval(timer);
}
},30);
}

/*
* 定义一个函数,用来获取指定元素的当前的样式
* 参数:
* obj 要获取样式的元素
* name 要获取的样式名
*/
function getStyle(obj , name){

if(window.getComputedStyle){
//正常浏览器的方式,具有getComputedStyle()方法
return getComputedStyle(obj , null)[name];
}else{
//IE8的方式,没有getComputedStyle()方法
return obj.currentStyle[name];
}

}
</script>
</head>
<body>
<button id="btn01">点击按钮以后box1向右移动</button>
<button id="btn02">点击按钮以后box1向左移动</button>

<br /><br />

<div id="box1"></div>

<div style="width: 0; height: 1000px; border-left:1px black solid; position: absolute; left: 800px;top:0;"></div>

</body>
</html>

133 定时器的应用(三)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">

*{
margin: 0;
padding: 0;
}

#box1{
width: 100px;
height: 100px;
background-color: red;
position: absolute;
left: 0;
}

#box2{
width: 100px;
height: 100px;
background-color: yellow;
position: absolute;
left: 0;
top: 200px;
}

</style>
<script type="text/javascript" src="js/tools.js"></script>
<script type="text/javascript">

window.onload = function(){

//获取box1
var box1 = document.getElementById("box1");
//获取btn01
var btn01 = document.getElementById("btn01");

//获取btn02
var btn02 = document.getElementById("btn02");


//点击按钮以后,使box1向右移动(left值增大)
btn01.onclick = function(){
move(box1 ,"left", 800 , 20);
};


//点击按钮以后,使box1向左移动(left值减小)
btn02.onclick = function(){
move(box1 ,"left", 0 , 10);
};


//获取btn03
var btn03 = document.getElementById("btn03");
btn03.onclick = function(){
move(box2 , "left",800 , 10);
};

//测试按钮
var btn04 = document.getElementById("btn04");
btn04.onclick = function(){
//move(box2 ,"width", 800 , 10);
//move(box2 ,"top", 800 , 10);
//move(box2 ,"height", 800 , 10);
move(box2 , "width" , 800 , 10 , function(){
move(box2 , "height" , 400 , 10 , function(){
move(box2 , "top" , 0 , 10 , function(){
move(box2 , "width" , 100 , 10 , function(){

});
});
});
});
};
};
</script>
</head>
<body>

<button id="btn01">点击按钮以后box1向右移动</button>
<button id="btn02">点击按钮以后box1向左移动</button>
<button id="btn03">点击按钮以后box2向右移动</button>
<button id="btn04">测试按钮</button>

<br /><br />

<div id="box1"></div>
<div id="box2"></div>

<div style="width: 0; height: 1000px; border-left:1px black solid; position: absolute; left: 800px;top:0;"></div>

</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
//尝试创建一个可以执行简单动画的函数
/*
* 参数:
* obj:要执行动画的对象
* attr:要执行动画的样式,比如:left top width height
* target:执行动画的目标位置
* speed:移动的速度(正数向右移动,负数向左移动)
* callback:回调函数,这个函数将会在动画执行完毕以后执行
*/
function move(obj, attr, target, speed, callback) {
//关闭上一个定时器
clearInterval(obj.timer);

//获取元素目前的位置
var current = parseInt(getStyle(obj, attr));

//判断速度的正负值
//如果从0 向 800移动,则speed为正
//如果从800向0移动,则speed为负
if(current > target) {
//此时速度应为负值
speed = -speed;
}

//开启一个定时器,用来执行动画效果
//向执行动画的对象中添加一个timer属性,用来保存它自己的定时器的标识
obj.timer = setInterval(function() {

//获取box1的原来的left值
var oldValue = parseInt(getStyle(obj, attr));

//在旧值的基础上增加
var newValue = oldValue + speed;

//判断newValue是否大于800
//从800 向 0移动
//向左移动时,需要判断newValue是否小于target
//向右移动时,需要判断newValue是否大于target
if((speed < 0 && newValue < target) || (speed > 0 && newValue > target)) {
newValue = target;
}

//将新值设置给box1
obj.style[attr] = newValue + "px";

//当元素移动到0px时,使其停止执行动画
if(newValue == target) {
//达到目标,关闭定时器
clearInterval(obj.timer);
//动画执行完毕,调用回调函数
callback && callback();
}

}, 30);
}

/*
* 定义一个函数,用来获取指定元素的当前的样式
* 参数:
* obj 要获取样式的元素
* name 要获取的样式名
*/
function getStyle(obj, name) {

if(window.getComputedStyle) {
//正常浏览器的方式,具有getComputedStyle()方法
return getComputedStyle(obj, null)[name];
} else {
//IE8的方式,没有getComputedStyle()方法
return obj.currentStyle[name];
}
}

134 轮播图——自动放映(自己实现)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>轮播图</title>
<style>
* {
margin: 0;
padding: 0;
}

#container {
/* 设置宽高 ,需要设置动态*/
width: 361px;
height: 200px;
/* 居中 */
margin: 50px auto;
background-color: #8080ff;
padding: 10px 0;
/* 开启相对定位 */
position: relative;
overflow: hidden;
}

#imgList {
/* 设置ul宽度 ,写死了不好,需要设置动态*/
/* width: 1444px; */
/* 开启相对定位 */
position: absolute;
left: 0px;
}

li {
height: 200px;
float: left;
list-style: none;
/* 设置左右边距 */
margin: 0 20px;
}

li img {
height: 100%;
}
</style>
<script>
window.onload = function () {
var imgList = document.getElementById("imgList");
var container = document.getElementById("container");
var imgs = document.getElementsByTagName("img");
/* 设置动态长度 */
imgList.style.width = 361 * imgs.length + "px";
imgList.style.left = 0 + "px";

/*
每向左移动361px,就会显示下一张图片
*/
var timer;
var index = 0;
var speed = 10;
var positionLeft;
var flag = true;
setInterval(() => {
clearInterval(timer);
if (index != imgs.length - 1 && flag == true) {
console.log("##" + imgList.style.left);
positionLeft = -361 * (++index % imgs.length);
timer = setInterval(() => {
imgList.style.left = (parseInt(getStyle(imgList, "left")) - speed) + "px";
if (positionLeft > parseInt(getStyle(imgList, "left"))) {
imgList.style.left = -361 * (index % imgs.length) + "px";
clearInterval(timer);
}
}, 10);
}
else {
console.log("@@" + imgList.style.left);
flag = false;
positionLeft = -361 * (--index % imgs.length);
timer = setInterval(() => {
imgList.style.left = (parseInt(getStyle(imgList, "left")) + speed) + "px";
if (positionLeft < parseInt(getStyle(imgList, "left"))) {
imgList.style.left = -361 * (index % imgs.length) + "px";
if (index == 0) {
flag = true;
}
clearInterval(timer);
}
}, 10);
}
}, 1000)
}

function getStyle(obj, name) {
// 正常浏览器的方式,具有getComputedStyle()方法
if (window.getComputedStyle) {
/*
这里window.属性 用的很巧妙,因为属性不存在返回undefined
而不加window代表变量,层层寻找没有后会报错
*/
return getComputedStyle(obj, null)[name];
} else {
return obj.currentStyle[name];
}
}
</script>
</head>

<body>
<div id="container">
<ul id="imgList">
<li><img src="./img/1.png" alt=""></li>
<li><img src="./img/2.png" alt=""></li>
<li><img src="./img/3.png" alt=""></li>
<li><img src="./img/4.png" alt=""></li>
</ul>
</div>
</body>

</html>

134 轮播图——点击跳转

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8">
<title></title>

<style type="text/css">
* {
margin: 0;
padding: 0;
}

/*
* 设置outer的样式
*/
#outer {
/*设置宽和高*/
width: 520px;
height: 333px;
/*居中*/
margin: 50px auto;
/*设置背景颜色*/
background-color: greenyellow;
/*设置padding*/
padding: 10px 0;
/*开启相对定位*/
position: relative;
/*裁剪溢出的内容*/
overflow: hidden;
}

/*设置imgList*/
#imgList {
/*去除项目符号*/
list-style: none;
/*设置ul的宽度*/
/*width: 2600px;*/
/*开启绝对定位*/
position: absolute;
/*设置偏移量*/
/*
* 每向左移动520px,就会显示到下一张图片
*/
left: 0px;
}

/*设置图片中的li*/
#imgList li {
/*设置浮动*/
float: left;
/*设置左右外边距*/
margin: 0 10px;
}

/*设置导航按钮*/
#navDiv {
/*开启绝对定位*/
position: absolute;
/*设置位置*/
bottom: 15px;
/*设置left值
outer宽度 520
navDiv宽度 25*5 = 125
520 - 125 = 395/2 = 197.5
* */
/*left: 197px;*/
}

#navDiv a {
/*设置超链接浮动*/
float: left;
/*设置超链接的宽和高*/
width: 15px;
height: 15px;
/*设置背景颜色*/
background-color: red;
/*设置左右外边距*/
margin: 0 5px;
/*设置透明*/
opacity: 0.5;
/*兼容IE8透明*/
filter: alpha(opacity=50);
}

/*设置鼠标移入的效果*/
#navDiv a:hover {
background-color: black;
}
</style>

<!--引用工具-->
<script type="text/javascript" src="js/tools.js"></script>
<script type="text/javascript">
window.onload = function () {
//获取imgList
var imgList = document.getElementById("imgList");
//获取页面中所有的img标签
var imgArr = document.getElementsByTagName("img");
//设置imgList的宽度
imgList.style.width = 520 * imgArr.length + "px";

/*设置导航按钮居中*/
//获取navDiv
var navDiv = document.getElementById("navDiv");
//获取outer
var outer = document.getElementById("outer");
//设置navDiv的left值
navDiv.style.left = (outer.offsetWidth - navDiv.offsetWidth) / 2 + "px";

//默认显示图片的索引
var index = 0;
//获取所有的a
var allA = document.getElementsByTagName("a");
//设置默认选中的效果
allA[index].style.backgroundColor = "black";

/*
点击超链接切换到指定的图片
点击第一个超链接,显示第一个图片
点击第二个超链接,显示第二个图片
* */

//为所有的超链接都绑定单击响应函数
for (var i = 0; i < allA.length; i++) {

//为每一个超链接都添加一个num属性
allA[i].num = i;

//为超链接绑定单击响应函数
allA[i].onclick = function () {

//获取点击超链接的索引,并将其设置为index
index = this.num;

//切换图片
/*
* 第一张 0 0
* 第二张 1 -520
* 第三张 2 -1040
*/
//imgList.style.left = -520*index + "px";
//设置选中的a
setA();

//使用move函数来切换图片
move(imgList, "left", -520 * index, 20, function () {

});
};
}

//创建一个方法用来设置选中的a
function setA() {

//遍历所有a,并将它们的背景颜色设置为红色
for (var i = 0; i < allA.length; i++) {
// allA[i].style.backgroundColor = "red"; // 会导致内联样式hover失效
allA[i].style.backgroundColor = "";
}

//将选中的a设置为黑色
allA[index].style.backgroundColor = "black";
};
};
</script>
</head>

<body>
<!-- 创建一个外部的div,来作为大的容器 -->
<div id="outer">
<!-- 创建一个ul,用于放置图片 -->
<ul id="imgList">
<li><img src="img/1.jpg" /></li>
<li><img src="img/2.jpg" /></li>
<li><img src="img/3.jpg" /></li>
<li><img src="img/4.jpg" /></li>
<li><img src="img/5.jpg" /></li>
</ul>
<!--创建导航按钮-->
<div id="navDiv">
<a href="javascript:;"></a>
<a href="javascript:;"></a>
<a href="javascript:;"></a>
<a href="javascript:;"></a>
<a href="javascript:;"></a>
</div>
</div>
</body>

</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
//尝试创建一个可以执行简单动画的函数
/*
* 参数:
* obj:要执行动画的对象
* attr:要执行动画的样式,比如:left top width height
* target:执行动画的目标位置
* speed:移动的速度(正数向右移动,负数向左移动)
* callback:回调函数,这个函数将会在动画执行完毕以后执行
*/
function move(obj, attr, target, speed, callback) {
//关闭上一个定时器
clearInterval(obj.timer);

//获取元素目前的位置
var current = parseInt(getStyle(obj, attr));

//判断速度的正负值
//如果从0 向 800移动,则speed为正
//如果从800向0移动,则speed为负
if(current > target) {
//此时速度应为负值
speed = -speed;
}

//开启一个定时器,用来执行动画效果
//向执行动画的对象中添加一个timer属性,用来保存它自己的定时器的标识
obj.timer = setInterval(function() {

//获取box1的原来的left值
var oldValue = parseInt(getStyle(obj, attr));

//在旧值的基础上增加
var newValue = oldValue + speed;

//判断newValue是否大于800
//从800 向 0移动
//向左移动时,需要判断newValue是否小于target
//向右移动时,需要判断newValue是否大于target
if((speed < 0 && newValue < target) || (speed > 0 && newValue > target)) {
newValue = target;
}

//将新值设置给box1
obj.style[attr] = newValue + "px";

//当元素移动到0px时,使其停止执行动画
if(newValue == target) {
//达到目标,关闭定时器
clearInterval(obj.timer);
//动画执行完毕,调用回调函数
callback && callback();
}

}, 30);
}

/*
* 定义一个函数,用来获取指定元素的当前的样式
* 参数:
* obj 要获取样式的元素
* name 要获取的样式名
*/
function getStyle(obj, name) {

if(window.getComputedStyle) {
//正常浏览器的方式,具有getComputedStyle()方法
return getComputedStyle(obj, null)[name];
} else {
//IE8的方式,没有getComputedStyle()方法
return obj.currentStyle[name];
}

}

134 轮播图——教程完整

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8">
<title></title>

<style type="text/css">
* {
margin: 0;
padding: 0;
}

/*
* 设置outer的样式
*/
#outer {
/*设置宽和高*/
width: 520px;
height: 333px;
/*居中*/
margin: 50px auto;
/*设置背景颜色*/
background-color: greenyellow;
/*设置padding*/
padding: 10px 0;
/*开启相对定位*/
position: relative;
/*裁剪溢出的内容*/
overflow: hidden;
}

/*设置imgList*/
#imgList {
/*去除项目符号*/
list-style: none;
/*设置ul的宽度*/
/*width: 2600px;*/
/*开启绝对定位*/
position: absolute;
/*设置偏移量*/
/*
* 每向左移动520px,就会显示到下一张图片
*/
left: 0px;
}

/*设置图片中的li*/
#imgList li {
/*设置浮动*/
float: left;
/*设置左右外边距*/
margin: 0 10px;
}

/*设置导航按钮*/
#navDiv {
/*开启绝对定位*/
position: absolute;
/*设置位置*/
bottom: 15px;
/*设置left值
outer宽度 520
navDiv宽度 25*5 = 125
520 - 125 = 395/2 = 197.5
* */
/*left: 197px;*/
}

#navDiv a {
/*设置超链接浮动*/
float: left;
/*设置超链接的宽和高*/
width: 15px;
height: 15px;
/*设置背景颜色*/
background-color: red;
/*设置左右外边距*/
margin: 0 5px;
/*设置透明*/
opacity: 0.5;
/*兼容IE8透明*/
filter: alpha(opacity=50);
}

/*设置鼠标移入的效果*/
#navDiv a:hover {
background-color: black;
}
</style>

<!--引用工具-->
<script type="text/javascript" src="js/tools.js"></script>
<script type="text/javascript">
window.onload = function () {
//获取imgList
var imgList = document.getElementById("imgList");
//获取页面中所有的img标签
var imgArr = document.getElementsByTagName("img");
//设置imgList的宽度
imgList.style.width = 520 * imgArr.length + "px";

/*设置导航按钮居中*/
//获取navDiv
var navDiv = document.getElementById("navDiv");
//获取outer
var outer = document.getElementById("outer");
//设置navDiv的left值
navDiv.style.left = (outer.offsetWidth - navDiv.offsetWidth) / 2 + "px";

//默认显示图片的索引
var index = 0;
//获取所有的a
var allA = document.getElementsByTagName("a");
//设置默认选中的效果
allA[index].style.backgroundColor = "black";

/*
点击超链接切换到指定的图片
点击第一个超链接,显示第一个图片
点击第二个超链接,显示第二个图片
* */

//为所有的超链接都绑定单击响应函数
for (var i = 0; i < allA.length; i++) {

//为每一个超链接都添加一个num属性
allA[i].num = i;

//为超链接绑定单击响应函数
allA[i].onclick = function () {

// 关闭自动切换定时器
clearInterval(timer);

//获取点击超链接的索引,并将其设置为index
index = this.num;

//切换图片
/*
* 第一张 0 0
* 第二张 1 -520
* 第三张 2 -1040
*/
//imgList.style.left = -520*index + "px";
//设置选中的a
setA();

//使用move函数来切换图片
move(imgList, "left", -520 * index, 20, function () {
// 动画执行完毕,开启自动切换
autoChange();
});
};
}
// 开启定时切换
autoChange();

function setA() {
//创建一个方法用来设置选中的a

// 处理循环播放的hover效果显示
if (index >= imgArr.length - 1) {
index = 0;

// 此时显示的是最后一张图片,而最后一张图片和第一张是一摸一样的,通过CSS将最后一张切换为第一张
imgList.style.left = "0px";
}

//遍历所有a,并将它们的背景颜色设置为红色
for (var i = 0; i < allA.length; i++) {
// allA[i].style.backgroundColor = "red"; // 会导致内联样式hover失效
allA[i].style.backgroundColor = "";
}

//将选中的a设置为黑色
allA[index].style.backgroundColor = "black";
};


var timer;
function autoChange() {
// 创建自动切换函数,用来开启自动切换图片
timer = setInterval(() => {
// 索引自增
index++;
index %= imgArr.length;
// 执行动画的切换
move(imgList, "left", -520 * index, 30, function () {
// 修改导航点
setA();
});
}, 2000)
}
};

</script>
</head>

<body>
<!-- 创建一个外部的div,来作为大的容器 -->
<div id="outer">
<!-- 创建一个ul,用于放置图片 -->
<ul id="imgList">
<li><img src="img/1.jpg" /></li>
<li><img src="img/2.jpg" /></li>
<li><img src="img/3.jpg" /></li>
<li><img src="img/4.jpg" /></li>
<li><img src="img/5.jpg" /></li>
<li><img src="img/1.jpg" /></li>
</ul>
<!--创建导航按钮-->
<div id="navDiv">
<a href="javascript:;"></a>
<a href="javascript:;"></a>
<a href="javascript:;"></a>
<a href="javascript:;"></a>
<a href="javascript:;"></a>
</div>
</div>
</body>
</html>

137 类的操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>类的操作</title>
<style>
.b1 {
width: 100px;
height: 100px;
background-color: #8080ff;
}

.b2 {
width: 50px;
height: 50px;
background-color: lightcoral;
}

.b3 {
border-radius: 20%;
}
</style>
<script>
window.onload = function () {
var btn01 = document.getElementById("btn01");
var box = document.getElementById("box");

btn01.onclick = function () {
// 单机响应函数

/*
通过sytle属性来修改元素的样式,每修改一个样式,浏览器都需要重新渲染一次页面
这样的执行性能较差,而且这种形式当我们要修改多个样式时,也不太方便,还存在代码耦合问题,所以不建议这样修改样式

box.style.background = "cyan";
box.style.height = "300px";
box.style.width = "300px";
*/
/*
一行代码修改多个样式
我们希望一行代码修改多个样式
*/
// 修改box的属性
// box.className = "b2";
/*
我们可以通过修改元素的class属性来间接的修改样式
这样一来,我们只需要修改一次,既可以同时修改多个样式,此时浏览器只需要重新渲染页面一次,性能较高,并且这种方式表现和行为进一步分离

但是存在问题:
.b1 {
width: 100px;
height: 100px;
background-color: #8080ff;
}
.b2 {
height: 50px;
background-color: lightcoral;
}
b2覆盖b1后,width效果会消失
*/
addClass(box, "b3");
// deleteClass(box, "b2");
toggleClass(box, "b2");
}
}


function addClass(obj, cn) {
/*
定义一个函数,用来向一个元素添加指定的class属性值
参数:
obj:要添加class属性的元素
cn:要添加的class
*/
// 限制已有效果添加
if (hasClass(obj, cn)) {
obj.className += " " + cn;
}

}


function hasClass(obj, cn) {
// 判断一个元素中是否有指定的class属性值
var reg = new RegExp("\\b" + cn + "\\b");
// \b为单词边界
if (reg.test(obj.className)) {
return false;
} else {
return true;
}
}


function deleteClass(obj, cn) {
/*
删除一个元素中指定的class属性值
*/
var reg = new RegExp("\\b" + cn + "\\b");
obj.className = obj.className.replace(reg, "");
}


function toggleClass(obj, cn) {
/*
toggleClass可以用来切换一个类
如果元素中有该类,则删除
如果元素中没有该类则添加
*/
if (hasClass(obj, cn)) {
addClass(obj, cn);
} else {
deleteClass(obj, cn);
}
console.log("d");
}
</script>
</head>

<body>
<button id="btn01">修改box样式</button>
<div id="box" class="b1"></div>
</body>

</html>

138 二级菜单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>二级菜单</title>
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8">
<title>二级菜单</title>
<style type="text/css">
* {
margin: 0;
padding: 0;
list-style-type: none;
}

a,
img {
border: 0;
text-decoration: none;
}

body {
font: 12px/180% Arial, Helvetica, sans-serif, "新宋体";
}
</style>
<link rel="stylesheet" href="./css/sdmenu.css">
<script src="./js/tools.js"></script>
<script>
window.onload = function () {

/*
我们的每一个菜单都是一个div
当div具有collapsed这个类时,div就是折叠状态
当div没有这个类时,div就是展开状态
*/
/*
点击菜单,切换菜单状态
*/
var menuSpan = document.querySelectorAll(".menuSpan");
// 保存当前打开的菜单
var openDiv = menuSpan[0].parentNode;
for (var i = 0; i < menuSpan.length; i++) {
menuSpan[i].onclick = function () {
// 获取当前span的父元素
var parentDiv = this.parentNode;

// 切换状态
toggleMenu(parentDiv);

// 打开菜单后,应该关闭之前的展开的菜单
if (openDiv != parentDiv && hasClass(openDiv, "collapsed")) {
// 打开菜单后,应该关闭之前打开的菜单
/*
为了可以统一处理动画的过渡效果,我们希望在这将addClass改为toggleClass
此处toggleClass()不需要有移除功能
*/
// addClass(openDiv, "collapsed");
// toggleClass(openDiv, "collapsed");

// 折叠动态效果
toggleMenu(openDiv);
}
openDiv = parentDiv;
};
}


/*
切换菜单后的折叠拉伸效果
*/
function toggleMenu(obj) {
// 在切换之前获取元素高度
var begin = obj.offsetHeight;

// 关闭parentDiv
toggleClass(obj, "collapsed");

// 在切换类之后获取一个高度
var end = obj.offsetHeight;

/*
动画效果就是将高度从begin向end过渡

将元素的高度重置为begin
*/
obj.style.height = begin + "px";

// 执行动画,从begin向end过渡
move(obj, "height", end, 10, function () {
// 动画执行完毕,内联样式没有存在意义,需要删除
obj.style.height = "";
});
}

}
</script>
</head>

<body>

<div id="my_menu" class="sdmenu">
<div>
<span class="menuSpan">在线工具</span>
<a href="#">图像优化</a>
<a href="#">收藏夹图标生成器</a>
<a href="#">邮件</a>
<a href="#">htaccess密码</a>
<a href="#">梯度图像</a>
<a href="#">按钮生成器</a>
</div>
<div class="collapsed">
<span class="menuSpan">支持我们</span>
<a href="#">推荐我们</a>
<a href="#">链接我们</a>
<a href="#">网络资源</a>
</div>
<div class="collapsed">
<span class="menuSpan">合作伙伴</span>
<a href="#">JavaScript工具包</a>
<a href="#">CSS驱动</a>
<a href="#">CodingForums</a>
<a href="#">CSS例子</a>
</div>
<div class="collapsed">
<span class="menuSpan">测试电流</span>
<a href="#">Current or not</a>
<a href="#">Current or not</a>
<a href="#">Current or not</a>
<a href="#">Current or not</a>
</div>
</div>
</body>

</html>

</head>

<body>

</body>

</html>

140 JSON

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JSON</title>
<script>
/*
JSON
- JS中的对象只有JS自己认识,其他语言不认识
- JSON就是一个特殊格式的字符串,这个字符串可以被任意语言识别,并且可以转换为任意语言中的对象,JSON在开发中主要用来进行数据的交互
- JSON JavaScript Object Notation对象表示法
- JSON和JS对象的格式一致,只不过JSON字符串中的属性名必须加双引!!!
- 其他的和JS语法一致
- JSON分类:
- 数组{}
- 对象[]

- JSON中允许的值
- 字符串
- 数值
- 对象,普通对象,不能时函数
- null
- 数组
- 布尔值
*/
var obj = '{"name":"ycy","age":18,"gender":"girl"}';
var obj2 = { name: "ycy", age: 18, gender: "girl" };
var arr = '[1,2,3,4,"hello",true]';
/*
JSON字符串转换为JS中的对象
在JS中,为我们提供了一个工具类,就叫JSON
这个对象可以帮助我们将一个JS对象转化为JSON格式,也可以将一个JSON格式对象转化为JS对象

JSON.parse()
- 可以将JSON字符串转换为JS对象
- 需要一个JSON字符串作为对象,会将该字符串转换为JS对象后返回

JSON.stringify()
- 可以将一个JS对象转换为JSON字符串
- 需要一个JS对象作为参数,会返回一个JSON字符串

JSON这个对象在IE7及其以下不支持
*/
var o = JSON.parse(obj);
console.log(o);
var o2 = JSON.parse(arr);
console.log(o2);

var json1 = JSON.stringify(obj2);
console.log(json1);

</script>
<style>

</style>
</head>

<body>

</body>

</html>

兼容IE

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JSON</title>
<!-- 如果要兼容IE7及其以下的JSON操作,则可以通过引入一个外部js文件实现 -->
<script src="./js/json2.js"></script>
<script>
var obj = '({"name":"ycy","age":18,"gender":"girl"})';
/*
eval()
- 这个函数可以用来执行一段字符串形式的JS代码,并将执行结果返回
- 如果使用eval()执行的字符串中含有{},它会将{}当做代码块,如果不希望将其当做代码块解析,则需要在字符串前后各加一个括号
- eval()这个函数功能强大,可以直接执行一个字符串中的JS代码,但是在开发中尽量不要使用,首先性能差,其次有安全隐患
*/
// var str = "alert('hello');";
// eval(str);

var obj = eval('(' + obj + ')');
console.log(obj);

</script>
<style></style>
</title>
</head>

<body>

</body>

</html>

JavaScript高级

基础深入总结

02 基本数据类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<title>01_数据类型</title>
</head>

<body>
<!--
1. 分类(2大类)
* 基本(值)类型
* Number: 任意数值
* String: 任意文本
* Boolean: true/false
* undefined: undefined
* null: null
* 对象(引用)类型
* Object: 任意对象
* Array: 特别的对象类型(下标/内部数据有序)
* Function: 特别的对象类型(可执行)
2. 判断
* typeof:
* 可以区别: 数值, 字符串, 布尔值, undefined, function
* 不能区别: null与对象, 一般对象与数组
* instanceof
* (a instanceof b)判断对象a是否为构造函数b的实例
* 专门用来判断对象数据的类型: Object, Array与Function
* ===
* 可以判断: undefined和null
-->

<script type="text/javascript">
// typeof: 返回的是数据类型的字符串表达形式
//1. 基本类型
var a
console.log(a, typeof a, a === undefined) // undefined 'undefined' true
console.log(a === typeof a) // false

a = 3
console.log(typeof a === 'number')
a = 'atguigu'
console.log(typeof a === 'string')
a = true
console.log(typeof a === 'boolean')

a = null
console.log(a === null) // true
console.log(typeof a) // 'object'

console.log('--------------------------------')

//2. 对象类型
var b1 = {
b2: [2, 'abc', console.log],
b3: function () {
console.log('b3()')
}
}
console.log(b1 instanceof Object, typeof b1) // true 'object'
console.log(b1.b2 instanceof Array, typeof b1.b2) // true 'object'
console.log(b1.b3 instanceof Function, typeof b1.b3) // true 'function'

console.log(typeof b1.b2[2]) // 'function'
console.log(b1.b2[2]('abc')) // 'abc' undefined
</script>

</body>

</html>

03 相关问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<title>01_相关问题</title>
</head>

<body>
<!--
1. undefined与null的区别?
* undefined代表定义了但是没有赋值
* null代表已经赋值, 只是值为null
2. 什么时候给变量赋值为null呢?
* var a = null //初始化赋值,a将指向一个对象, 但对象此时还没有确定
* a = null //让a指向的对象成为垃圾对象,以便被垃圾回收器回收,释放内存
3. 严格区别变量类型与数据类型?
* js的变量本身是没有类型的, 变量的类型实际上是变量内存中数据的类型
* 变量类型:
* 基本类型: 保存基本类型数据的变量
* 引用类型: 保存对象地址值的变量
* 数据对象
* 基本类型
* 对象类型
-->

<script type="text/javascript">
// 实例:实例对象
// 类型:类型对象
function Person(name, age) { // 构造函数 类型:对象
this.name = name
this.age = age
}
var p = new Person("张加林", 20) // 根据类型创建的实例对象
/*
最好不要直接使用Person("张加林", 20)调用构造函数
*/
console.log(p)

// 1. undefined与null的区别?
var a1
var a2 = null
console.log(a1, a2)

// 2. 什么时候给变量赋值为null呢?
//初始
var a3 = null
//中间
var name = 'Tom'
var age = 12
a3 = {
name: name,
age: age
}
//结束
a3 = null
</script>
</body>
</html>

04 数据、变量、内存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!-- 
1.什么是数据?
* 存储在内存中代表特定信息,本质上是二进制串01010……
* 数据的特点:可传递性,可运算性
* 一切皆数据,内存中,所有操作的目标:数据
* 算数运算
* 逻辑运算
* 赋值
* 运行函数
2.什么是内存?
* 内存条通电后产生的可存储数据的空间(临时,断电后消失)
* 内存产生和死亡:内存条(集成电路板)==>通电==>产生一定容量的存储空间==>存储各种数据==>断电==>内存全部消失
* 一块小内存的2个数据:
* 内部存储的数据
* 内存地址数据
* 内存的分类
* 栈:存储全局变量和局部变量(空间较小)
* 堆:存储对象(空间较大)
3.什么是变量?
* 可变化的量,由变量名和变量值组成
* 每个变量都对应着一块小内存,变量名用来查找对应的内存,变量值就是内存中保存的数据(数据可能是)
4.内存、数据、变量三者之间的关系
* 内存用来存储数据的空间
* 变量是内存的标识
5.代码执行
* 将代码取入内存,编译,解析执行
-->

05 相关问题

1
2
3
4
5
6
7
8
9
  <!--
问题: var a = xxx, a内存中到底保存的是什么?
* xxx是一个基本数据
* 保存的就是这个数据
* xxx是一个对象
* 保存的是对象的地址值
* xxx是一个变量
* 取决于xxx变量保存的数据的位置
-->

关于引用变量赋值问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<body>
<!--
关于引用变量赋值问题
* 多个个引用变量指向同一个对象, 通过一个引用变量修改对象内部数据, 其他所有引用变量也看得见
* 2个引用变量指向同一个对象,让一个引用变量指向另一个对象, 另一个引用变量还是指向原来的对象
-->
<script type="text/javascript">

//1. 2个引用变量指向同一个对象, 通过一个引用变量修改对象内部数据, 另一个引用变量也看得见
var obj1 = {}
var obj2 = obj1
obj2.name = 'Tom'
console.log(obj1.name)
function f1(obj) {
obj.age = 12
}
f1(obj2)
console.log(obj1.age)

//2. 2个引用变量指向同一个对象,让一个引用变量指向另一个对象, 另一个引用变量还是指向原来的对象
var obj3 = { name: 'Tom' }
var obj4 = obj3
obj3 = { name: 'JACK' }
console.log(obj4.name)
function f2(obj) {
obj = { name: 'Bob' }
}
f2(obj4)
console.log(obj4.name)

console.log("----------------")
var a = { name: 'zjl' }
var b = { name: 'zjl' }
a.name = 'ycy'
console.log(b.name);
/* 因为a和b指向的不是同一个对象 */
</script>
</body>

易错点

1
2
3
4
5
6
7
8
9
a = { name: 'zjl' }
function fun1(obj) {
obj = { name: "羽川翼" }
console.log(a.name) //zjl
console.log(obj.name) //羽川翼
}
fun1(a)
console.log(a) // { name: 'zjl' }
/* 总结:obj引用的地址值发生改变,不再引用传进来的形参地址,并且函数作用域的原因,这个对象只能在函数内使用 */

调用函数时,将数据a赋值给形参obj,此时a和obj都指向堆中的同一个{ name: 'zjl' },在函数内部修改obj指向的对象,由:2个引用变量指向同一个对象,让一个引用变量指向另一个对象, 另一个引用变量还是指向原来的对象,所以a仍然指向{ name: 'zjl' },而obj指向{ name: "羽川翼" },obj只是具有局部作用域,而且函数执行完成后会被销毁。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 同理有:
a = 3
function fun1(v) {
v = 666
console.log(a) // 3
}
fun1(a)
console.log(a) // 3


function fun2(a) {
a = 666
console.log(a) // 666
}
fun2(a)
console.log(a) // 3

06 相关问题2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<body>
<!--
问题: 在js调用函数时传递变量参数时, 是值传递还是引用传递
* 只有值传递, 没有引用传递, 传递的都是变量的值, 只是这个值可能是基本数据, 也可能是地址(引用)数据
* 如果后一种看成是引用传递, 那就值传递和引用传递都可以有
-->
<script type="text/javascript">
function f(a) {
console.log(a)
}
var n = 4
f(n) //传递的是n的值 --->值传递

function f2(a) {
a.name = 'atguigu'
}
n = {}
f2(n) // 传递的是n指向的对象 ---> 引用传递
console.log(n.name)
</script>
</body>

内存管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<body>
<!--
问题: JS引擎如何管理内存?
1. 内存生命周期
1). 分配需要的内存
2). 使用分配到的内存
3). 不需要时将其释放/归还
2. 释放内存
* 为执行函数分配的栈空间内存;函数执行完自动释放
* 存储对象的堆空间内存: 当内存没有引用指向时, 对象成为垃圾对象, 垃圾回收器后面就会回收释放此内存
-->
<script type="text/javascript">
var obj = {}
obj = null // ?

function fn () {
var a = 3
var b = {}
}
fn() // a,b都是自动释放的,在后面某个时刻由垃圾回收器回收
</script>
</body>

07 对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<body>
<!--
1. 什么是对象?
* 代表现实中的某个事物, 是该事物在编程中的抽象
* 多个数据的集合体(封装体)
* 用于保存多个数据的容器
2. 为什么要用对象?
* 便于对多个数据进行统一管理
3. 对象的组成
* 属性
* 代表现实事物的状态数据
* 由属性名和属性值组成
* 属性名都是字符串类型, 属性值是任意类型
* 方法
* 代表现实事物的行为数据
* 是特别的属性==>属性值是函数
4. 如何访问对象内部数据?
* .属性名: 编码简单, 但有时不能用
* ['属性名']: 编码麻烦, 但通用
-->
<script type="text/javascript">
// 创建对象
var p = {
name: 'Tom',
age: 12,
setName: function (name) {
this.name = name
},
setAge: function (age) {
this.age = age
}
}

// 访问对象内部数据
console.log(p.name, p['age'])
p.setName('Jack')
p['age'](23)
console.log(p['name'], p.age)

</script>
</body>

属性名相关问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<body>
<!--
问题: 什么时候必须使用['属性名']的方式?
* 属性名不是合法的标识名
* 属性名不确定
-->
<script type="text/javascript">
// 创建对象
var p = {}

/*情形一: 属性名不是合法的标识名*/
/*需求: 添加一个属性: content-type: text/json */
// p.content-type = 'text/json' //不正确
p['content-type'] = 'text/json'

/*情形二: 需要使用变量作为对象的属性名时*/
var prop = 'xxx'
var value = 123
// p.prop = value //不正确
p[prop] = value
console.log(p['content-type'], p[prop])
</script>
</body>

08 函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<body>
<!--
1. 什么是函数?
* 具有特定功能的n条语句的封装体
* 只有函数是可执行的, 其它类型的数据是不可执行的
* 函数也是对象
* typeof检查返回function
2. 为什么要用函数?
* 提高代码复用
* 便于阅读和交流
3. 如何定义函数?
* 函数声明
* 表达式
4. 如何调用(执行)函数?
* test()
* new test():构造函数
* obj.test():通过对象调用
* test.call/apply(obj):临时让test成为obj的方法进行调用(本来obj中没有test方法,目的是改变this的指向为obj)
-->
<script type="text/javascript">
/*
函数也是对象
*/
function fn() {

}
console.log(fn instanceof Object) // 是Object类型的实例
console.log(fn.prototype) // 内部有属性
console.log(fn.call) // 内部有方法
fn.t1 = 'atguigu' // 可以添加属性
fn.t2 = function () { // 可以添加方法
console.log('t2() ' + this.t1)
}
fn.t2()
</script>
</body>

09 回调函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<body>
<button id="btn">测试点击事件</button>
<!--
1. 什么函数才是回调函数?
* 你定义的
* 你没有直接调用
* 但最终它执行了(在特定条件或时刻)
2. 常见的回调函数?
* DOM事件函数
* 定时器函数

* ajax回调函数(后面学)
* 生命周期回调函数(后面学)
-->
<script type="text/javascript">

//1. DOM事件回调函数
var btn = document.getElementById('btn')
btn.onclick = function () {
alert(this.innerHTML)
}

//2. 定时器回调函数
setInterval(function () {
alert('到点啦!')
}, 2000)
</script>
</body>

10 IIFE(立即调用函数表达式 / 匿名函数自调用)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!--
1. 理解
* 全称: Immediately-Invoked Function Expression 立即调用函数表达式
* 别名: 匿名函数自调用
2. 作用
* 隐藏内部实现
* 不污染外部命名空间
-->
<script type="text/javascript">
(function (i) {
var a = 4
function fn() {
console.log('fn ', i+a)
}
fn()
})(3)
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<body>
<!--
1. 理解
* 全称: Immediately-Invoked Function Expression 立即调用函数表达式
* 别名: 匿名函数自调用
2. 作用
* 隐藏内部实现
* 不污染外部命名空间
* 用来编写js模块
-->
<script type="text/javascript">
(function (i) {
var a = 4
function fn() {
console.log('fn ', i + a)
}
fn()
})(3)
var a = 4
console.log(a) // 4
// 对于匿名函数调用,千万小心分号!!!
; (function () {
var a = 1
function test() {
console.log(++a)
}
window.$ = function () { // 向外暴露一个全局函数
return {
test: test
}
}
})()

$().test() // 2
console.log(a) // 4

11 函数中的this

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<body>
<!--
1. this是什么?
* 任何函数本质上都是通过某个对象来调用的,如果没有直接指定,那就是window
* 一个关键字, 一个内置的引用变量
* 在函数中都可以直接使用this
* this代表调用函数的当前对象
* 在定义函数时, this还没有确定, 只有在执行时才动态确定(绑定)的
2. 如何确定this的值?
* test():window
* obj.test():obj
* new test():新创建的对象
* test.call(obj):obj
前置知识:
* 本质上任何函数在执行时都是通过某个对象调用的
-->

<script type="text/javascript">
function Person(color) {
console.log(this)
this.color = color;
this.getColor = function () {
console.log(this)
return this.color;
};
this.setColor = function (color) {
console.log(this)
this.color = color;
};
}

Person("red"); //this是谁? window

var p = new Person("yello"); //this是谁? p

p.getColor(); //this是谁? p

var obj = {};
p.setColor.call(obj, "black"); //this是谁? obj

var test = p.setColor;
test(); //this是谁? window

function fun1() {
function fun2() {
console.log(this);
}
fun2(); //this是谁? window
}
fun1();
</script>
</body>

12 分号问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<!--
1. js一条语句的后面可以不加分号
2. 是否加分号是编码风格问题, 没有应该不应该,只有你自己喜欢不喜欢
3. 在下面2种情况下不加分号会有问题
* 小括号开头的前一条语句
* 中方括号开头的前一条语句
4. 解决办法: 在行首加分号
5. 强有力的例子: vue.js库
6. 知乎热议: https://www.zhihu.com/question/20298345
-->
<script type="text/javascript">

// 情形一: 小括号开头的前一条语句
var a = 3
; (function () {

})
/*
错误理解: 将3看成是函数调用
var a = 3(function () {

})
*/

// 情形二: 中方括号开头的前一条语句
var b = a
;[1, 3, 5].forEach(function (item) {
console.log(item)
})
/*
错误理解:
a = b[5].forEach(function(e){
console.log(e)
})
</script>

函数高级

15 函数的prototype

image-20211117170342952

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<body>
<!--
1. 函数的prototype属性(图)
* 每个函数都有一个prototype属性, 它默认指向一个Object空对象(即称为: 原型对象)
* 原型对象中有一个属性constructor, 它指向函数对象
2. 给原型对象添加属性(一般都是方法)
* 作用: 函数的所有实例对象自动拥有原型中的属性(方法)
-->
<script type="text/javascript">
// 每个函数都有一个prototype属性, 它默认指向一个对象(即称为: 原型对象)
console.log(Date.prototype, typeof Date.prototype)
function fn() {

}
console.log(fn.prototype, typeof fn.prototype)

// 原型对象中有一个属性constructor, 它指向函数对象
console.log(Date.prototype.constructor === Date)
console.log(fn.prototype.constructor === fn)


// 2. 给原型对象添加属性(一般都是方法)===>实例对象可以访问
function F() {
}
F.prototype.age = 12 //添加属性
F.prototype.setAge = function (age) { // 添加方法
this.age = age
}
// 创建函数的实例对象
var f = new F()
console.log(f.age)
f.setAge(23)
console.log(f.age)

</script>
</body>

16 显式原型和隐式原型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<title>02_显式原型与隐式原型</title>
</head>

<body>
<!--
1. 每个函数function都有一个prototype,即显式原型
2. 每个实例对象都有一个__proto__,可称为隐式原型
3. 对象的隐式原型的值为其对应构造函数的显式原型的值
4. 内存结构(图)
5. 总结:
* 函数的prototype属性: 在定义函数时自动添加的, 默认值是一个空Object对象
* 对象的__proto__属性: 创建对象时自动添加的, 默认值为构造函数的prototype属性值
* 程序员能直接操作显式原型, 但不能直接操作隐式原型(ES6之前)
-->
<script type="text/javascript">
function Fn() {

}
var fn = new Fn()
console.log(Fn.prototype, fn.__proto__)
// console.log(Fn.prototype===fn.__proto__)

// Fn.prototype.test = function () {
// console.log('test()')
// }
// fn.test()

</script>
</body>

</html>

image-20211123005614856

17 原型链

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<body>
<!--
1. 原型链(图解)
* 访问一个对象的属性时,
* 先在自身属性中查找,找到返回
* 如果没有, 再沿着__proto__这条链向上查找, 找到返回
* 如果最终没找到, 返回undefined
* 别名: 隐式原型链
* 作用: 查找对象的属性(方法)
2. 构造函数/原型/实体对象的关系(图解)
3. 构造函数/原型/实体对象的关系2(图解)
-->
<script type="text/javascript">
function Fn() {
this.test1 = function () {
console.log('test1()')
}
}
console.log(Fn.prototype) // 含有test2()
Fn.prototype.test2 = function () {
console.log('test2()')
}
var fn = new Fn()

fn.test1()
fn.test2()
console.log(fn.toString())
console.log(fn.test3) // undefined
fn.test3() // 报错
</script>
</body>
image-20211123114246690 image-20211123114313048

image-20211123120218139

x

var Foo = new Function(),所以所有函数都有隐式原型属性,指向Function的显示原型。

注意:

  • function Function()实例对象的显示原型和隐式原都型指向Function.prototype
image-20211123121508335

image-20211123145249079

  • 自己尝试用process on画了一下,不知道对不对,反正都可以在控制台验证的。

https://www.processon.com/view/link/619c9b56e401fd183dbdee8f

18 原型链补充

函数的显式原型指向的对象默认是空Object对象(但是Object不满足)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<body>
<script>
function Fn() {
this.test1 = function () {
console.log('test1()')
}
}
/*
1.函数的显式原型指向的对象默认是空Object实例对象(但是Object不满足)
*/
console.log(Fn.prototype instanceof Object) // true
console.log(Object.prototype instanceof Object) // false
console.log(Function.prototype instanceof Object) // true

/*
2.所有函数都是Function的实例对象(包含Function本身)
*/
console.log(Function.__proto__ === Function.prototype) // true

/*
2.Object的原型对象是原型链的尽头
*/
console.log(Object.prototype.__proto__) // null
</script>
</body>

19 原型链属性问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<body>
<!--
1. 读取对象的属性值时: 会自动到原型链中查找
2. 设置对象的属性值时: 不会查找原型链, 如果当前对象中没有此属性, 直接添加此属性并设置其值
3. 方法一般定义在原型中, 属性一般通过构造函数定义在对象本身上
-->
<script>
function Fn() {

}
Fn.prototype.a = 'xxx'
var fn1 = new Fn()
console.log(fn1.a, fn1) // xxx Fn{}

var fn2 = new Fn()
fn2.a = 'yyy'
console.log(fn1.a, fn2.a, fn2) // xxx yyy Fn {a: 'yyy'}
</script>
</body>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<body>
<!--
1. 读取对象的属性值时: 会自动到原型链中查找
2. 设置对象的属性值时: 不会查找原型链, 如果当前对象中没有此属性, 直接添加此属性并设置其值
3. 方法一般定义在原型中, 属性一般通过构造函数定义在对象本身上
-->
<script type="text/javascript">
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.setName = function (name) {
this.name = name;
}
Person.prototype.sex = '男';

var p1 = new Person('Tom', 12)
p1.setName('Jack')
console.log(p1.name, p1.age, p1.sex)
p1.sex = '女'
console.log(p1.name, p1.age, p1.sex)

var p2 = new Person('Bob', 23)
console.log(p2.name, p2.age, p2.sex)

</script>
</body>

20 探索instanceof

  1. instanceof是如何判断的?
  • 表达式: A instanceof B

  • 如果B函数的显式原型对象在A对象的原型链上, 返回true, 否则返回false

  1. Function是通过new自己产生的实例

案例一

1
2
3
4
function Foo() {  }
var f1 = new Foo();
console.log(f1 instanceof Foo); // ture
console.log(f1 instanceof Object); //true

image-20211123165304929

案列二

1
2
3
4
5
6
7
console.log(Object instanceof Function); // true
console.log(Object instanceof Object); // true
console.log(Function instanceof Function); // true
console.log(Function instanceof Object); // true

function Foo() {}
console.log(Object instanceof Foo); // false

image-20211123165424420

22 变量提升与函数提升

1
2
3
4
5
6
7
8
9
  <!--
1. 变量声明提升(必须使用函数声明方式,不能使用变量声明方式)
* 通过var定义(声明)的变量, 在定义语句之前就可以访问到
* 值: undefined
2. 函数声明提升
* 通过function声明的函数, 在之前就可以直接调用
* 值: 函数定义(对象)
3. 问题: 变量提升和函数提升是如何产生的?
-->
1
2
3
/*变量提升*/
console.log(a1) //可以访问, 但值是undefined
var a1 = 3
1
2
3
4
5
6
7
/*函数提升*/
a2() // 可以直接调用

var a1 = 3
function a2() {
console.log('a2()')
}

易错

1
2
3
4
5
f3() // 不能调用,会报错,因为此时遵循变量提升

var f3 = function(){
console.log('f3()')
}

23 执行上下文

  1. 代码分类(位置)
  • 全局代码
  • 函数代码
  1. 全局执行上下文
  • 在执行全局代码前将window确定为全局执行上下文
  • 对全局数据进行预处理
    • var定义的全局变量(直接a = 1是不行的,不会被预处理)==>undefined, 添加为window的属性
    • function声明的全局函数==>赋值(fun), 添加为window的方法
    • this==>赋值(window)
  • 开始执行全局代码
  1. 函数执行上下文
  • 在调用函数, 准备执行函数体之前, 创建对应的函数执行上下文对象
  • 对局部数据进行预处理
    • 形参变量==>赋值(实参)==>添加为执行上下文的属性
    • arguments==>赋值(实参列表), 添加为执行上下文的属性
    • var定义的局部变量==>undefined, 添加为执行上下文的属性
    • function声明的函数 ==>赋值(fun), 添加为执行上下文的方法
    • this==>赋值(调用函数的对象)
  • 开始执行函数体代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<script type="text/javascript">
var a1 = 1
function fn() {
console.log(a1) // 1
console.log(a2) // undefined
a3() // a3()!!
console.log(this) // Window
console.log(arguments) // 输出伪数组对象

var a2 = 3
function a3() {
console.log('a3()!!')
// thish
}
}
fn(2, 3)
</script>

24 执行上下文栈

image-20211123211006407

image-20211123211429918

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<body>
<!--
1. 在全局代码执行前, JS引擎就会创建一个栈来存储管理所有的执行上下文对象
2. 在全局执行上下文(window)确定后, 将其添加到栈中(压栈)
3. 在函数执行上下文创建后, 将其添加到栈中(压栈)
4. 在当前函数执行完后,将栈顶的对象移除(出栈)
5. 当所有的代码执行完后, 栈中只剩下window
-->
<script type="text/javascript">
//1. 进入全局执行上下文
var a = 10
var bar = function (x) {
var b = 5
foo(x + b) //3. 进入foo执行上下文
}
var foo = function (y) {
var c = 5
console.log(a + c + y)
}
bar(10) //2. 进入bar函数执行上下文
</script>
</body>

25 上下文面试题

第一题

image-20211123211915586
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<body>
<!--
1. 依次输出什么?
2. 整个过程中产生了几个执行上下文?
* 全局上下文
* f(1)
* f(2)
* f(3)
* f(4)
栈结构分析:
f(4)
f(3)
f(2)
f(1)
全局上下文
-->
<script type="text/javascript">
console.log('global begin: '+ i)
var i = 1
foo(1);
function foo(i) {
if (i == 4) {
return;
}
console.log('foo() begin:' + i);
foo(i + 1) // 递归
console.log('foo() end:' + i);
}
console.log('global end: ' + i)
</script>

</body>

第二题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<body>
<script type="text/javascript">
/*
测试题1: 函数提升优先级高于变量提升,且不会被同名变量声明时覆盖,但是会被变量赋值后覆盖
*/
function a() {}
var a;
console.log(typeof a) // function


/*
测试题2: 变量预处理, in操作符
*/
if (!(b in window)) {
var b = 1; // 相当于全局声明了变量b,但是在if中赋值
}
console.log(b) // undefined

/*
测试题3: 函数提升优先级高于变量提升,且不会被同名变量声明时覆盖,但是会被变量赋值后覆盖,这里是函数被赋值操作覆盖了
*/
var c = 1
function c(c) {
console.log(c)
var c = 3
}
c(2) // 报错

</script>
</body>

026 复习

JS是基于原型对象的继承,JAVA和Python是基于类的继承。

027 作用域与作用域链

image-20211124144242056

  1. 区别1
  • 全局作用域之外,每个函数都会创建自己的作用域,作用域在函数定义时就已经确定,而不是在函数调用时

  • 全局执行上下文环境是在全局作用域确定之后, js代码马上执行之前创建

  • 函数执行上下文环境是在调用函数时, 函数体代码执行之前创建

  1. 区别2
  • 作用域是静态的, 只要函数定义好了就一直存在, 且不会再变化

  • 上下文环境是动态的, 调用函数时创建, 函数调用结束时上下文环境就会被释放

  1. 联系
  • 执行上下文环境(对象)是从属于所在的作用域

  • 全局上下文环境==>全局作用域

  • 函数上下文环境==>对应的函数使用域

image-20211124145129879

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<body>
<!--
1. 理解
* 多个上下级关系的作用域形成的链, 它的方向是从下向上的(从内到外)
* 查找变量时就是沿着作用域链来查找的
2. 查找一个变量的查找规则
* 在当前作用域下的执行上下文中查找对应的属性, 如果有直接返回, 否则进入2
* 在上一级作用域的执行上下文中查找对应的属性, 如果有直接返回, 否则进入3
* 再次执行2的相同操作, 直到全局作用域, 如果还找不到就抛出找不到的异常
-->
<script type="text/javascript">

var a = 2;
function fn1() {
var b = 3;
function fn2() {
var c = 4;
console.log(c); // 4
console.log(b); // 3
console.log(a); // 2
console.log(d); // 报错
}

fn2();
}
fn1();
</script>
</body>

注意:函数作用域内读取不到指定变量会抛异常!!!

28 面试题

第一题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<script type="text/javascript">
/*
问题: 结果输出多少?

作用域在函数定义时就已经确定
*/
var x = 10;
function fn() {
console.log(x);
}
function show(f) {
var x = 20;
f();
}
show(fn) // 10
</script>

第二题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<script type="text/javascript">
/*
说说它们的输出情况

1.ƒ () {
console.log(fn)
}

2.Uncaught ReferenceError: fn2 is not defined
at Object.fn2
应该改为:this.fn2
*/

var fn = function () {
console.log(fn)
}
fn()

var obj = {
fn2: function () {
console.log(fn2) // fn2不是声明的变量,而是obj的属性
}
}
obj.fn2()
</script>

29 循环遍历加监听

错误代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<body>

<button>测试1</button>
<button>测试2</button>
<button>测试3</button>
<!--
需求: 点击某个按钮, 提示"点击的是第n个按钮"
-->
<script type="text/javascript">
var btns = document.getElementsByTagName('button')
//有问题
for(var i=0,length=btns.length;i<length;i++) {
var btn = btns[i]
btn.onclick = function () {
alert('第'+(i+1)+'个')
}
}
</script>
</body>

将i保存为下标

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<body>
<button>测试1</button>
<button>测试2</button>
<button>测试3</button>
<!-- 需求:点击某个按钮,提示点击的是第几个按钮 -->
<script>
var btns = document.getElementsByTagName("button")
for (var i = 0; i < btns.length; i++) {
btns[i].index = i + 1
// 将btn对应的下标保存为每个btn的属性
btns[i].onclick = function () {
alert('这是第' + this.index + '个button')
}
}
</script>
</body>

利用闭包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<body>

<button>测试1</button>
<button>测试2</button>
<button>测试3</button>
<!--
需求: 点击某个按钮, 提示"点击的是第n个按钮"
-->
<script type="text/javascript">
var btns = document.getElementsByTagName('button')
//解决办法: 利用闭包
for (var i = 0, length = btns.length; i < length; i++) {
(function (i) {
var btn = btns[i]
btn.onclick = function () {
alert('第' + (i + 1) + '个')
}
})(i)
}
</script>
</body>

30 理解闭包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<body>
<!--
1. 如何产生闭包?
* 当一个嵌套的内部(子)函数引用了嵌套的外部(父)函数的变量(函数)时, 就产生了闭包
2. 闭包到底是什么?
* 使用chrome调试查看
* 理解一: 闭包是嵌套的内部函数(绝大部分人)
* 理解二: 包含被引用变量(函数)的对象(极少数人)
* 注意: 闭包存在于嵌套的内部函数中
3. 产生闭包的条件?
* 函数嵌套
* 内部函数引用了外部函数的数据(变量/函数)
-->
<script type="text/javascript">
function fn1() {
var a = 3
function fn2() { // 执行函数定义就会产生闭包(不用调用内部函数)
console.log(a)
}
return fn2
}
fn1()

</script>
</body>

31 常见的闭包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<body>
<!--
1. 将函数作为另一个函数的返回值
2. 将函数作为实参传递给另一个函数调用
-->
<script type="text/javascript">
// 1. 将函数作为另一个函数的返回值
function fn1() {
var a = 2

function fn2() {
a++
console.log(a)
}

return fn2
}

var f = fn1() // 注意:fn1()函数执行后,局部变量fn2被释放了,但是fn2所保存的函数对象的地址值返回给了全局变量f了

f() // 3
f() // 4

// 2. 将函数作为实参传递给另一个函数调用
function showMsgDelay(msg, time) {
setTimeout(function () {
console.log(msg)
}, time)
}
showMsgDelay('hello', 1000)
</script>
</body>

32 闭包的作用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<body>
<!--
1. 使用函数内部的变量在函数执行完后, 仍然存活在内存中(延长了局部变量的生命周期)
2. 让函数外部可以操作(读写)到函数内部的数据(变量/函数)

问题:
1. 函数执行完后, 函数内部声明的局部变量是否还存在?
一般是不会存在的,存在于闭包中的变量才可能存在
2. 在函数外部能直接访问函数内部的局部变量吗?
不能,但是通过闭包可以让外部操作它
-->
<script type="text/javascript">
function fun1() {
var a = 3;

function fun2() {
a++; //引用外部函数的变量--->产生闭包
console.log(a);
}

return fun2;
}
var f = fun1(); //由于f引用着内部的函数-->内部函数以及闭包都没有成为垃圾对象(如果只是fun1(),那么局部变量就不会存在)
/* fun1()执行完由于是函数释放成为垃圾对象,当f=fn1时由于是赋值操作把地址赋值给了所以现在是f和fn1都指向一个内存空间,所以fun1执行完不能释放因为f还指向这个内存空间 */

f(); //间接操作了函数内部的局部变量
f();
</script>
</body>

33 闭包的生命周期

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<body>
<!--
1. 产生: 在嵌套内部函数定义执行完时就产生了(不是在调用)
2. 死亡: 在嵌套的内部函数成为垃圾对象时
-->
<script type="text/javascript">
function fun1() {
//此处闭包已经产生
var a = 3;

function fun2() {
a++;
console.log(a);
}

return fun2;
}
var f = fun1();

f();
f();
f = null //此时闭包对象死亡(包含闭包的函数成为了垃圾对象)
</script>
</body>

34 闭包应用 自定义JS模块

例一

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* 自定义模块1
*/
function coolModule() {
//私有的数据
var msg = 'atguigu'
var names = ['I', 'Love', 'you']

//私有的操作数据的函数
function doSomething() {
console.log(msg.toUpperCase())
}
function doOtherthing() {
console.log(names.join(' '))
}

//向外暴露包含多个方法的对象
return {
doSomething: doSomething,
doOtherthing: doOtherthing
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<body>
<!--
闭包的应用2 : 定义JS模块
* 具有特定功能的js文件
* 将所有的数据和功能都封装在一个函数内部(私有的)
* 只向外暴露一个包信n个方法的对象或函数
* 模块的使用者, 只需要通过模块暴露的对象调用方法来实现对应的功能
-->
<script type="text/javascript" src="05_coolModule.js"></script>
<script type="text/javascript">
var module = coolModule()
module.doSomething()
module.doOtherthing()
</script>
</body>

例二

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* 自定义模块2
*/
(function (window) {
//私有的数据
var msg = 'atguigu'
var names = ['I', 'Love', 'you']
//操作数据的函数
function a() {
console.log(msg.toUpperCase())
}
function b() {
console.log(names.join(' '))
}

window.coolModule2 = {
doSomething: a,
doOtherthing: b
}
})(window)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<body>
<!--
闭包的应用2 : 定义JS模块
* 具有特定功能的js文件
* 将所有的数据和功能都封装在一个函数内部(私有的)
* 只向外暴露一个包信n个方法的对象或函数
* 模块的使用者, 只需要通过模块暴露的对象调用方法来实现对应的功能
-->
<script type="text/javascript" src="05_coolModule2.js"></script>
<script type="text/javascript">
coolModule2.doSomething()
coolModule2.doOtherthing()
</script>
</body>

35 闭包缺点——内存溢出和内存泄漏

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<body>
<!--
1. 缺点
* 函数执行完后, 函数内的局部变量没有释放, 占用内存时间会变长
* 容易造成内存泄露
2. 解决
* 能不用闭包就不用
* 及时释放
-->
<script type="text/javascript">
function fn1() {
var a = 2;

function fn2() {
a++;
console.log(a);
}

return fn2;
}
var f = fn1();

f(); // 3
f(); // 4

f = null // 释放
</script>
</body>
  • 内存溢出
    • 一种程序运行出现的错误
    • 当程序运行需要的内存超过了剩余的内存时,就抛出内存溢出的错误
  • 内存泄漏
    • 占用的内存没有及时释放
    • 内存泄漏积累多了容易导致内存溢出
    • 常见内存泄漏
      • 意外的全局变量
      • 没有及时清理的计时器或回调函数
      • 闭包
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<body>
<script>
// 内存溢出
var obj = {};
for (var i = 0; i < 10000; i++) {
obj[i] = new Array(100000000);
console.log("--------------");
}

// 内存泄漏
function fn() {
a = 3 // 不使用var会导致a变成全局变量
console.log(a)
}
fn()

var id = setInterval(function () { // 启动循环定时器后不清理
console.log('------------')
}, 10000)
// clearInterval(id)

function fn1() {
var a = 1
function fn2() {
a++
console.log(a)
}
return fn2
}
var f = fn1()
// f = null
// 需要释放
</script>
</body>

36 面试题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<script type="text/javascript">
/*
说说它们的输出情况
*/

//代码片段一
var name = "The Window";
var object = {
name: "My Object",
getNameFunc: function () {
return function () {
// console.log(this) // window(没有闭包)
return this.name;
};
}
};
console.log(object.getNameFunc()()); // The Window

//代码片段二
var name2 = "The Window";
var object2 = {
name2: "My Object",
getNameFunc: function () {
var that = this; // 这里存了一次this,为object2
return function () { // 这里是闭包
return that.name2;
};
}
};
console.log(object2.getNameFunc()()); // My Object
</script>
image-20211124180024239
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<script type="text/javascript">
/*
说说它们的输出情况
*/

function fun(n, o) {
console.log(o)
return {
fun: function (m) {
return fun(m, n)
}
}
}

var a = fun(0)
a.fun(1)
a.fun(2)
a.fun(3) //undefined,0,0,0

var b = fun(0).fun(1).fun(2).fun(3) //undefined,0,1,2

var c = fun(0).fun(1) // undefined,0
c.fun(2)
c.fun(3) //undefined,1,1

</script>

37 对象创建模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<body>
<!--
方式一: Object构造函数模式
* 套路: 先创建空Object对象, 再动态添加属性/方法
* 适用场景: 起始时不确定对象内部数据
* 问题: 语句太多
-->
<script type="text/javascript">
/*
一个人: name:"Tom", age: 12
*/
var p = new Object()
// p = {}
p.name = 'Tom'
p.age = 12
p.setName = function (name) {
this.name = name
}
p.setaAge = function (age) {
this.age = age
}

console.log(p)

</script>
</body>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!--
方式二: 对象字面量模式
* 套路: 使用{}创建对象, 同时指定属性/方法
* 适用场景: 起始时对象内部数据是确定的
* 问题: 如果创建多个对象, 有重复代码
-->
<script type="text/javascript">
var p = {
name: 'Tom',
age: 23,
setName: function (name) {
this.name = name
}
}
console.log(p.name, p.age)
p.setName('JACK')
console.log(p.name, p.age)

var p2 = {
name: 'BOB',
age: 24,
setName: function (name) {
this.name = name
}
}
</script>
</body>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<body>
<!--
方式三: 工厂模式
* 套路: 通过工厂函数动态创建对象并返回
* 适用场景: 需要创建多个对象
* 问题: 对象没有一个具体的类型, 都是Object类型
-->
<script type="text/javascript">
// 工厂函数: 返回一个需要的数据的函数
function createPerson(name, age) {
var p = {
name: name,
age: age,
setName: function (name) {
this.name = name
}
}
return p
}

var p1 = createPerson('Tom', 12)
var p2 = createPerson('JAck', 13)
console.log(p1)
console.log(p2)
</script>
</body>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<body>
<!--
方式四: 自定义构造函数模式
* 套路: 自定义构造函数, 通过new创建对象
* 适用场景: 需要创建多个类型确定的对象
* 问题: 每个对象都有相同的数据, 浪费内存
-->
<script type="text/javascript">

function Person(name, age) {
this.name = name
this.age = age
this.setName = function (name) {
this.name = name
}
}

var p1 = new Person('Tom', 12)
var p2 = new Person('Tom2', 13)
console.log(p1, p1 instanceof Person)
</script>
</body>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<body>
<!--
方式六: 构造函数+原型的组合模式
* 套路: 自定义构造函数, 属性在函数中初始化, 方法添加到原型上
* 适用场景: 需要创建多个类型确定的对象
-->
<script type="text/javascript">
function Person (name, age) {
this.name = name
this.age = age
}
Person.prototype.setName = function (name) {
this.name = name
}
var p1 = new Person('Tom', 12)
var p2 = new Person('JAck', 23)
p1.setName('TOM3')
console.log(p1)

Person.prototype.setAge = function (age) {
this.age = age
}
p1.setAge(23)
console.log(p1.age)

Person.prototype = {}
p1.setAge(34)
console.log(p1)
var p3 = new Person('BOB', 12)
p3.setAge(12)
</script>
</body>

38 原型链继承

原型链继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<body>
<!--
方式1: 原型链继承
1. 套路
1. 定义父类型构造函数
2. 给父类型的原型添加方法
3. 定义子类型的构造函数
4. 创建父类型的对象赋值给子类型的原型
5. 将子类型原型的构造属性设置为子类型
6. 给子类型原型添加方法
7. 创建子类型的对象: 可以调用父类型的方法
2. 关键
1. 子类型的原型为父类型的一个实例对象
-->
<script type="text/javascript">

function Supper() { //父类型
this.superProp = 'The super prop'
}
//原型的数据所有的实例对象都可见
Supper.prototype.showSupperProp = function () {
console.log(this.superProp)
}

function Sub() { //子类型
this.subProp = 'The sub prop'
}

// 子类的原型为父类的实例
Sub.prototype = new Supper()
// 修正Sub.prototype.constructor为Sub本身
Sub.prototype.constructor = Sub //让子类型原型的constructorzhi

Sub.prototype.showSubProp = function () {
console.log(this.subProp)
}

// 创建子类型的实例
var sub = new Sub()
// 调用父类型的方法
sub.showSubProp()
// 调用子类型的方法
sub.showSupperProp()
</script>
</body>

image-20211124213125840

https://www.processon.com/view/link/619e3f107d9c083e98aafa1b

39 组合继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<title>02_借用构造函数继承</title>
</head>

<body>
<!--
方式2: 借用构造函数继承(假的)
1. 套路:
1. 定义父类型构造函数
2. 定义子类型构造函数
3. 在子类型构造函数中调用父类型构造
2. 关键:
1. 在子类型构造函数中通用call()调用父类型构造函数
-->
<script type="text/javascript">

function Person(name, age) {
this.name = name
this.age = age
}

function Student(name, age, price) {
Person.call(this, name, age) // this.Person(name, age)
this.price = price
}

var s = new Student('Tom', 20, 12000)
console.log(s.name, s.age, s.price)
</script>
</body>

</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<body>
<!--
方式3: 原型链+借用构造函数的组合继承
1. 利用原型链实现对父类型对象的方法继承
2. 利用call()借用父类型构建函数初始化相同属性
-->
<script type="text/javascript">

function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.setName = function (name) {
this.name = name
}

function Student(name, age, price) {
Person.call(this, name, age) //得到父类型的属性
this.price = price
}
Student.prototype = new Person() //得到父类型的方法
Student.prototype.constructor = Student
Student.prototype.setPrice = function (price) {
this.price = price
}

var s = new Student('Tom', 12, 10000)
s.setPrice(11000)
s.setName('Bob')
console.log(s)
console.log(s.constructor)

</script>
</body>

40 复习

new一个对象背后做了什么?

  • 创建一个空对象
  • 给对象设置__proto__,值为构造函数对象的prototype属性值,this.__proto__ = this.prototype
  • 执行构造函数体(给对象添加属性和方法)

42 进程与线程

1.进程:程序的一次执行, 它占有一片独有的内存空间

2.线程: CPU的基本调度单位, 是程序执行的一个完整流程

3.进程与线程

  • 一个进程中一般至少有一个运行的线程: 主线程
  • 一个进程中也可以同时运行多个线程, 我们会说程序是多线程运行的
  • 一个进程内的数据可以供其中的多个线程直接共享
  • 多个进程之间的数据是不能直接共享的

4.浏览器运行是单进程还是多进程?

  • 有的是单进程
    • firefox
    • 老版IE
  • 有的是多进程
    • chrome
    • 新版IE

5.如何查看浏览器是否是多进程运行的呢?

  • 任务管理器==>进程

6.浏览器运行是单线程还是多线程?

  • 都是多线程运行的

7.JS是单线程还是多线程?

  • js是单线程运行的
  • 但使用H5中的 Web Workers可以多线程运行

43 浏览器内核

  1. 什么是浏览器内核?
  • 支持浏览器运行的最核心的程序
  1. 不同的浏览器可能不太一样
  • Chrome, Safari: webkit
  • firefox: Gecko
  • IE: Trident
  • 360,搜狗等国内浏览器: Trident + webkit
  1. 内核由很多模块组成
  • 主线程
    • html,css文档解析模块 : 负责页面文本的解析
    • dom/css模块 : 负责dom/css在内存中的相关处理
    • 布局和渲染模块 : 负责页面的布局和效果的绘制
  • 分线程
    • 定时器模块 : 负责定时器的管理
    • 网络请求模块 : 负责服务器请求(常规/Ajax)
    • 事件响应模块 : 负责事件的管理

44 定时器思考

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<body>

<button id="btn">启动定时器</button>

<!--
1. 定时器真是定时执行的吗?
* 定时器并不能保证真正定时执行
* 一般会延迟一丁点(可以接受), 也有可能延迟很长时间(不能接受)
2. 定时器回调函数是在分线程执行的吗?
* 在主线程执行的, js是单线程的
3. 定时器是如何实现的?
* 事件循环模型(后面讲)
-->
<script type="text/javascript">
document.getElementById('btn').onclick = function () {
var start = Date.now()
console.log('启动定时器')
setTimeout(function () {
console.log('定时器执行了: ', Date.now()-start)
}, 100)

//定时器启动之后做一个长时间的工作
for (var i = 0; i < 1000000000; i++) {

}
console.log('完成长时间工作', Date.now()-start)
}
</script>
</body>

45 JS是单线程执行的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<body>
<!--
1. 如何证明js执行是单线程的?
* setTimeout()的回调函数是在主线程执行的
* 定时器回调函数只有在运行栈中的代码全部执行完后才有可能执行
2. 为什么js要用单线程模式, 而不用多线程模式?
* JavaScript的单线程,与它的用途有关。
* 作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。
* 这决定了它只能是单线程,否则会带来很复杂的同步问题

3. 代码的分类:
* 初始化代码
* 回调代码
4. js引擎执行代码的基本流程
* 先执行初始化代码: 包含一些特别的代码
* 设置定时器
* 绑定监听
* 发送ajax请求
* 后面在某个时刻才会执行回调代码
-->
<script type="text/javascript">
setTimeout(function () {
console.log('timeout 3')
alert('3333')
}, 3000)

setTimeout(function () {
console.log('timeout 2')
alert('2222')
}, 2000)

setTimeout(function () {
console.log('timeout 0')
alert('0000')
}, 0)

console.log('alert之前') // 最先输出,因为等所有主线程的任务执行完毕,再看异步任务,异步任务可以执行的情况下就丢去主线程执行了(先执行同步代码 ,再执行回调代码)

alert('提示...') // 暂停当前主线程的执行,(同时暂停了计时器,点击确定后恢复程序执行和计时),2021年,EDGE浏览器中定时器不再会被暂停计时了
console.log('alert之后')
</script>
</body>

46 事件循环模型

image-20211125152510842

image-20211125153553255

事件轮询:从任务队列中循环取出回调函数放入执行栈中处理(一个接一个)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<body>
<button id="btn">测试</button>
<!--
1. 所有代码分类
* 初始化执行代码(同步代码): 包含绑定dom事件监听, 设置定时器, 发送ajax请求的代码
* 回调执行代码(异步代码): 处理回调逻辑
2. js引擎执行代码的基本流程:
* 初始化代码===>回调代码
3. 模型的2个重要组成部分:
* 事件管理模块
* 回调队列
4. 模型的运转流程
* 执行初始化代码, 将事件回调函数交给对应模块管理
* 当事件发生时, 管理模块会将回调函数及其数据添加到回调列队中
* 只有当初始化代码执行完后(可能要一定时间), 才会遍历读取回调队列中的回调函数执行
-->
<script type="text/javascript">
function fn1() {
console.log('fn1()')
}
fn1()

document.getElementById('btn').onclick = function () {
console.log('处理点击事件')
}

setTimeout(function () {
console.log('到点了')
}, 2000)

function fn2() {
console.log('fn2()')
}
fn2()

</script>
</body>

47 Web Workers多线程

  • js是单线程的,但是浏览器是多线程的,js碰到异步任务,并没有自己处理,而是交给了浏览器的其他线程。

  • Web Workers 是 HTML5 提供的一个javascript多线程解决方案

  • 我们可以将一些大计算量的代码交由web Worker运行而不冻结用户界面

  • 但是子线程完全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质

  • 使用:

    • 创建在分线程执行的js文件
    • 在主线程中的js中发消息并设置回调
  • 缺点:

    • 不能跨域加载JS
    • worker内代码不能访问DOM(更新UI)
    • 不是每个浏览器都支持这个新特性
  • H5规范提供了js分线程的实现, 取名为: Web Workers

    相关API

    • Worker: 构造函数, 加载分线程执行的js文件

    • Worker.prototype.onmessage: 用于接收另一个线程的回调函数

    • Worker.prototype.postMessage: 向另一个线程发送消息

image-20211125160402286

work.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function fibonacci(n) {
return n <= 2 ? 1 : fibonacci(n - 1) + fibonacci(n - 2);
}

console.log(this);
var onmessage = function (event) {
var number = event.data;
console.log("分线程接受主线程发送的数据" + number);

//计算
var result = fibonacci(number);
postMessage(result);
console.log("分线程向主线程返回数据:" + result);
// alert(result)
/*
alert是window的方法,在分线程是不能调用的
分线程中的全局对象不再是window,所以分线程中不可能更新界面
*/
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<body>
<input type="text" placeholder="数值" id="number">
<button id="btn">计算</button>
<script>
var input = document.getElementById("number")
document.getElementById("btn").onclick = function () {
var number = input.value;
// 创建一个Worker对象
var worker = new Worker('work.js')
// 绑定接受消息的监听
worker.onmessage = function (event) {
console.log('主线程接收分线程返回的数据:' + event.data)
alert(event.data)
}

// 先分线程发送消息
worker.postMessage(number)
console.log('主线程向分线程发送数据:' + number)

}
</script>
</body>
image-20211125162250984 image-20211125162352638

补漏

原型链+this

1
2
3
4
5
6
7
8
9
10
11
12
13
function Person(name, age, gender){
this.name = name;
this.age = age;
this.gender = gender;
}
Person.prototype.getName = function(){
console.log("this" ,this instanceof Person)
return this.name;
}

let p = new Person("张加林", 20, "male");
p.getName();
console.log(p)

以方法的形式调用时,this就是调用方法的对象,所以通过this可以访问到实例对象身上的属性。