20:JavaScript详解 || 足够好的雕塑仍需要注入灵魂
JavaScript详解
一、什么是JavaScript
JavaScript:是一种弱类型脚本语言,其源代码不需要经过编译,是一门世界上最流行的脚本语言。和Java没有半毛钱关系。是一个大牛因为不喜欢Java,所以用了10天设计出来的。
一个合格的后端人员,必须要精通JavaScript,了解<熟悉<掌握<精通
ECMAScript可以理解为是JavaScript的一个标准,最新版本已经到es6版本,但是大部分浏览器还只停留在支持es5的版本。所以开发环境和线上环境是版本不一致的。
二、快速入门
1. 引入JavaScript
-
内部标签
<script> //注释跟java的一样 </script> -
外部引入
abc.js文件
alert("Hello,World!")test.html文件
<script src="abc.js"></script> -
测试代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <!--script标签内,写JavaScript代码,后面简称JS--> </head> <body> <!--放在body最底部最好,这是内部引入--> <!-- <script>--> <!-- alert("hello,world");--> <!-- </script>--> <!--外部引入,切记不要自闭合标签,成对闭合,不然容易出问题--> <script src="js/qj.js"></script> <!--不用显示定义type,默认就是JavaScript--> <script type="text/javascript"> </script> </body> </html>
2. 基本语法入门
-
浏览器必备调试须知(中英对照,F12一键打开审查元素):


-
element:元素审查,常用来查看html源代码或调颜色间距等等
-
Console:常用来打印一些数据的值,查看代码运行过程中值的变化
-
Sources:有代码存放的目录,可以打断点,用来一步步调试代码
-
Network:用来抓包等等
-
其他的后边用到再说
-
-
基本语法:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- 但是 JS 严格区分大小写-->
<script>
// 1. 定义变量 一切的变量都叫var
var name = "dearliu";
var age = 21;
// alert(name);
var score = 85;
"1234545";// 这都是一条完整的语句,离谱!
if (score > 90){
alert("优秀");
}else if (score > 60 && score <= 90){
alert("及格");
}else if (score < 60){
alert("不及格");
}
//console.log(score) 在浏览器的控制台打印变量! 相当于Java中的System.out.println();
</script>
</head>
<body>
</body>
</html>
3. 数据类型简述
数值、文本、图形、音频、视频...
变量
不能以数字开头,可以使用美元符 字母 下划线开头,中文也可以 但不建议
//不加var,不管是定义在函数内还是定义在函数外都 默认是全局变量
i = 1;
//加上var之后,定义在函数外就是全局变量,定义在函数内就是局部变量
var i = 1;
//局部变量 ES6之后 使用let声明局部变量 严格检查模式
let i = 1;
number:js不区分小数和整数,统一用Number
123//整数123
123.1//浮点数123.1
1.123e3//科学计数法
NaN //not a number
Infinity //表示无限大
字符串
‘abc’ “abc”
布尔值
true false
逻辑运算
&& 两个都为真,结果为真
|| 一个为真,结果为真
! 真变假,假变真
比较运算符
=
== 等于(类型不一样,值一样,也会判断为true)
=== 绝对等于(类型一样,值一样,结果为true) 坚持使用===
需要知道:
- NaN===NaN,返回值为false,NaN与所有的数值都不相等,包括自己
- 只能通过isNaN(NaN)来判断这个数是否是NaN
浮点数问题:
console.log((1/3) === (1-(2/3)));
尽量避免使用浮点数进行运算,存在精度
console.log(Math.abs(1/3 - (1-(2/3)) < 0.00000001));
null和undefined
- null 空
- undefined 未定义
数组
Java中数组必须是一系列相同类型的对象,js中不需要这样
var arr = [1,2,3,4,5,'hello',null,true]
new Array(1,12,3,4,5,'hello')
取数组下标:如果越界了,就会undefined
对象
对象是大括号,数组是中括号
每个属性之间使用逗号隔开,最后一个不需要添加逗号
//Person person = new Person(1,2,3,4,5);
var person = {
name:"liu",
age:3,
tags:['js','java','web','...']
};
取对象的值:

