前言:
学习B站UP主狂神说视频笔记整理视频链接
文章参考廖雪峰的官方网站
简介
前端三要素:HTML(结构),CSS(展示),JavaScript(行为)
什么是JavaScript
JavaScript(简称“JS”)
是一种具有函数优先的轻量级,解释型或即时编译型的编程语言。虽然它是作为开发Web页面的脚本语言而出名,但是它也被用到了很多非浏览器环境中,JavaScript
基于原型编程、多范式的动态脚本语言,并且支持面向对象、命令式和声明式(如函数式编程)风格
JavaScript的标准是ECMAScript 。截至 2012 年,所有浏览器都完整的支持ECMAScript 5.1,旧版本的浏览器至少支持ECMAScript 3 标准。2015年6月17日,ECMA国际组织发布了ECMAScript的第六版,该版本正式名称为 ECMAScript 2015,但通常被称为ECMAScript 6 或者ES2015。
什么是ECMAScript
ECMAScript是一种由Ecma国际通过ECMA-262标准化的脚本程序设计语言。这种语言在万维网上应用广泛,它往往被称为JavaScript或JScript,所以它可以理解为是JavaScript的一个标准,但实际上后两者是ECMA-262标准的实现和扩展
最新版本已经到es6版本~
但是大部分浏览器还只停留在支持es5代码上!
开发环境—线上环境,版本不一致
快速入门
在HTML书写JS的方式(掌握)
方式一:<script>标签内写入JavaScript代码
<head>
...
<!--方式一:<script>标签内写入JavaScript代码-->
<script>
alert("helloJavaScript")
</script>
</head>
script标签可以放在head或body或页面的其他位置中,通常会放在head或body中
方式二:通过<script>标签引入外部的JS文件
<head>
...
<!--方式二:引入外部JS 注意不能使用自闭和标签-->
<script src="js/hello.js"></script>
</head>
下`
- 1.方式二引入不能使用自闭和标签,必须成对出现
- 2.如果script标签是用于引入JS文件的,就不要在该标签内部再书写JS代码,否则写了也不会执行!
控制台与严格检查模式
控制台
浏览器F12打开控制台
Debug断点调试
浏览器本地存储
严格检查模式
JavaScript是门非常随意的语言,为了防止它的随意性产生的问题,通过设置use strict检查代码
使用步骤:
1.IDEA中设置支持EC6语法
2.定义use strict
必须写在<script>第一行
<script>
"use strict"
let i=1;
</script>
语法入门
在JavaScript中严格区分大小写
注释格式
JS的注释符合和Java的注释符合相同,如下:
// 单行注释内容
/* 多行注释内容 */
数据类型
基本数据类型
JS的基本数据类型一共有五种,分别为数值类型(number)、字符串类型(string)、布尔类型(boolean)、undefined、null。
(1)数值-numbe
在JS中不区分整数和浮点数
| 说明 | 案例 |
|---|---|
| 整数 | 123 |
| 浮点数 | 123.1 |
| 科学计数法 | 1.123e3 |
| 负数 | -99 |
| NaN | not a number |
| Infinity | 无穷大 |
注意点:
尽量避免使用浮点数进行运算,存在精度问题
(2)字符串
1.JS中的字符串是基本数据类型,和Java中不同的是,JS中的字符串可以用单引号或双引号引起来。
<script>
var str1 = "Hello JS";
var str2 = 'Hello JS';
</script>
2.注意转译字符\
<script>
var str1 = "Hello\'";//输入引号
var str2 = 'Hello \n JS'; //换行
</script>
3.多行字符串编写,使用``符号包裹
<script>
var str1 = `1234567
22222222222211111`;//与Java不同的是 不用+号连接
</script>
注意:反引号在键盘的ESC下方,数字键1的左边:
4.模板字符串
<script>
var name= "秦疆";//定义模板
var hello="你好,${name}";//引入模板
</script>
5.字符串长度
与Java一样,字符串具有不变性
<script>
var name= "秦疆";
console.log(name.length);
</script>
6.截取字符串substring
<script>
var name= "HelloWord";
console.log(name.substring(1,3));
</script>
(3)布偶值
布尔类型常用条件测试中,值为true和false
(4)null和undefined
- null:空
- undefined:未定义
复杂数据类型
JS的复杂数据类型主要指对象 需要注意的是,在JS中,数组、函数也属于对象
数组
Array 对象用于在单个的变量中存储多个值,可以包含任意类型的数据
(1)通过Array构造函数创建数组
例如,声明一个空数组:
var arr1 = new Array();
例如,声明一个指定初始值的数组:
var arr2 = new Array(88,"Hello" ,true , 100);
(2)通过数组直接量创建数组
例如,声明一个空数组:
var arr1 = [];
例如,声明一个指定初始值的数组:
var arr2 = [88,"Hello" ,true , 100];
提示:
- 数组的length属性可以返回数组的长度
- 如果给
arr.length赋值,数组的长度就可以发生变化,数值较小元素就会丢失 - 与字符串不同的是,数组具有可变性,如
arr[0]=1; - 不同类型的元素是不一样的,如
"1" != 1 slice ()截取Array的一部分,返回一个新数组,类似于String中的substring- 使用
push()在尾部加入值,pop()从尾部删除值 - 使用
unshift()在头部加入值,shift()在头部移除值 sort()可以对当前Array进行排序
对象
若干个键值对,在JavaScript中所有键都是字符串,值是任意类型
<script>
/*格式*/
var user={
name: "秦疆",
age: 12,
sex: "男"
}
</script>
提示:
- 使用不存在的属性,不会报错
- 使用
delete 对象属性名动态删除属性 - 使用
hasOwnProperty()判断一个属性是否是这个对象自身拥有的
Map与Set
Map与Set是EC6的新特性
Map:KV键值对
<script>
"use strict"
//EC6新特性 Map Set
let map = new Map();
map.set("tom",123);//设置一个元素
console.log(map.get("tom"));//获取一个元素
map.delete("tom");//删除一个元素
</script>
Set:无序不重复集合
<script>
"use strict"
//EC6新特性 Map Set
let set = new Set();
set.add("1");//添加
set.add("2");
set.delete("2");//删除一个元素
console.log(set.has("2"));//是否包含某个元素
</script>
Lterable迭代
遍历数组
<script>
"use strict"
var arr=[3,4,5];
for (let x of arr){
console.log(x);
}
</script>
遍历Map
<script>
"use strict"
var map = new Map( [["tom", 100],[ "jack",90],[ "haha",80]]);
for (let x of map){
console.log(x);
}
</script>
遍历Set
<script>
"use strict"
let set = new Set([1,2,3]);
for (let x of set){
console.log(x);
}
</script>
变量声明
在JS中通过var声明变量
<script>
var a = 10; //声明变量,赋值为数值10
var b = true; //声明变量,赋值为布尔值true
var c = "Hello JS"; //声明变量,赋值为字符串"Hello JS"
</script>
在JS中声明的变量不区分类型,可以指向任意的数据类型
<script>
var x = 10; //声明变量,赋值为数值10
x = true; //将x赋值为布尔值true
x = "Hello JS"; 将x赋值为字符串"Hello JS"
</script>
在EC6中通过let声明局部变量更加安全
<script>
let a= 10; //let声明变量
</script>
JS运算符
JS和Java中的运算符大致相同
算术运算符: +,-,*,/,%,++,--
赋值运算符: =,+=,-=,*=,/=,%=
比较运算符: ==,!=,>,>=,<,<=
位运算符: & , |
逻辑运算符: && ,||
前置逻辑运算符: ! (not)
三元运算符: 表达式 ? 表达式 : 表达式
...
比较运算符(重要)
= 赋值
== 类型不一样 值一样 也会判断为true 1="1"
=== 类型一样 值一样才会判断为true
注意点:
- 这是js的缺陷 坚持使用
===比较 NaN===NaNcy与任何值比较都不相等 包括自己
流程控制
if分支结构
if分支结构用于基于不同的条件来执行不同的动作。语法结构如下:
if (条件 1){
当条件 1 为 true 时执行的代码
}else if (条件 2){
当条件 2 为 true 时执行的代码
}else{
当条件 1 和 条件 2 都不为 true 时执行的代码
}
switch语句
使用 switch 语句来选择要执行的多个代码块之一。语法结构如下:
switch(n){
case 1:
执行代码块 1
break;
case 2:
执行代码块 2
break;
default:
与 case 1 和 case 2 不同时执行的代码
}
执行原理:首先设置表达式 n(通常是一个变量)。随后表达式的值会与结构中的每个 case 的值做比较。如果存在匹配,则与该 case 关联的代码块会被执行。请使用 break 来阻止代码自动地向下一个 case 运行。
for循环语句
for 循环的语法结构如下:
for (语句 1; 语句 2; 语句 3){
//被执行的代码块
}
while循环
JS中while循环也分为while和do/while循环,下面为while循环语法结构
while (条件){
//需要执行的代码
}
while 循环会在指定条件为真时循环执行代码块。
函数
定义函数
在JavaScript中,定义函数的方式如下:
function abs(x) {
if (x >= 0) {
return x;
} else {
return -x;
}
}
上述abs()函数的定义如下:
function指出这是一个函数定义;abs是函数的名称;(x)括号内列出函数的参数,多个参数以,分隔;{ ... }之间的代码是函数体,可以包含若干语句,甚至可以没有任何语句。
请注意,函数体内部的语句在执行时,一旦执行到return时,函数就执行完毕,并将结果返回。因此,函数内部通过条件判断和循环可以实现非常复杂的逻辑。
如果没有return语句,函数执行完毕后也会返回结果,只是结果为undefined。
由于JavaScript的函数也是一个对象,上述定义的abs()函数实际上是一个函数对象,而函数名abs可以视为指向该函数的变量。
因此,第二种定义函数的方式如下:
var abs = function (x) {
if (x >= 0) {
return x;
} else {
return -x;
}
};
在这种方式下,function (x) { ... }是一个匿名函数,它没有函数名。但是,这个匿名函数赋值给了变量abs,所以,通过变量abs就可以调用该函数。
上述两种定义完全等价,注意第二种方式按照完整语法需要在函数体末尾加一个;,表示赋值语句结束。
调用函数
调用函数时,按顺序传入参数即可:
abs(10); // 返回10
abs(-9); // 返回9
JS中允许传任意个参数,也可以不传递参数
abs(10, 'blablabla'); // 返回10
abs(-9, 'haha', 'hehe', null); // 返回9
abs(); // 返回NaN
参数进来是否存在问题?
假设不存在参数,如何进行规避?
function abs(x) {
//手动抛出异常来判断
if (typeof x !== 'number') {
throw 'Not a number';
}
if (x >= 0) {
return x;
} else {
return -x;
}
}
typeof
判断参数的类型
格式:
typeof x(参数)
arguments
JavaScript还有一个免费赠送的关键字arguments,它只在函数内部起作用,并且永远指向当前函数的调用者传入的所有参数。arguments类似Array但它不是一个Array:
function foo(x) {
console.log('x = ' + x); // 10
for (var i=0; i<arguments.length; i++) {
console.log('arg ' + i + ' = ' + arguments[i]); // 10, 20, 30
}
}
foo(10, 20, 30);
arguments包含所有的参数,有时我们只想使用多余的参数来进行附加操作,需要排除已有参数
rest
ES6的新特性,获取除了已经定义的参数之外的参数
function aaa(a,b,...rest) {
console.log("a=>"+a);
console.log("b=>"+b);
console.log(rest);
}
rest参数只能写在最后面,并且格式为...rest
变量作用域
在JavaScript中,用var申明的变量实际上是有作用域的。
如果一个变量在函数体内部申明,则该变量的作用域为整个函数体,在函数体外不可引用该变量:
'use strict';
function foo() {
var x = 1;
x = x + 1;
}
x = x + 2; // ReferenceError! 无法在函数体外引用变量x
ps:非要想实现的话,可以研究一下闭包
如果两个不同的函数各自申明了同一个变量,那么该变量只在各自的函数体内起作用。换句话说,不同函数内部的同名变量互相独立,互不影响:
'use strict';
function foo() {
var x = 1;
x = x + 1;
}
function bar() {
var x = 'A';
x = x + 'B';
}
由于JavaScript的函数可以嵌套,此时,内部函数可以访问外部函数定义的变量,反过来则不行:
'use strict';
function foo() {
var x = 1;
function bar() {
var y = x + 1; // bar可以访问foo的变量x!
}
var z = y + 1; // ReferenceError! foo不可以访问bar的变量y!
}
如果内部函数和外部函数的变量名重名怎么办?
function foo() {
var x = 1;
function bar() {
var x = 'A';
console.log('x in bar() = ' + x); // 'A'
}
console.log('x in foo() = ' + x); // 1
bar();
}
foo();
这说明JavaScript的函数在查找变量时从自身函数定义开始,从“内”向“外”查找。如果内部函数定义了与外部函数重名的变量,则内部函数的变量将“屏蔽”外部函数的变量。
变量提升
JavaScript的函数定义有个特点,它会先扫描整个函数体的语句,把所有申明的变量“提升”到函数顶部:
'use strict';
function foo() {
var x = 'Hello, ' + y;
console.log(x);
var y = 'Bob';
}
foo();
运行结果会发现:y=undefined
这正是因为JavaScript引擎自动提升了变量y的声明,但不会提升变量y的赋值。
对于上述foo()函数,JavaScript引擎看到的代码相当于:
function foo() {
var y; // 提升变量y的申明,此时y为undefined
var x = 'Hello, ' + y;
console.log(x);
y = 'Bob';
}
由于JavaScript的这一怪异的“特性”,我们在函数内部定义变量时,请严格遵守“在函数内部首先申明所有变量”这一规则。最常见的做法是用一个var申明函数内部用到的所有变量:
function foo() {
var
x = 1, // x初始化为1
y = x + 1, // y初始化为2
z, i; // z和i为undefined
// 其他语句:
for (i=0; i<100; i++) {
...
}
}
全局变量
不在任何函数内定义的变量就具有全局作用域。实际上,JavaScript默认有一个全局对象window,全局作用域的变量实际上被绑定到window的一个属性:
"use strict"
//全局变量
var x ="helloWord";
function foo() {
alert(x);
alert(window.x);//默认所有全局变量都会绑定到window对象上
}
alert()这个函数本身也是一个window变量
"use strict"
//全局变量
var old =window.alert;
old(123);
window.alert=function () {
}
window.alert(345);//失效
window.alert=old;//恢复
window.alert(678);
你可能猜到了,由于函数定义有两种方式,以变量方式var foo = function () {}定义的函数实际上也是一个全局变量,因此,顶层函数的定义也被视为一个全局变量,并绑定到window对象:
'use strict';
function foo() {
alert('foo');
}
foo(); // 直接调用foo()
window.foo(); // 通过window.foo()调用
Javascript 实际上只有一个全局作用域,任何变量(函数也可以视为变量),假设没有在函数作用范围内找到,就会向外查找,如果在全局作用域都没有找到,报错RefrenceError
规范
由于我们所有的全局变量都会绑定到我们的 window 上,如果不同的js 文件,使用了相同的全局变量,就会引发冲突~>如果能够减少冲突?
"use strict"
//唯一全局变量 不绑定到window上
var listapp={};
//定义全局变量
listapp.name="王根基";
//定义函数
listapp.app=function (x) {
}
把自己的代码全部放入自己定义的唯一空问名字中,降低全局命名冲突的问题–
局部变量
由于JavaScript的变量作用域实际上是函数内部,我们在for循环等语句块中是无法定义具有局部作用域的变量的:
'use strict';
function foo() {
for (var i=0; i<100; i++) {
//
}
i += 100; // 仍然可以引用变量i
}
为了解决块级作用域,ES6引入了新的关键字let,用let替代var可以申明一个块级作用域的变量:
'use strict';
function foo() {
var sum = 0;
for (let i=0; i<100; i++) {
sum += i;
}
// SyntaxError:
i += 1;
}
常量
由于var和let申明的是变量,如果要申明一个常量,在ES6之前是不行的,我们通常用全部大写的变量来表示“这是一个常量,不要修改它的值”:
var PI = 3.14;
ES6标准引入了新的关键字const来定义常量,const与let都具有块级作用域:
'use strict';
const PI = 3.14;
PI = 3; // 某些浏览器不报错,但是无效果!
PI; // 3.14
方法
在一个对象中绑定函数,称为这个对象的方法
在JavaScript中,对象的定义是这样的:
var xiaoming = {
name: '小明',
birth: 1990
};
但是,如果我们给xiaoming绑定一个函数,就可以做更多的事情。比如,写个age()方法,返回xiaoming的年龄:
var xiaoming = {
name: '小明',
birth: 1990,
age: function () {
var y = new Date().getFullYear();
return y - this.birth;
}
};
xiaoming.name; // 调用属性
xiaoming.age(); // 调用方法必须得带括号
它在内部使用了一个this关键字,这个东东是什么?
一个方法内部,this是一个特殊变量,它始终指向当前对象,也就是xiaoming这个变量。
让我们拆开写:
function getAge() {
var y = new Date().getFullYear();
return y - this.birth;
}
var xiaoming = {
name: '小明',
birth: 1990,
age: getAge
};
xiaoming.age(); // 25, 正常结果
getAge(); // NaN
单独调用函数getAge()怎么返回了NaN?请注意,我们已经进入到了JavaScript的一个大坑里。
JavaScript的函数内部如果调用了this,那么这个this到底指向谁?
答案是,视情况而定!
如果以对象的方法形式调用,比如xiaoming.age(),该函数的this指向被调用的对象,也就是xiaoming,这是符合我们预期的。
如果单独调用函数,比如getAge(),此时,该函数的this指向全局对象,也就是window。
apply
在js中可以控制this的指向
function getAge() {
var y = new Date().getFullYear();
return y - this.birth;
}
var xiaoming = {
name: '小明',
birth: 1990,
age: getAge
};
xiaoming.age(); // 25
getAge.apply(xiaoming, []); // 25, this指向xiaoming, 参数为空
内部函数
Data
时间函数
基本使用:
"use strict"
let dat = new Date();
dat.getFullYear();//年份
dat.getMonth();//月份 0-11 代表月
dat.getDate();//日期
dat.getDay();//星期几
dat.getHours();//时
dat.getMinutes()//分
dat.getSeconds();//秒
dat.getTime();//时间戳 全世界统一 1970
转换:

注意点:调用的是一个方法不是一个属性
JSON
JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式,目前使用特别广泛。
在JavaScript一切皆为对象、任何js支持的类型都可以用JSON来表示;number,string…
格式:
- 对象都用{}
- 数组都用[]
- 所有的键值对都是 key:value
javascript中使用JSON
//编写一个javascript 对象
var user= {
name: "秦疆",
age: 3,
sex: "男"
}
//将js对象转换成JSON
var jsonuser = JSON.stringify(user);
//将JSON字符串转换成JS对象
var parse = JSON.parse(jsonuser);
console.log(parse);
面向对象
什么是面向对象
JavaScript的面向对象编程和大多数其他语言如Java、C#的面向对象编程都不太一样。如果你熟悉Java或C#,很好,你一定明白面向对象的两个基本概念:
类:类是对象的类型模板,例如,定义
Student类来表示学生,类本身是一种类型,Student表示学生类型,但不表示任何具体的某个学生;实例:实例是根据类创建的对象,例如,根据
Student类可以创建出xiaoming、xiaohong、xiaojun等多个实例,每个实例表示一个具体的学生,他们全都属于Student类型。
所以,类和实例是大多数面向对象编程语言的基本概念。
不过,在JavaScript中,这个概念需要改一改。JavaScript不区分类和实例的概念,而是通过原型(prototype)来实现面向对象编程。
原型继承(不推荐使用)
原型是指当我们想要创建xiaoming这个具体的学生时,我们并没有一个Student类型可用。那怎么办?恰好有这么一个现成的对象:
var robot = {
name: 'Robot',
height: 1.6,
run: function () {
console.log(this.name + ' is running...');
}
};
我们看这个robot对象有名字,有身高,还会跑,有点像小明,干脆就根据它来“创建”小明得了!
于是我们把它改名为Student,然后创建出xiaoming:
var Student = {
name: 'Robot',
height: 1.2,
run: function () {
console.log(this.name + ' is running...');
}
};
var xiaoming = {
name: '小明'
};
//原型 小明指向Student
xiaoming.__proto__ = Student;
注意最后一行代码把xiaoming的原型指向了对象Student,看上去xiaoming仿佛是从Student继承下来的:
xiaoming.name; // '小明'
xiaoming.run(); // 小明 is running...
xiaoming有自己的name属性,但并没有定义run()方法。不过,由于小明是从Student继承而来,只要Student有run()方法,xiaoming也可以调用:
JavaScript的原型链和Java的Class区别就在,它没有“Class”的概念,所有对象都是实例,所谓继承关系不过是把一个对象的原型指向另一个对象而已。
什么是原型链?
在JavaScript中,每个函数都有一个prototype属性,这个属性指向函数的原型对象。
当我们用obj.xxx访问一个对象的属性时,JavaScript引擎先在当前对象上查找该属性,如果没有找到,就到其原型对象上找,如果还没有找到,就一直上溯到Object.prototype对象,最后,如果还没有找到,就只能返回undefined。
举个栗子~!
建一个Array对象:
var arr = [1, 2, 3];
其原型链是:
arr ----> Array.prototype ----> Object.prototype ----> null
Array.prototype定义了indexOf()、shift()等方法,因此你可以在所有的Array对象上直接调用这些方法。
当我们创建一个函数时:
function foo() {
return 0;
}
函数也是一个对象,它的原型链是:
foo ----> Function.prototype ----> Object.prototype ----> null
由于Function.prototype定义了apply()等方法,因此,所有函数都可以调用apply()方法。
很容易想到,如果原型链很长,那么访问一个对象的属性就会因为花更多的时间查找而变得更慢,因此要注意不要把原型链搞得太长。
Class继承(推荐使用)
在上面的章节中我们看到了JavaScript的对象模型是基于原型实现的,特点是简单,缺点是理解起来比传统的类-实例模型要困难,最大的缺点是继承的实现需要编写大量代码,并且需要正确实现原型链。
新的关键字class从ES6开始正式被引入到JavaScript中。class的目的就是让定义类更简单。
定义
用新的class关键字来编写Student,可以这样写:
class Student {
//构造器
constructor(name) {
this.name = name;
}
hello() {
alert('Hello, ' + this.name + '!');
}
}
//使用
let student = new Student("王根基");
student.hello();
继承
用class定义对象的另一个巨大的好处是继承更方便了。现在,原型继承的中间对象,原型对象的构造函数等等都不需要考虑了,直接通过extends来实现:
class xiaomin extends Student{
constructor(name,age){
//必须调用父类的构造器 否则会报错
super(name);
this.age=age;
}
helloword(){
alert("name:"+this.name+"age:"+this.age);
}
}
BOM对象
BOM:浏览器对象模型
JavaScript和浏览器关系?
JavaScript 诞生就是为了能够让他在浏览器中运行!
window-浏览器窗口
window对象不但充当全局作用域,而且表示浏览器窗口。
window对象有innerWidth和innerHeight属性,可以获取浏览器窗口的内部宽度和高度。内部宽高是指除去菜单栏、工具栏、边框等占位元素后,用于显示网页的净宽高。
兼容性:IE<=8不支持。
window.innerHeight
//210 内部宽度
window.innerWidth
//1280 内部高度
window.outerWidth
//1280
window.outerHeight
//690
还有一个outerWidth和outerHeight属性,可以获取浏览器窗口的整个宽高。
navigator-浏览器信息
navigator对象表示浏览器的信息,最常用的属性包括:
- navigator.appName:浏览器名称;
- navigator.appVersion:浏览器版本;
- navigator.language:浏览器设置的语言;
- navigator.platform:操作系统类型;
- navigator.userAgent:浏览器设定的User-Agent字符串。

大多数时候,我们不会使用navigator对象,因为会被人为修改!
不建议使用这些属性来判断和修改代码
screen-屏幕信息
screen对象表示屏幕的信息,常用的属性有:
- screen.width:屏幕宽度,以像素为单位;
- screen.height:屏幕高度,以像素为单位;
- screen.colorDepth:返回颜色位数,如8、16、24。
screen.width
// 1280
screen.height
// 720
screen.colorDepth
// 24
location-URL信息
location对象表示当前页面的URL信息。
要加载一个新页面,可以调用location.assign()。如果要刷新当前页面,调用location.reload()方法非常方便。
location.reload();//刷新页面
location.assign('https://www.bilibili.com/video/BV1JJ41177di?p=19');//加载新页面
document-文档树
document对象表示当前页面。由于HTML在浏览器中以DOM形式表示为树形结构,document对象就是整个DOM树的根节点。
获取具体的文档树根节点
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>HelloScript</title>
</head>
<body>
<dl id="app">
<dt>Java</dt>
<dd>JavaEE</dd>
<dd>JavaSE</dd>
</dl>
<script>
var dl= document.getElementById('app');
</script>
</body>
</html>
JavaScript可以通过document.cookie读取到当前页面的Cookie:
document.cookie; // 'v=123; remember=true; prefer=zh'
由于JavaScript能读取到页面的Cookie,而用户的登录信息通常也存在Cookie中,这就造成了巨大的安全隐患,这是因为在HTML页面中引入第三方的JavaScript代码是允许的
Cookie安全性问题
为了解决这个问题,服务器在设置Cookie时可以使用httpOnly,设定了httpOnly的Cookie将不能被JavaScript读取。这个行为由浏览器实现,主流浏览器均支持httpOnly选项,IE从IE6 SP1开始支持。
为了确保安全,服务器端在设置Cookie时,应该始终坚持使用httpOnly。
history-浏览器历史记录(不推荐使用)
history对象保存了浏览器的历史记录,JavaScript可以调用history对象的back()或forward (),相当于用户点击了浏览器的“后退”或“前进”按钮。
history.back();//后退
history.forword();//前进
DOM对象
DOM:文档对象模型
核心
由于HTML文档被浏览器解析后就是一棵DOM树,要改变HTML的结构,就需要通过JavaScript来操作DOM。
始终记住DOM是一个树形结构。操作一个DOM节点实际上就是这么几个操作:
更新:更新该DOM节点的内容,相当于更新了该DOM节点表示的HTML的内容;
遍历:遍历该DOM节点下的子节点,以便进行进一步操作;
添加:在该DOM节点下新增一个子节点,相当于动态增加了一个HTML节点;
删除:将该节点从HTML中删除,相当于删掉了该DOM节点的内容以及它包含的所有子节点。
在操作一个DOM节点前,我们需要通过各种方式先拿到这个DOM节点。
最常用的方法是document.getElementById()和document.getElementsByTagName(),以及CSS选择器document.getElementsByClassName()。
获取DOM节点
//标签选择器
let h1 = document.getElementsByTagName("h1");
//id选择器
let p1 = document.getElementById("p1");
//class选择器
let p2 = document.getElementsByClassName("p2");
let fals = document.getElementById("fals");
let children = fals.children;//获取父节点下的所有子节点
// fals.firstChild;获取第一个节点
// fals.lastChild; 获取最后一个节点
这是原生代码,以后都会使用Jquery
更新节点
<body>
<div id="fals">
</div>
<script>
let fals = document.getElementById("fals");
//修改文本的值
fals.innerText="123";
//修改超文本
fals.innerHTML="<a href=\"www.baidu.com\">123</a>";
//操作CSS
fals.style.color="steelblue";
fals.style.fontSize="200px";//注意驼峰命名
</script>
</body>
注意点:属性使用字符串包裹
删除节点
要删除一个节点,首先要获得该节点本身以及它的父节点,然后,调用父节点的removeChild把自己删掉:
//拿到待删除节点
let dl123 = document.getElementById("dl123");
//拿到父节点
let parent = dl123.parentElement;
//删除
let delt = parent.removeChild(dl123);
注意到删除后的节点虽然不在文档树中了,但其实它还在内存中,可以随时再次被添加到别的位置。
使用children可以获取到父节点下所有子节点,它是一个数组可以通过下标获取节点fals.children[1]
当我们用如下代码删除子节点时:
var parent = document.getElementById('parent');
parent.removeChild(parent.children[0]);
parent.removeChild(parent.children[1]); // <-- 浏览器报错
浏览器报错:parent.children[1]不是一个有效的节点。原因就在于,当<p>First</p>节点被删除后,parent.children的节点数量已经从2变为了1,索引[1]已经不存在了。
插入节点
当我们获得了某个DOM节点,想在这个DOM节点内插入新的DOM,应该如何做?
如果这个DOM节点是空的,例如,<div></div>,那么,直接使用innerHTML = '<span>child</span>'就可以修改DOM节点的内容,相当于“插入”了新的DOM节点。
如果这个DOM节点不是空的,那就不能这么做,因为innerHTML会直接替换掉原来的所有子节点。
有两个办法可以插入新的节点。
使用appendChild,把一个已有的子节点添加到父节点的最后一个子节点
<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");
// 追加到div最后面
list.appendChild(js);
</script>
</body>

更多的时候我们会从零创建一个新的节点,然后插入到指定位置:
//创建方式一:
let newp = document.createElement("p");
newp.id="newp";
newp.innerText="helloword";
//插入到div最后面
list.appendChild(newp);
//创建方式二
let myscript = document.createElement("script");
//万能设置值的方式setAttribute
myscript.setAttribute("type","text/javascript");
//插入到div最后面
list.appendChild(myscript);

还可以插入CSS样式
//创建style标签
let mystyle = document.createElement("style");
//设置CSS样式
mystyle.setAttribute("type","text/css");
mystyle.innerText="body{\n" +
" background: steelblue;\n" +
" }";
//获取head标签
let myhead = document.getElementsByTagName("head")[0];
//插入到子后面
myhead.appendChild(mystyle);
注意:获取<head>标签时,它在第0个位置
insertBefore
如果我们要把子节点插入到指定的位置怎么办?
可以使用parentElement.insertBefore(插入节点, 在哪个节点前插入);
//获取div节点
let list = document.getElementById("list");
let ee = document.getElementById("ee");
let js = document.getElementById("js");
list.insertBefore(js,ee);

操作表单
用JavaScript操作表单和操作DOM是类似的,因为表单本身也是DOM树。
不过表单的输入框、下拉框等可以接收用户输入,所以用JavaScript来操作表单,可以获得用户输入的内容,或者对一个输入框设置新的内容。
HTML表单的输入控件主要有以下几种:
文本框,对应的
<input type="text">,用于输入文本;口令框,对应的
<input type="password">,用于输入口令;单选框,对应的
<input type="radio">,用于选择一项;复选框,对应的
<input type="checkbox">,用于选择多项;下拉框,对应的
<select>,用于选择一项;隐藏文本,对应的
<input type="hidden">, 用户不可见,但表单提交时会把隐藏文本发送到服务器。
获取值
如果我们获得了一个<input>节点的引用,就可以直接调用value获得对应的用户输入值:
// <input type="text" id="email">
var input = document.getElementById('email');
input.value; // '用户输入的值'
这种方式可以应用于text、password、hidden以及select。
对于单选框和复选框,value属性返回的永远是HTML预设的值,而我们需要获得的实际是用户是否“勾上了”选项,所以应该用checked判断:
// <label><input type="radio" name="weekday" id="monday" value="1"> Monday</label>
// <label><input type="radio" name="weekday" id="tuesday" value="2"> Tuesday</label>
var mon = document.getElementById('monday');
var tue = document.getElementById('tuesday');
mon.value; // '1'
tue.value; // '2'
mon.checked; // true或者false
tue.checked; // true或者false
设置值
设置值和获取值类似,对于text、password、hidden以及select,直接设置value就可以:
// <input type="text" id="email">
var input = document.getElementById('email');
input.value = 'test@example.com'; // 文本框的内容已更新
对于单选框和复选框,设置checked为true或false即可。
提交表单
提交表单时 MD5对密码加密
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>HelloScript</title>
<!--md5工具类-->
<script src="https://cdn.bootcss.com/blueimp-md5/2.10.0/js/md5.min.js"></script>
</head>
<body>
<!--表单级别的提交时间:
onsubmit
-->
<div id="div123">
<form action="#" method="post" onsubmit="return dist()">
<p>
<span>用户名:</span><input type="text" name="username" id="name1">
</p>
<p>
<span>密码:</span><input type="password" id="pwd">
</p>
<!--隐藏域 隐藏真实密码-->
<input type="hidden" name="md5-password" id="password">
<input type="submit" value="提交">
</form>
</div>
<script>
function dist() {
let username = document.getElementById("name1").value;
let pwd = document.getElementById("pwd").value;//获取输入密码
let password = document.getElementById("password");//获取隐藏域
password.value =md5(pwd);//MD5加密
alert(password.value);
//可以校验表单内容 true就是通过提交 false就是阻止提交
return false;
}
</script>
</body>
</html>
JQuery
JavaScript世界中使用最广泛的一个库。
使用jQuery
使用jQuery只需要在页面的引入jQuery文件即可:
<html>
<head>
//本地
<script src="//code.jquery.com/jquery-1.11.3.min.js"></script>
//CDN
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
...
</head>
<body>
...
</body>
</html>
$符号
$ 是著名的jQuery符号。实际上,jQuery把所有功能全部封装在一个全局变量jQuery中,而$也是一个合法的变量名,它是变量jQuery的别名
window.jQuery; // jQuery(selector, context)
window.$; // jQuery(selector, context)
$ === jQuery; // true
typeof($); // 'function'
快速上手
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>HelloScript</title>
<!--Jqury CDN-->
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
</head>
<body>
<!--
jquery公式: $("#test-jqury").click();
-->
<a href="" id="test-jqury">点击</a>
<script>
//点击事件
$("#test-jqury").click(function () {
alert("helloJqury")
})
</script>
</body>
</html>
JQuery选择器
首先请看原生JS选择器
//id选择器
document.getElementById();
//类
document.getElementsByClassName();
//标签选择器
document.getElementsByTagName();
原生JS代码中,选择器复杂且类型较少
在Jquery中 CSS代码的选择器 它全部都能用
//jQuery css 中的选择器它全部都能用!
$('p' ).click();//标签选择器
$( '#id1' ).click(); //id选择器
$( '.class1 ' ).click() //cLass选择器
事件
因为JavaScript在浏览器中以单线程模式运行,页面加载后,一旦页面上所有的JavaScript代码被执行完后,就只能依赖触发事件来执行JavaScript代码。
浏览器在接收到用户的鼠标或键盘输入后,会自动在对应的DOM节点上触发相应的事件。如果该节点已经绑定了对应的JavaScript处理函数,该函数就会自动调用。
Jquery常用事件如下:
//当网页元素加载完毕之后 响应事件
$(function () {
//获取鼠标移动事件
$("#mouseMove").mousemove(function (e) {
$("#mouseMove").text("x"+e.pageX+"Y:"+e.pageY);
})
});
操作DOM
/*节点文本操作*/
$(function () {
//操作文本
$("#text-u1 li[class=js]").text();//获取值
$("#text-u1 li[class=js]").text("JavaSE");//设置值
//操作html
$("#text-u1 li[name=python]").html();//获取html
$("#text-u1 li[name=python]").html("<li name='js'>mmm</li>");//设置值
});