4. 严格检查模式
必须要保证IDEA支持ES6 语法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
//前提:IDEA需要设置支持ES6 语法
//'use strict' 严格检查模式,预防js的随意性导致产生的一些问题
//必须写在JavaScript的第一行,写在其他地方是没有用的
// 局部变量建立使用let去定义
'use strict';
//不加var,不管是定义在函数内还是定义在函数外都 默认是全局变量
i = 1;
//加上var之后,定义在函数外就是全局变量,定义在函数内就是局部变量
var i = 1;
//局部变量 ES6之后 使用let声明局部变量
let i = 1;
</script>
</head>
<body>
</body>
</html>
三、数据类型详细讲解
1. 字符串
-
正常字符串,我们使用单引号
''或者双引号""包裹 -
注意使用转义字符,比如要打印单引号或者双引号 ,转义字符必须在字符串包裹内
\' \n \t \u4e2d unicode字符 \u#### \x41 AscII字符 -
多行字符串编写
tab键上边的反引号``
var msg = `hello world nihao 你好 ` -
模板字符串
let name = "liu"; let age = 3; let msg = `你好呀,${name},${age}` -
字符串长度
var student = "this is a student"; student.length; student[0]; student[0] = 1; //赋值失败 String字符串是不可变的 student.toUpperCase() -
字符串的可变性 不可变
var student = "this is a student"; student[0]; student[0] = 1; //赋值失败 String字符串是不可变的 -
大小写转换
//这里是方法不是属性 student.toUpperCase() student.toLowerCase() -
获取指定字符的下标
student.indexOf('u') -
截取两个下标之间的字符串,含头不含尾
student.substring(1,3) //截取第一个字符串和第三个字符串之间的内容 不包含第三个 student.substring(0) //从第0个字符串截取到最后一个字符串
2. 数组
Array可以包含任意的数据类型
var arr = [1,3,4,5,6];
//通过下标取值和赋值
arr[0];
arr[0] = 1;
-
长度
arr.length注意:假如给arr.length 赋值,数组的大小就会发生变化,如果赋值过小,会导致后边的元素丢失,如果赋值大了,会在后边出现很多undefined元素。
-
indexOf
arr.indexOf(2) //获得2这个元素的下标字符串的“1” 和数字1返回值是不同的
-
slice() 截取Array的一部分,返回一个新数组,类似于String中的substring
arr.slice(3) //从下标为3的值截取到最后一个 arr.slice(2,5) //包头不包尾的截取下标为2到下标为5之间的值 -
push() , pop() 尾部操作
arr.push('a','b') //在最后面添加元素,压入到尾部 arr.pop() //从最后往外弹出元素 ,从尾部弹出 -
unshift() , shift() 头部操作
arr.unshift() //压入到头部 arr.shift() //弹出头部的一个元素 -
排序 sort()
arr.sort() //对数组中的元素进行排序 -
元素反转
arr.reverse() //将元素进行反转 第一个换到最后一个,最后一个换到第一个 以此类推 -
concat() 拼接
arr.concat() //返回一个新数组 原来的arr数组并没有发生修改,参数为一个数组 返回值为两个数组凭借的新数组 -
连接符 join
arr.join('-') // 使用小短线- 将arr数组中的值连接起来 -
多维数组
arr1 = [[1,2],[2,4],['d','v']]; arr1[1][1] //4 -
fill() 填充
-
find() 比如一个1-10的数组a,可以a.find(函数名),而这个函数式判断大于5的,会返回该数组中大于5的值
数组:存储数据(如何存,如何取,方法都可以自己实现!)
3. 对象
若干个键值对
var person = {
属性名:属性值,
属性名:属性值,
属性名:属性值
}
定义了一个person对象,有四个属性
var person = {
name:"liu",
age: 3,
email:"laxsilence@vip.qq.com",
score:99
}
js中的对象,使用{}包裹起来,键值对描述属性,多个属性之间使用逗号隔开,最后一个属性不加逗号!
js中的所有的键都是字符串,值是任意的对象!
person["age"] //会打印出来age的值
-
赋值
person.name = "dearLiu" -
使用一个不存在的对象属性,不会报错!undefined
person.haha //haha是不存在的属性 -
动态的删减属性,使用delete删除对象的属性
delete person.name -
动态的添加 直接给新的属性添加值就可以了
person.haha = "haha" -
判断属性值是否在这个对象中 xxx in xxx!
'age' in person //会打印出true 'toString' in person //会打印出true 继承 找到父类的方法 -
判断一个属性是否是对象自身拥有的 hasOwnProperty()
person.hasOwnProperty('toString') //false person.hasOwnProperty('age')//true
4. 流程控制
-
if 判断
'use strict'; var age = 3; if (age > 3){ alert("haha"); }else if(age < 5){ alert("kuwa"); }else{ alert("heihei"); } -
循环,避免程序死循环
var li = 5; while (li<100){ li = li + 1; console.log(li) } //死循环 while(true){ alert("就是关不掉!"); } //do while do{ age = age + 1; console.log(age); }while(age < 100) -
for循环
for (let i = 0; i < 100; i++) { console.log(i); } -
遍历数组forEach循环 ES 5.1
var arr = [12,23,3,54,65,67,67,123]; arr.forEach(function (value){ console.log(value); }) -
for ... in ...
for(var num in arr){//这里num是索引 console.log(num)//打印出索引,要打印值得话:age[num] } for(var num of arr){//这里num是值 console.log(num)//打印出值 }
5. Map 和 Set
ES6 的 新特性。
-
Map
'use strict'; //ES6 //学生的成绩,学生的名字 var names = ["tom","jack","haha"]; var scores = [100,90,80]; // ES6 Map集合 var map = new Map([['Tom',100],['Jack',90],['haha',80]]); var name = map.get('Tom');//通过key获得value map.set('admin',123456);//新增或修改 map.delete('Tom');//删除 console.log(name); -
Set,无序不重复
var set = new Set([3,1,1,1,1]);//set 可以去重 set.add(2);//添加 set.delete(1);//删除 console.log(set.has(3))//是否包含某个元素
6. Iterator 迭代器
对象的成员可以遍历,是因为该对象实现了Iterator 接口。
迭代器对象本质上,就是一个指针对象。通过指针对象的next(),用来移动指针。
【迭代器协议】对象必须提供一个next(),执行该方法要么返回迭代中的下一项,要么就引起一个Stopiteration异常,以终止迭代。
next()返回一个对象,表示当前数据成员的信息。这个对象具有value和done两个属性,value属性返回当前位置的成员,done属性是一个布尔值,表示遍历是否结束,即是否还有必要再一次调用next()。对于遍历器对象来说,done: false和value: undefined属性都是可以省略的。
ES6 规定,默认的 Iterator 接口部署在数据结构的Symbol.iterator属性上。
原生具备 Iterator 接口的数据结构如下。
- Array
- Map
- Set
- String
- TypedArray
- 函数的 arguments 对象
- NodeList 对象
-
遍历数组:
//通过for of实现,for in 是下标,还支持set和map 不光是数组 var array1 = [3,4,5]; for (var x of array1){ console.log(x); } -
遍历Map:
var map1 = new Map([['Tom',100],['Jack',90],['haha',80]]); for (let x of map1){ console.log(x); } -
遍历Set
var set = new Set([5,6,7]); for(let x of set){ console.log(x); }
四、函数
1. 定义函数
假设定义一个绝对值函数
定义方式1:
function abs(x){
if(x>=0){
return x;
}else{
return -x;
}
}
一旦执行到return,代表函数结束,返回结果!如果不传参数或者没有执行return,函数执行完也会返回结果,结果就是undefined或者NaN。
定义方式2:
var abs = function(x){
if(x>=0){
return x;
}else{
return -x;
}
}
这是一个匿名函数,但是可以把结果复制给abs,通过abs就可以调用函数!方式一和方式二等价。
还可以发现:方法也可以当做一个对象,即后面这个方法是名为abs的对象。
2. 调用函数
abs(10) //10
abs(-10) //10
参数问题:js可以传任意个参数,但是会看形式参数的个数,只写了一个就只执行一个实参,即第一个参数。js也可以不传递参数。
假设参数没有传递进去,要怎么解决不报错问题:
var abs = function(x){
if(typeof x != "number"){
throw "not a Number";
}
if(x>=0){
return x;
}else{
return -x;
}
}
手动判断参数是否是一个数字,如果不是就抛出异常。
假如存在多个参数,如何解决:
arguments是一个js自带的关键词,代表传递进来的所有参数,是一个数组。
var abs = function(x){
console.log("x=>" + x);
for(var i = 0;i < arguments.length;i++){
console.log(arguments[i]);
}
if(arguments.length > 1){
arguments[1];//可以拿到第二个参数
}
//或者
if(arguments.length == 2){
}else if (arguments.length == 3){
}
if(x>=0){
return x;
}else{
return -x;
}
}
但是仍然有一个问题:arguments包含所有传进来的参数,我们有时候想使用多余的,未被定义为形式参数的参数来进行附加操作,需要排除已有的参数。比如我是这个函数的调用者,我在调用的时候传递了6个参数进去,但是这个函数的开发者定义的形式参数有几个我是不知道的,所以我想用除了他定义的形式参数外的其他几个参数,但是这样的参数到底有几个是不确定的。
以前:
function aaa(a,b){
console.log("a=>" + a);
console.log("b=>" + b);
if(arguments.length > 2){
for (var i = 2;i<arguments.length;i++){
}
}
}
ES6 参数 rest
获取除了已经定义的参数之外的所有参数。
function aaa(a,b,...rest){
console.log("a=>" + a);
console.log("b=>" + b);
console.log(rest);
if(arguments.length > 2){
for (var i = 2;i<arguments.length;i++){
}
}
}
会发现这部分参数,全部被放到了rest这个数组中。需要将...rest写在参数的最后。
3. 变量的作用域
在js中,var定义的变量实际是由作用域的。假设在函数体中声明,则在函数体外不可以使用,那假设我非要在函数体外使用呢,需要用到(闭包),后续再说。
"use strict";
function qj(){
var x = 1;
x = x + 1;
}
x = x + 2;//js这个随意的语言第一次报错:Uncaught ReferenceError : x is not defined
-
如果两个函数使用了相同的变量名,只要在函数内部,就不冲突。
function qj(){ var x = 1; x = x +1; } function qj(){ var x = 'A'; x = x + 1; } -
内部函数可以访问外部函数的成员,反之则不行。
function qj(){ var x = 1; //内部函数可以访问外部函数的成员,反之则不行 function qj2(){ var y = x + 1; } var z = y + 1; //Uncaught ReferenceError : y is not defined } -
假设内部函数变量和外部函数变量重名:在js中,遵循就近原则,函数查找变量从自身函数开始,由内向外查找。里面找到了直接用,里面没找到就从外面找。
function qj(){ var x = 1; function qj2(){ var x = 'A'; console.log('inner' + x); //inner A } console.log('outer' + x); //outer 1 qj2(); } qj(); -
提升变量的作用域:
function qj(){ var x = "x" + y; console.log(x);//y undefined。 var y = 'y'; } //这段代码等价于下面这段 function qj2(){ var y; var x = 'x' + y; console.log(x);//所以说y是undefined y = 'y'; }运行结果:xundefined注意:这里代码是‘x’+y,所以是y is undefined,而不是x is undefined说明:js执行引擎,自动提升了y的声明,但是不会提升变量y的赋值!所以写js的时候有多少个变量直接全部写在最前面:
var x,y,z,...;//会把所有变量提到最前面写,只有var可以,在js建立之初就存在 -
全局变量:
var x = 1; function f(){ console.log(x); } f(); console.log(x); -
全局作用域 window
var x = 'xxx'; alert(x); window.alert(x);//等价于上边的 alert(window.x);//默认所有的全局变量,都会自动绑定在window对象下发现alert()这个函数本身也是一个window变量
var x = "xxx"; window.alert(x); var old_alert = window.alert; old_alert(x); //弹窗弹两次 window.alert = function(){ }; window.alert(123); //发现弹窗失效了,因为alert被重写了 //恢复 window.alert = old_alert; window.alert(123);js实际上只有一个全局作用域,都被绑定在window下,任何变量(函数也可以视为变量),假设没有在函数作用范围内找到,就会向外查找,最终查找到window下。如果在全局作用域都没有找到,就会报错
RefrenceError。由于我们所有的全局变量都会绑定在我们的window上,如果不同的js文件,使用了相同的全局变量,就会发生冲突。那么如何减少冲突。所以会写一个只属于自己的全局变量,凡是自己用到的,想当做全局变量的,都绑定在这个变量下面!
//唯一全局变量 var Laxsilence = { //定义一个全局变量 Laxsilence.name = "liu"; Laxsilence.add = function(a,b){ return a + b; } };即把自己的代码全部放入自己定义的唯一空间名字中,降低全局命名冲突的问题。jQuery就是这样干的,甚至他为了写jQuery更简单,直接让
jQuery.等价于$()。 -
局部作用域 let
function aaa(){ for(var i = 0;i<100;i++){ console.log(i); } console.log(i + 1);//i 出了作用域 还是可以实现 }ES6 let 关键字,解决局部作用域冲突问题,所以建议使用let
function aaa(){ for(let i = 0;i<100;i++){ console.log(i); } console.log(i + 1);//i 会显示 undefined } -
常量 const
在ES6 之前,怎么定义常量:只有用全部大写字母命名的变量就是常量;建议不要修改这样命名的变量,这就很扯淡。就是说常量的值可以改变。。。
所以在ES6引入了常量关键字
constconst PI = '3.14';//只读变量 console.log(PI); PI = '123';//会报错,不允许修改 TypeError:Assignment to constant variable
4. 方法
对象里面的函数就叫做方法。对象只有两个东西:属性和方法
var Laxsilence = {
//属性
name:'liu',
birth:'2001',
//方法
age:function(){
//今年 - 出生年份
var now = new Date().getFullYear();
return now - this.birth;
}
}
//调属性
Laxsilence.name;
//调方法 要带()
Laxsilence.age();
或者第二种写法:
function getAge(){
var now = new Date().getFullYear();
return now - this.birth;
}
var Laxsilence = {
name:'liu',
birth:2001,
age:getAge
}
//调用
Laxsilence.age();//正确
getAge();//NaN
可以知道this是指向当前调用该方法的对象,比如在Laxsilence.age()中,指向Laxsilence对象,而getAge()则默认是window对象,但是window对象没有birth属性。
在Java中this是无法指向的,是默认指向调用它的那个对象。
但在js中,apply可以控制this指向。可以理解为将这个方法应用到了某个对象上。
function getAge(){
var now = new Date().getFullYear();
return now - this.birth;
}
var Laxsilence = {
name:'liu',
birth:2001,
age:getAge
}
var Laxsilence = {
name:'xiaoming',
birth:2001,
age:getAge
}
//调用
Laxsilence.age();//正确
getAge();//NaN
getAge.apply(Laxsilence,[]);//代表this指向了这个对象,参数为空,可以实现!!!
getAge.apply(xiaoming,[]);
五、内部对象
标准对象,可以使用typeof 判断一个对象属于什么类型
typeof 123 //"number"
typeof '123' //"string"
typeof true //boolean
typeof [] //"object"
typeof {} //"object"
typeof NaN //"number"
typeof Math.abs //"function"
typeof undefined //"undefined"
...
1. Date
-
基本使用
var now = new Date();//Tue Mar 22 2022 20:33:54 GMT+0800 (中国标准时间) now.getFullYear();//年 now.getMonth();//月 0~11 代表月 now.getDate();//日 now.getDay();//星期几 now.getHours();//时 now.getMinutes();//分 now.getSeconds();//秒 now.getTime();//时间戳 全世界统一 1970.1.1 0:00:00 毫秒数 格林尼治时间的零点 北京时间的八点 647952955697 -
转换
注意:调用的是一个方法,记得加上括号
console.log(new Date(647952955697)) //时间戳转换为时间 now.toLocaleString();//转换为当地时间 now.toGMTString();
2.JSON(后续会讲)
json是什么?
早期,所有数据传输习惯都使用xml文件,但是xml的定义语法太过于繁琐,所以json出现了。
JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。
它基于 ECMAScript (欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。
易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。
在JS中一切皆为对象,任何js支持的类型都可以 用JSON来表示;
格式:
- 对象都用{}
- 数组都用[]
- 所有的键值对都是用key:value
var user = {
name:"liu",
age:13,
sex:"男"
}
//对象转换为json字符串 {"name":"liu","age":13,"sex":"男"}
var jsonUser = JSON.stringify(user);
console.log(jsonUser)
//json字符串转换为对象 参数为json字符串
var jsonUSerO = JSON.parse(jsonUser);
var jsonUSerO1 = JSON.parse('{"name":"liu","age":13,"sex":"男"}');
console.log(jsonUSerO);
console.log(jsonUSerO1);
JSON和js对象的区别:
var obj = {
a:"hello",
b:"hellob"
};
var json = '{"a":"hello","b":"hellob"}';
可以发现对象中的属性名是不需要双引号的,但是json中的键必须要用双引号括起来。
3. Ajax(后续会讲)
- 原生的js写法 xhr异步请求
- JQuery封装好的 方法 $(“#name”).ajex(“”)
- axios 请求
六、面向对象编程
1. 什么是面向对象
js、java、C# ... 面向对象;
面向对象:
- 类:模板
- 对象:具体的实例
js有一些区别,需要换个思路:
-
原型:
var user = { name:"liu", age:3, run:function(){ console.log(this.name + "run..."); } }; var xiaoming = { name:"xiaoming" //跑不起来 }; var bird = { fly:function(){ console.log(this.name + "fly...") } }; //小明的原型 是 user xiaoming.__proto__ = user; xiaoming.__proto__ = bird;
2. class继承
class关键字 是在ES6引入的
定义一个类,属性,方法
function Student(name){
this.name = name;
}
//给Student 新增一个方法
Student.prototype.hello = function(){
alert('hello')
}
//ES6之后
//定义一个学生的类
class Student{
constructor(name){
this.name = name;
}
hello(){
alert('hello')
}
}
var xiaoming = new Student("xiaoming");
xiaoming.hello();
var xiaohong = new Student("xiaohong");
xiaohong.hello();
//继承
class XiaoStudent extends Student{
constructor(name,grade){
super(name);
this.grade = grade;
}
myGrade(){
alert('我是一个小学生')
}
}
var xiaojun = new XiaoStudent("xiaojun","三")
本质:还是一个原型

原型链:
在js中,每个函数都有一个prototype属性,这个属性指向函数的原型对象。
_proto_:最终都会指向Object
简单的回顾一下构造函数、原型和实例的关系:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。那么假如我们让原型对象等于另一个类型的实例,结果会怎样?显然,此时的原型对象将包含一个指向另一个原型的指针,相应地,另一个原型中也包含着一个指向另一个构造函数的指针。假如另一个原型又是另一个类型的实例,那么上述关系依然成立。如此层层递进,就构成了实例与原型的链条。这就是所谓的原型链的基本概念。——摘自《javascript高级程序设计》

图中由相互关联的原型组成的链状结构就是原型链,也就是蓝色的这条线。
七、操作BOM对象(重点)
浏览器介绍:
js的诞生就是为了能够让他在浏览器中运行!
BOM:浏览器的对象模型
内核:
- IE 6~11
- Chrome,
- Safari
- FireFox (Linux)
三方(可以换内核):
- QQ浏览器
- 360浏览器
Window
window代表浏览器窗口
比如获取浏览器的高度跟宽度,可以更改浏览器的大小尝试

Navigator
Navigator,封装了浏览器的信息,大多数时候我们不会使用这个对象,因为会被人为修改,不建议使用这些属性来判断和编写代码,不能说通过这个代码判断出浏览器是window的就开始写代码,这个window可能是被人为修改的。
navigator.appName
navigator.appVersion
screen
代表屏幕尺寸
screen.width//1920px
screen.height//1080px
location(重点)
localtion 代表当前页面的URL信息
location
host:"www.baidu.com"
href:"https://www.baidu.com/"
protocol:"https"
reload:f reload() //刷新网页
//设置新的地址
localtion.assign("https://cnblogs.com/")

document(内容 ,在DOM中详细讲解)
document 代表当前的页面,HTML DOM 文档树
document.title //"百度一下,你就知道"
document.title="laxsilence" //"laxsilence"
获取具体的文档树节点
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<dl id="app">
<dt>Java</dt>
<dd>JavaSE</dd>
<dd>JavaEE</dd>
</dl>
<script>
let app = document.getElementById("app");
</script>
</body>
</html>
获取cookie
document.cookie
劫持cookie原理
www.taobao.com
<script src = "aa.js"></script>
<!-- 恶意人员,获取你的cookie上传到它的服务器,就知道了你的个人隐私信息 -->
服务器端可以设置cookie:httpOnly,保护我们的cookie不被劫持
history(不建议使用)
history代表浏览器的历史记录
history.back() //后退
history.forward() //前进
八、操作DOM对象(重点)
DOM:文档对象模型
使用js动态的操作节点。

1. 核心
浏览器网页就是一个DOM树形结构!
- 更新:更新Dom节点
- 遍历DOM节点:得到DOM节点
- 删除:删除一个DOM节点
- 添加:添加一个新的节点
2. 获得Dom节点
要操作一个DOM节点,就必须要先获得这个DOM节点
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="father">
<h1>标题一</h1>
<p id="p1">p1</p>
<p class="p2">p2</p>
</div>
<script>
let h1 = document.getElementsByTagName('h1');
let p1 = document.getElementById('p1');
let p2 = document.getElementsByClassName('p2');
var father = document.getElementById('father');
var children = father.children; //获取父节点下的所有子节点
var children = father.children[index]; //获取父节点下的指定子节点
</script>
</body>
</html>
这是原生代码,之后都是用jQuery();
3. 更新Dom节点
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="id1">
</div>
<script>
let id1 = document.getElementById('id1');
id1.innerText = '123'; //修改文本的值
id1.innerHTML = '<strong>123</strong>>' //可以解析HTML文本标签
id1.innerText = 'abc';
id1.style.color = 'red';
id1.style.fontSize = '50px';
id1.style.padding = '2em';
</script>
</body>
</html>
4. 删除DOM节点
删除节点的步骤:先获取父节点,再通过父节点删除自己
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="father">
<h1>标题一</h1>
<p id="p1">p1</p>
<p class="p2">p2</p>
</div>
<script>
//方式1
let self = document.getElementById('p1');
let father = self.parentElment;
father.removeChild(self);
//方式2
father.removeChile(father.children[0]);
//father.removeChile(father.children[1]);//会报错,删除是一个动态的过程,下标会一直变,当children[0]删除后,children[1]就会变成children[0],所以这样写是不对的
//father.removeChile(father.children[2]);
</script>
</body>
</html>
注意:删除多个节点的时候,一定要注意children是时刻在变化的
5. 插入节点
我们获得了某个DOM节点,假设这个DOM节点是空的,我们通过innerHTML就可以增加一个元素了,但是这个DOM节点已经存在元素了,我们就不能这么干了,因为会产生覆盖。
所以我们选择追加操作
-
追加已经存在的节点
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <p id="js">JavaScript</p> <div id="list"> <p id="se">JavaSE</p> <p id="ee">JavaEE</p> <p id="me">JavaME</p> </div> <script> let js = document.getElementById('js'); let list = document.getElementById('list'); list.appendChild(js); // </script> </body> </html>追加后的效果:

发现原来代码中的id为list的标签已经移动到div中了。
-
追加一个不存在的节点,即创建一个新的标签
//通过JS创建一个新节点 var newP = document.createElement('P');//创建一个P标签 newP.id = 'new P'; //或者 newP.setAttribute("id","new P") newP.innerText = "hello,world"; list.appendChild(newP);同样的,插入之后,代码会发生变化,会追加到div中。
创建一个标签节点
//通过这个属性可以设置任意的值 var myScript = document.createElement('script'); myScript.setAttribute('type',"text/javascript"); list.appendChild(myScript);var body = document.getElementsByTagName('body'); body[0].style.backgroundColor = "red";//通过标签或者类名获取到的是一个数组,需要选定,只有ID获得的不是数组,可以直接用 //或者 var myStyle = document.createElement('style');//创建一个空style标签 myStyle.setAttribute('type','text/css'); myStyle.innerHTML = "body{background-color:blue;}"//设置标签内容 document.getElementsByTagName('head')[0].appendChild(myStyle); -
插入到想插入的位置前面 insert
var ee = document.getElementById('ee'); var js = document.getElementById('js'); var list = document.getElementById('list'); //父节点.insertBefore(newNode,targetNode);在父节点下的目标节点前插入新节点,如果不指定的话,默认插入到最后面 list.insertBefore(js,ee)
九、操作表单(验证)
1. 表单是什么
form input 标签 也是DOM树中的节点
常见的表单:
- 文本框 text
- 下拉框 <select>
- 复选框 checkbox
- 单选框 redio
- 隐藏域 hidden
- 密码框 password
- ...
表单的目的:提交信息
2. 获得要提交的信息

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="#" method="post">
<p>
<span>用户名:</span><input type="text" id="username">
</p>
<!-- 多选框的值就是定义好的value值-->
<p>
<span>性别:</span>
<input type="radio" name="sex" value="man" id="boy">男
<input type="radio" name="sex" value="woman" id="girl">女
</p>
</form>
<script>
let input_text = document.getElementById("username");
let boy_radio = document.getElementById("boy");
let girl_radio = document.getElementById("girl");
//得到输入框的值
console.log(input_text.value);
//修改输入框的值
input_text.value = '123';
//对于单选框和多选框使用boy_radio.value只能取到当前的值
boy_radio.value;//返回 man
girl_radio.value;//返回 woman
//那么怎么拿到单选选择的值呢,使用checked方法 选中什么 什么为true
boy_radio.checked;//如果单选框选择的是男 那么该值为true
girl_radio.checked;//同上
//如果想直接用代码实现选中,怎么实现
boy_radio.checked = true; //这样选中的就是男 赋值操作
</script>
</body>
</html>
3. 提交表单及前端加密
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- MD5工具类-->
<script src="https://cdn.bootcss.com/blueimp-md5/2.10.0/js/md5.min.js"></script>
</head>
<body>
<!--
表单绑定提交事件
onsubmit= 绑定一个提交检测的函数 true false
将这个结果返回给表单,使用onsubmit接收
-->
<form action="https://www.baidu.com/" method="post" onsubmit="return aaa()">
<p>
<span>用户名:</span><input type="text" id="username" name="username">
</p>
<p>
<span>密码:</span><input type="password" id="password" name="password"> <!-- 普通的密码框 可以抓包获取到值 但是可以用md5加密 -->
</p>
<p>
<span>不走密码框密码:</span><input type="password" id="input-password"> <!-- 高级一点的方法,这个是用来输入密码的框,但不用来提交,所以不能加name属性(post提交,没有name属性的不会被提交) -->
</p>
<input type="hidden" id="md5-password" name="password2"> <!-- 这个才是真的密码框,但是是被隐藏的 -->
<!--绑定事件,被点击-->
<button type="submit" >提交</button><!-- onclick="aaa()"-->
</form>
<script>
function aaa(){
let username = document.getElementById('username');
let password = document.getElementById('password');
let inputPassword = document.getElementById('input-password');
let md5Password = document.getElementById('md5-password');
// console.log(username.value);
// console.log(password.value);
//MD5算法
// password.value = md5(password.value); //加密密码框中的值 ,但是会发现提交的一瞬间密码框中的值不再是输入的值,而是变成了加密后的一串东西,体验很差
// console.log(username.value);
// console.log(password.value);
md5Password.value = md5(inputPassword.value); //把用来输入的密码框中的值,用md5加密后传给真正的密码框,这样的话提交后,密码框中的值还是你输入的值
//false 表单提交不通过,return 表单提交通过 ,这里配合if-else 来决定返回true还是false,用来验证 表单填写是否合法
return true;
}
</script>
</body>
</html>
使用审查元素,network抓包

十、JQuery
js 和 JQuery : JQuery库,里面存在大量的JS函数。
JQuery工具站:https://jquery.cuishifeng.cn/
jQuery操作公式: $(selector).action()
1. 获取JQuery
可以前往JQUuery官网下载使用,也可以搜索JQuery CDN 加速链接引用。
但是建议下载导入,CDN引入不可靠
-
直接下载导入
-
在线CDN
<script src="https://lib.baomitu.com/jquery/3.6.0/jquery.js"></script>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- CDN引入-->
<!-- <script src="https://lib.baomitu.com/jquery/3.6.0/jquery.js"></script>-->
<!-- 下载导入-->
<script src="lib/jquery-3.6.0.js"></script>
</head>
<body>
<!--
jQuery操作公式: $(selector).action()
-->
<a href="" id="test-jquery">点我</a>
<script>
//selector选择器就是CSS的选择器
$('#test-jquery').click(function (){
alert('Hello,JQuery');
})
</script>
</body>
</html>
2. JQuery选择器
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
//原生js,选择器少,不好用
//标签
document.getElementsByTagName();
//id
document.getElementById();
//类
document.getElementsByClassName();
//jQuery
$('p').click();//标签选择器
$('#id1').click();//id选择器
$('.class1').click();//类选择器
//CSS中的选择器都可以使用
</script>
</body>
</html>
3. JQuery 事件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://lib.baomitu.com/jquery/3.6.0/jquery.js"></script>
<style>
#divMove{
width: 500px;
height: 500px;
border: 1px solid red;
}
</style>
</head>
<body>
<!--获取鼠标当前的坐标-->
mouse: <span id="mouseMove"></span>
<div id="divMove">
在这里移动鼠标试试
</div>
<script>
//当网页元素加载完毕之后,响应事件
// $(document).ready(function (){
//
// })
//简写:
$(function (){
$('#divMove').mousemove(function (e){
$('#mouseMove').text('x:'+e.pageX + 'y:'+e.pageY)
})
});
</script>
</body>
</html>


4. JQuery操作DOM元素
-
节点文本操作
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://lib.baomitu.com/jquery/3.6.0/jquery.js"></script> </head> <body> <ul id="test-ul"> <li class="js">JavaScript</li> <li name="python">Python</li> </ul> <script> $('#test-ul li[name = python]').text();//获得值 $('#test-ul li[name = python]').text('this is python');//设置值 $('#test-ul').html(); $('#test-ul').html('<strong>JavaScript</strong>'); </script> </body> </html> -
CSS的操作
$('#test-ul li[name = python]').css({"color":"red"}); -
元素的显示和隐藏(本质:display = none)
$('#test-ul li[name = python]').show() //元素显示 $('#test-ul li[name = python]').hide() //元素隐藏 -
娱乐测试
$(window).width(); $(window).height(); $(document).width(); ... -
未来 Ajax(); 重点
$('#form').ajax();
十一、前端的小技巧
- 如何巩固JS
- 看框架源码(JQuery)
- 看游戏源码!(前端游戏)
- 巩固HTML和CSS
- 扒网站,下载下来,对应修改查看效果
- 为自己的博客前端做准备

浙公网安备 33010602011771号