JavaScript学习笔记
一、JavaScript是什么?
1、HTML是网页的结构,CSS是网页的外观,而JavaScript是页面的行为。
2、HTML页面是静态的,平常我们所见到的各种网页特效就是使用JavaScript实现的。
二、JavaScript有什么作用?
1、动态的改变页面内容
HTML是网页的骨架,一旦编写,内容是无法改变的。JavaScript可以弥补这个不足,可以将内容动态地显示在网页中。
2、动态改变网页的外观
JavaScript通过修改网页元素的CSS样式,达到动态地改变网页的外观。(改的是css的样式)
3、验证表单数据
各大网站中的注册中的验证功能,就是JavaScript实现的。
4、响应事件
JavaScript是基于事件的语言。例如点击一个按钮弹出一个对话框,就是鼠标点击触发的事件。
对于JavaScript的理解,就一句话:如果没有使用JavaScript,网页就是静态的,仅仅是给用户浏览的。加入了JavaScript,网页的功能增加了。
三、JavaScript在HTML中的引用方式(有三种)
(1)内嵌式(head标签内);
<head>
<script type="text/javascript">
alert("我是内部的JS代码");
</script>
(2)行内式(body标签内,在某个元素内);
<body>
<!-- 行内式的js,直接写到元素的内部 -->
<input type="button" value="你好世界" onclick="alert('helloWorld')">
</body>
(3)引入外部JS文件;
<head>
<!-- 3. 外部js script 双标签 -->
<script src="my.js"></script> //注意在引用外部js文件时,在script标签里不能再写其他东西
</head>
四、JavaScript的一些误区 回到顶部
(1)JavaScript往往都是在网页中使用,而Java却可以在软件、网页、手机App等各个领域中使用;
(2)Java是一门面向对象的语言,而从本质上讲,JavaScript更像是一门函数式编程语言;
五、JavaScript基础 回到顶部
1、注释(两种,与java相同)
1. 单行注释 ctrl + / // 单行注释
2、多行注释 默认的快捷键 shift + alt + a /* */
2、 JS输入输出语句(三种)
<script>
// 这是一个输入框,“Are you ok?”这个会出现在输入框的上面
prompt('Are you ok?');
// alert 弹出警示框 输出的 展示给用户的
alert('Hello,world!');
// console 控制台输出 给程序员测试用的 ,网页F12调出开发者模式可进行查看
console.log('我是程序员能看到的');
</script>
3、JS数据结构 回到顶部
注意点:
1、标识符:
(1)第一个字符必须是字母、下划线(_)或美元符号这3种其中之一,其后的字符可以是字母、数字或下划线、美元符号;
(2)变量名不能包含空格、加号、减号等符号;
(3)标识符不能和JavaScript中用于其他目的的关键字同名;
2、关键词:
与JAVA一样,关键词有特定含义,不能乱定义
4、JS数据类型
JS里的数据类型有2大分类:一是“基本数据类型”,二是“特殊数据类型”。
基本数据类型包括以下3种:
- 1)数字型(Number型):如整型10,浮点型6.23;
- 2)字符串型(String型):如"你好";
- 3)布尔型(Boolean型):true或fasle;
特殊数据类型有3种:
- 1)空值(null型);
- 2)未定义值(undefined型);
- 3)转义字符;
5、变量 回到顶部
5.1 定义:就是存放数据的、内疗可以存储任意数据
<script>
//var 变量名称 = 存储的数据; (variable 变量)
var age =2333;
</script>
5.2 变量命名规范:(驼峰命名法)
1. 只能由字母、数字、_(下划线)、$(美元符号)组成。
2. 不能以数字开头。
3. 命名中不能出现-(js会理解成减号进行减法的操作),不能和关键字冲突。
js是弱类型语言,不重视类型的定义,但js会根据为变量赋值的情况自定判断该变量是何种类型:
数值型:var i = 1; var d = 2.35;
字符串:var str = "用心学习";
布尔型:var b = true; //这三种都为简单数据类型
5.3 isNaN()方法
isNaN() 方法用来判断非数字 并且返回一个值
》如果是数字,返回的是 false ;
》如果不是数字,返回的是true;
<script>
console.log(isNaN(99)); // false
console.log(isNaN('我是个好人')); // true
</script>
5.4数字型Number
// 1. 八进制 0 ~ 7 我们程序里面数字前面加0 表示八进制
var num1 = 010;
console.log(num1); // 010 八进制 转换为 10进制 就是 8
var num2 = 012;
console.log(num2);
// 2. 十六进制 0 ~ 9 a ~ f #ffffff 数字的前面加 0x 表示十六进制
var num3 = 0x9;
console.log(num3);
var num4 = 0xa;
console.log(num4);
// 3. 数字型的最大值
console.log(Number.MAX_VALUE); //和Java一样都是XXX.XXX (这是一个常量)
// 4. 数字型的最小值
console.log(Number.MIN_VALUE); //同上
// 5. 无穷大
console.log(Number.MAX_VALUE * 2); // Infinity 无穷大
// 6. 无穷小
console.log(-Number.MAX_VALUE * 2); // -Infinity 无穷大
// 7. 非数字
console.log('我是一个好人' - 100); // NaN
5.5 字符串型String
<script>
var str = 'Hello,world';
console.log(str);
// 字符串转义字符 都是用 \ 开头
var str1 = "你好\n世界";
console.log(str1);
//1. 获取字符串的长度 length
var str = 'Hello world';
console.log(str.length); // 11
// 2. 字符串的拼接 + 只要有字符串和其他类型相拼接 最终的结果都是字符串类型
console.log('沙漠' + '骆驼'); // 沙漠骆驼 字符
console.log('人人' + 18); // '人人18' 字母
console.log(12 + 12); // 24,数字
console.log('24' + 12); // '36'
//字符串的拼接(与java一样,用“+”号)
var age = 666;
console.log('我今年' + age + '岁'); //我今年666岁
</script>
5.6 布尔类型 Bollean
<script>
var abc = false; // abc 布尔型
var abc1 =true; // abc1 布尔型
//1. true 参与加法运算等于1
console.log(abc +233); //233
//2. false 参与加法运算等于0
console.log(abc1 +666); //667
// 如果一个变量声明未赋值 就是 undefined 未定义数据类型
var str;
console.log(str); // undefined
var variable = undefined;
console.log(variable + 1); // NaN undefined+数字 =NaN
// null 空值,在加法运算中等于0
var space = null;
console.log(space + 1); // 1
</script>
5.7 typeof用法(检测数据类型)
typeof运算符用于判断变量类型,返回的是当前变量的数据类型,这对于判断一个变量是否已被定义特别有用。
var num = 10;
console.log(typeof num); // number
var str = 'abc';
console.log(typeof str); // string
var flag = true;
console.log(typeof flag); // boolean
var vari = undefined;
console.log(typeof vari); // undefined
var timer = null;
console.log(typeof timer); // object
5.8数据之间的转化
// 1. 数字型-->字符串型 变量.toString()
var num = 10;
var str = num.toString();
console.log(str);//'10'
console.log(typeof str);//'String'
console.log(123+' ');//隐式转化:字符串拼接加空格
//-------------------------------------------------------------------------------
// 2. parseInt(变量)/Number(变量) 字符型-->数字型
console.log(parseInt('3.64')); // 3 取整
console.log(parseInt('120px')); // 120 会去到这个px单位
var str = '123';
console.log(Number(str));
console.log(Number('12'));
// 2. parseFloat(变量) 字符型-->数字型(float型)
console.log(parseFloat('3.14')); // 3.14
console.log(parseFloat('120px')); // 120 会去掉这个px单位
// 4. 利用算数运算 - * / (隐式转换)-->转为数字型的
console.log('12' - 0); // 12
console.log('123' - '120');//3
console.log('123' * 1);//123
//-------------------------------------------------------------------------------
//其他类型--->Bollean型
console.log(Boolean('')); // false
console.log(Boolean(0)); // false
console.log(Boolean(NaN)); // false
console.log(Boolean(null)); // false
console.log(Boolean(undefined)); // false
console.log('------------------------------');
console.log(Boolean('123'));
6、运算符 回到顶部
6.1算术运算符
常用的几种:
+ - * / % ++ --
具体用法:
//1.加减乘除:
console.log(1 + 1); // 2
console.log(1 - 1); // 0
console.log(1 * 1); // 1
console.log(1 / 1); // 1
// 2. % 取余 (取模,取得余数)
console.log(4 % 2); // 0
console.log(5 % 3); // 2
console.log(3 % 5); // 3
//自增自减(++、--):一般用于循环中
// 变量自增/减 ++i先自加后参与运算; i++先参与运算后自加
var num = 1;
var num1 = ++num; //先自加后参与运算
var num2 = num++
console.log(num1); // 2
console.log(num2); // 2
console.log(num); // 3
6.2 比较运算符
–》 返回true/false
种类:
> >= < <= !=
console.log(3 >= 5); // false
console.log(2 <= 4); // true
//1. == 默认转换数据类型 会把字符串型的数据转换为数字型 只要求值相等就可以
// == 等于(只比较内容)
console.log(3 == 5); // false
console.log(18 == 18); // true
console.log(18 == '18'); // true
console.log(18 != 18); // false
// 2. === 恒等于(比较内容的同时还要比较数据类型)
console.log(18 === 18); // true
console.log(18 === '18'); // false
6.3 逻辑运算符
&& 与
|| 或
! 非
//------------------------------------
console.log(3 > 5 && 3 > 2); // false
console.log(3 > 5 || 3 > 2); // true
console.log(!true); // false
//------------------------------------
// 逻辑与短路运算&& 如果表达式1 结果为真-则返回表达式2 如果表达式1为假-则返回表达式1
console.log(123 && 456); // 456
console.log(0 && 456); // 0
console.log(0 && 1 + 2 && 456 * 56789); // 0
console.log('' && 1 + 2 && 456 * 56789); // ''
// 如果有空的或者否定的为假 其余是真的 0 '' null undefined NaN
// 4. 逻辑或短路运算 如果表达式1 结果为真 则返回的是表达式1 如果表达式1 结果为假 则返回表达式2
console.log(123 || 456); // 123
console.log(123 || 456 || 456 + 123); // 123
console.log(0 || 456 || 456 + 123); // 456
// 逻辑中断很重要 它会影响我们程序运行结果思密达
var num = 0;
console.log(123 || num++);
console.log(num); // 0
6.4 赋值运算符
“=”
<script>
var num = 10;
console.log(num);
var age = 2;
console.log(age);
</script>
6.5 运算符优先级
小括号() >一元运算符(++、–、!)> 算数运算符(先* / % 后 + - ) > 相等运算符(== != === !==)>逻辑运算符(先&&后||)>赋值运算符(=)>逗号运算符(,)
7、流程控制分支结构 回到顶部
7.1 if选择结构
// 1. if 的语法结构 如果if 否则 else else...
if (条件表达式1) {
// 语句1;
} else if (条件表达式2) {
// 语句2;
} else if (条件表达式3) {
// 语句3;
} else {
// 最后的语句;
}
// 例子
if (3 > 5) {
alert('正确');
}else if(3=3){
alert('还是对的')
}else{
alert('错误')
};//还是对的
7.2 switch多分支语句
<script>
// 1. switch 语句也是多分支语句 也可以实现多选1
// 2. 语法结构 switch 转换、开关 case 小例子或者选项的意思
// switch (表达式) {
// case value1:
// 执行语句1;
// break;
// case value2:
// 执行语句2;
// break;
// ...
// default:
// 执行最后的语句;
// }
// 3. 执行思路 利用我们的表达式的值 和 case 后面的选项值相匹配 如果匹配上,就执行该case 里面的语句 如果都没有匹配上,那么执行 default里面的语句
// 4. 代码验证
switch (8) {
case 1:
console.log('这是1');
break;
case 2:
console.log('这是2');
break;
case 3:
console.log('这是3');
break;
default:
console.log('没有匹配结果');
} //没有匹配结果
</script>
7.3 for循环
for (初始化变量; 条件表达式; 操作表达式) {
//循环体
}
//--------------------------------------------
for (var i = 1; i <= 100; i++) {
console.log('Are you ok?');
}//输出100句Are you ok?
//与绝大多数高级语言一样,具体看java笔记(这里不详讲)
7.4 while循环和do while循环
// 1. while 循环语法结构 while 当...的时候
// while (条件表达式) {
// // 循环体
//
// 例子:
var num = 1;
while (num <= 100) {
console.log('你好');
num++;
}//输出100次你好
//-------------------------------------------------
//do while 循环 语法结构
do {
// 循环体
} while (条件表达式)
// 例子:
var i = 1;
do {
console.log('how are you?');
i++;
} while (i <= 100)
7.5 关键词continue和break
continue 退出本次(当前次的循环) 继续执行剩余次数循环
break 退出整个循环
8、数组 回到顶部
// 1.利用new 创建数组
var arr = new Array(); // 创建了一个空的数组
// 2.利用数组字面量创建数组 []
var arr = []; // 创建了一个空的数组
var arr1 = [1, true];
console.log(arr1);
console.log(arr1[1]); // true
console.log(arr1[2]); // 因为没有这个数组元素 所以输出的结果是 undefined
// 3.数组长度 数组名.length------>数组元素的个数
console.log(arr1.length); //2
// 4.新增数组元素
arr1.length = 5; // 方式一:把我们数组arr1的长度修改为了 5
console.log(arr1[2]); // undefined 里面应该有5个元素(空的为undefined)
arr1[5] = 666 // 方式二:新增数组元素 修改索引号 追加数组元素
// 扩容成了6个元素了
//注意点:不要直接给 数组名赋值 否则里面的数组元素都没有了
arr1 = '啊这';
console.log(arr1); //啊这
9、函数
函数,就是一个一系列JavaScript语句的集合,这是为了完成某一个会重复使用的特定功能。
可以方便代码重用,方便维护。
9.1 函数的定义
<script>
// 函数使用分为两步: 声明函数 和 调用函数
// 1. 声明函数
function 函数名() {
// 函数体
}
function hello() {
console.log('hello!');
}
// function 声明函数的关键字 全部小写
//----------------------------------------------------------
// 2. 调用函数
// 函数名();
hello();
// 调用函数的时候千万不要忘记加小括号
</script>
9.2 函数的值传递机制
我们可以利用函数的参数实现函数重复不同的代码
function 函数名(形参1,形参2...) { // 在声明函数时,小括号里面是 形参
}
// 函数名(实参1,实参2...); // 在函数调用时,小括号里面是 实参
// 3. 形参和实参的执行过程
function hello(name) { //
console.log(name);
}
function hello1(a,b){
console.log(a+'给'+b+'打招呼');
}
hello('何森');//何森
hello1('何森','张三');//何森在给张三打招呼
// 4. 注意点
// (1) 函数的参数可以有,也可以没有个数不限
// (2) 多个参数之间用逗号隔开
// (3) 形参可以看做是不用声明的变量
9.3 形参相关问题
<script>
// 函数形参实参个数匹配
function getSum(num1, num2) {
console.log(num1 + num2);
}
// 1. 如果实参的个数和形参的个数一致 则正常输出结果
getSum(1, 2);//3
// 2. 如果实参的个数多于形参的个数 只取到形参的个数(以形参数量为准)
getSum(1, 2, 3);//3
// 3. 如果实参的个数小于形参的个数 多于的形参定义为undefined 最终的结果就是 NaN
// 形参可以看做是不用声明的变量 num2 是一个变量但是没有接受值 结果就是undefined
getSum(1); // NaN
</script>
9.4 有返回值的函数
函数的返回值格式
function 函数名() {
return 需要返回的结果;
}
//调用函数
函数名();
// (1) 我们函数只是实现某种功能,最终的结果需要返回给函数的调用者函数名() 通过return 实现的
// (2) 只要函数遇到return 就把后面的结果 返回给函数的调用者 函数名() = return后面的结果
// 例子:
function getResult() {
return 2333;
}
var ABC = getResult();
console.log(ABC); //2333
9.5 有返回值函数的注意点
<script>
// 函数返回值注意事项
// 1. return 终止函数
function getSum(num1, num2) {
return num1 + num2; // return 后面的代码不会被执行
alert('改行不执行!');//这一行不会执行,在return后面
}
console.log(getSum(1, 2));
// 2. return 只能返回一个值
function fn(num1, num2) {
return num1, num2; // 返回的结果是最后一个值
}
console.log(fn(1, 2));
// 3. 我们求任意两个数的 加减乘除结果
function getResult(num1, num2) {
return [num1 + num2, num1 - num2, num1 * num2, num1 / num2];
}
var re = getResult(1, 2); // 返回的是一个数组
console.log(re);
// 4. 我们的函数如果有return 则返回的是 return 后面的值,如果函数么有 return 则返回undefined
function fun1() {
return 666;
}
console.log(fun1()); // 返回 666
function fun2() {
}
console.log(fun2()); // 函数返回的结果是 undefined
</script>
9.6 arguments的使用(伪数组)
arguments:里面存储了所有传递过来的实参
使用场景:当我们不知道用户要传多少个实参的时候,可以用arguments进行调用
<script>
// arguments 的使用 只有函数才有 arguments对象 而且是每个函数都内置好了这个arguments
function fn() {
// console.log(arguments); arguments = [1,2,3]
// console.log(arguments.length); //3
// console.log(arguments[2]); //3
// 我们可以按照数组的方式遍历arguments
for (var i = 0; i < arguments.length; i++) {
console.log(arguments[i]);
}
}
fn(1, 2, 3);
fn(1, 2, 3, 4, 5);
// 伪数组 并不是真正意义上的数组
// 1. 具有数组的 length 属性
// 2. 按照索引的方式进行存储的
// 3. 它没有真正数组的一些方法 pop() push() 等等
<script>
//-----------------------------------------------------------------------------
案例一:利用函数(arguments)求任意数的最大值
<script>
// 利用函数求任意个数的最大值
function getMax() { // arguments = [1,2,3]
var max = arguments[0];
for (var i = 1; i < arguments.length; i++) {
if (arguments[i] > max) {
max = arguments[i];
}
}
return max;
}
console.log(getMax(1, 2, 3)); //3
console.log(getMax(1, 2, 3, 4, 5));//5
console.log(getMax(11, 2, 34, 444, 5, 100));//444
</script>
//--------------------------------------------------------------------------------
<script>
案例二:利用函数翻转任意数组 reverse 翻转
function reverse(arr) {
var newArr = [];
for (var i = arr.length - 1; i >= 0; i--) {
newArr[newArr.length] =
arr[i];
}
return newArr;
}
var arr1 = reverse([1, 3, 4, 6, 9]);
console.log(arr1);
var arr2 = reverse(['red', 'pink', 'blue']);
console.log(arr2);
</script>
//--------------------------------------------------------------------------------
<script>
案例3:利用函数冒泡排序 sort 排序
function sort(arr) {
for (var i = 0; i < arr.length - 1; i++) {
for (var j = 0; j < arr.length - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
var temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
return arr;
}
var arr1 = sort([1, 4, 2, 9]);
console.log(arr1);
var arr2 = sort([11, 7, 22, 999]);
console.log(arr2);
</script>
9.7 函数的两种声明方式
<script>
// 函数的2中声明方式
1. 利用函数关键字自定义函数(命名函数)
function fn() {
}
fn(); //调用函数
2. 函数表达式(匿名函数)
// var 变量名 = function() {};
var fun = function(aru) {
console.log('我是函数表达式');
console.log(aru);
}
fun('qaqQAQ');
// (1) fun是变量名 不是函数名
// (2) 函数表达式声明方式跟声明变量差不多,只不过变量里面存的是值 而 函数表达式里面存的是函数
// (3) 函数表达式也可以进行传递参数
</script>
10、作用域 回到顶部
10.1 作用域 : 就是代码名字(变量)在某个范围内起作用和效果
目的:为了提高程序的可靠性,更重要的是减少命名冲突
<script>
// 1. js的作用域(es6)之前 : 分为 全局作用域 和 局部作用域
// 3. 全局作用域: 整个script标签 或者是一个单独的js文件
var num = 10;
var num = 30;
console.log(num);//30
// 4. 局部作用域(函数作用域) 在函数内部就是局部作用域 这个代码的名字只在函数内部起效果和作用
function fn() {
// 局部作用域
var num = 20;
console.log(num);//20
}
fn();
</script>
//---------------------------------------------------------------------------
<script>
// 变量的作用域: 根据作用域的不同我们变量分为全局变量和局部变量
// 1. 全局变量: 在全局作用域下的变量 在全局下都可以使用
// 注意 如果在函数内部 没有声明直接赋值的变量也属于全局变量
var num = 10; // num就是一个全局变量
console.log(num);
function fn() {
console.log(num);
}
fn();
// console.log(aru);
// 2. 局部变量 在局部作用域下的变量 后者在函数内部的变量就是 局部变量
// 注意: 函数的形参也可以看做是局部变量
function fun(aru) {
var num1 = 10; // num1就是局部变量 只能在函数内部使用
num2 = 20;
}
fun();
// console.log(num1);
// console.log(num2);
// 3. 从执行效率来看全局变量和局部变量
// (1) 全局变量只有浏览器关闭的时候才会销毁,比较占内存资源
</script>
JS现阶段没有块级作用域。若花括号里面定义的变量赋了值则为全局变量,在花括号外面也可以用。
10.2作用域链
作用域链 : 内部函数访问外部函数的变量,采取的是链式查找的方式来决定取那个值 这种结构我们称为作用域链 就近原则
<script>
//
var num = 10;
function fn() { // 外部函数
var num = 20;
function fun() { // 内部函数
console.log(num); //20
}
fun();
}
fn();
</script>
案例:
<script>
// 案例1
function f1() {
var num = 123;
function f2() {
var num = 0;
console.log(num); // 0
}
f2();
}
var num = 456;
f1();
// 案例2
var a = 1;
function fn1() {
var a = 2;
var b = '22';
fn2();
function fn2() {
var a = 3;
fn3();
function fn3() {
var a = 4;
console.log(a); //a的值 4
console.log(b); //b的值 '22'
}
}
}
fn1();
</script>
11、JS预解析 回到顶部
- 我们js引擎运行js 分为两步: 预解析 代码执行
(1). 预解析:js引擎会把js 里面所有的 var 还有 function 提升到当前作用域的最前面
(2). 代码执行 :按照代码书写的顺序从上往下执行 - 预解析分为 变量预解析(var变量提升) 和 函数预解析(function函数提升)
(1) 变量提升:就是把所有的变量声明提升到当前的作用域最前面 不提升赋值操作
(2) 函数提升:就是把所有的函数声明提升到当前作用域的最前面 不调用函数
// 1
console.log(num); //报错,未定义
// 2
console.log(num); // undefined
var num = 10;
// 相当于执行了以下代码,先预解析,var变量提升但赋值不提升。
// var num;
// console.log(num); // undefined
// num = 10;
// 3
fn();
function fn() {
console.log(11);
}
//fn(); 放在上面或下面都可以,会把这个fn()先提升,直接的函数声明
// 4
fun(); // 报错
var fun = function() { //匿名函数
console.log(22);
}
// 函数表达式 调用必须写在函数表达式的下面
// 相当于执行了以下代码
// var fun;
// fun(); 赋值的这种函数不可以提升(非直接),这就一定要把函数声明写在函数调用代码的前面
// fun = function() {
// console.log(22);
// }
案例:
案例1:
var num = 10;
fun();
function fun() {
console.log(num);
var num = 20;
}
// 等价于:(把函数提到了最前面,变量也先声明)
function fun() {
var num;
console.log(num);
num = 20;
}
num = 10;
fun();
-------------------------------------------------------------------------
案例2:
var num = 10;
function fn() {
console.log(num);
var num = 20;
console.log(num);
}
fn();
// 相当于以下代码
var num;
function fn() {
var num;
console.log(num);
num = 20;
console.log(num);
}
num = 10;
fn();
------------------------------------------------------------------
案例3:
var a = 18;
f1();
function f1() {
var b = 9;
console.log(a);
console.log(b);
var a = '123';
}
// 相当于以下代码
var a;
function f1() {
var b;
var a;
b = 9;
console.log(a);
console.log(b);
a = '123';
}
a = 18;
f1();
---------------------------------------------------------------------
案例4:
f1();
console.log(c);
console.log(b);
console.log(a);
function f1() {
var a = b = c = 9;
console.log(a);
console.log(b);
console.log(c);
}
// 相当于以下代码
function f1() {
var a;
a = b = c = 9;
// 相当于 var a = 9; b = 9; c = 9; b 和 c 直接赋值 没有var 声明 当 全局变量看
// 集体声明 var a = 9, b = 9, c = 9;
console.log(a);
console.log(b);
console.log(c);
}
f1();
console.log(c);
console.log(b);
console.log(a);
12、JS对象 回到顶部
12.1 自定义对象的创建(三种方式)
一、利用对象字面量创建对象
// var obj = {}; // 创建了一个空的对象
var obj = {
uname: '张三疯',
age: 18,
sex: '男',
sayHi: function() {
console.log('hi~');
}
}
// (1) 里面的属性或者方法我们采取键值对的形式 键 属性名 : 值 属性值
// (2) 多个属性或者方法中间用逗号隔开的
// (3) 方法冒号后面跟的是一个匿名函数
1.1 使用对象
// (1). 调用对象的属性 我们采取 对象名.属性名
console.log(obj.uname);
// (2). 调用属性还有一种方法 对象名['属性名']
console.log(obj['age']);//在这个对象里没出现的属性是undefined
// (3) 调用对象的方法 sayHi 对象名.方法名()
obj.sayHi();
二、利用new Object来创建对象
var obj = new Object(); // 创建了一个空的对象
obj.uname = '张三疯'; //每一句都是一个单独的句子
obj.age = 18;
obj.sex = '男';
obj.sayHi = function() {
console.log('c');
}
// (1) 我们是利用 等号 = 赋值的方法 添加对象的属性和方法
// (2) 每个属性和方法之间用 分号结束(;)
console.log(obj.uname); //张三疯
console.log(obj['sex']); //男
obj.sayHi(); //hi~
三、利用构造函数来创建对象
可以减少代码重复,一次可以创建多个对象(利用函数封装到函数中去)
构造函数的语法格式:
function 构造函数名() {
this.属性 = 值;
this.方法 = function() {}
}
// new 构造函数名();
function Star(uname, age, sex) {
this.name = uname;
this.age = age;
this.sex = sex;
this.sing = function(sang) {
console.log(sang);
}
}
-----------------------------------------------
例子:
var ldh = new Star('刘德华', 18, '男'); // 调用函数返回的是一个对象
// console.log(typeof ldh); 返回是一个对象object
console.log(ldh.name); //刘德华
console.log(ldh['sex']); //男
ldh.sing('冰雨'); //冰雨
var zxy = new Star('张学友', 19, '男');
console.log(zxy.name); //张学友
console.log(zxy.age); //19
zxy.sing('李香兰') //李香兰
----------------------------------------------------
注意点:
1. 构造函数名字首字母要大写
2. 我们构造函数不需要return 就可以返回结果
3. 我们调用构造函数 必须使用 new
4. 我们只要new Star() 调用函数就创建一个对象 ldh {}
5. 我们的属性和方法前面必须添加 this
12.2 构造函数和对象的关系 回到顶部
1. 构造函数 明星 泛指的某一大类 它类似于 java 语言里面的 类(class)
function Star(uname, age, sex) {
this.name = uname;
this.age = age;
this.sex = sex;
this.sing = function(sang) {
console.log(sang);
}
}
2. 对象 特指 是一个具体的事物 刘德华 == {name: "刘德华", age: 18, sex: "男", sing: ƒ}
var ldh = new Star('刘德华', 18, '男'); // 调用函数返回的是一个对象
console.log(ldh);
// 3. 我们利用构造函数创建对象的过程我们也称为对象的实例化
-----------------------------------------------------------
<script>
3. new关键字执行过程
// 1. new 构造函数可以在内存中创建了一个空的对象
// 2. this 就会指向刚才创建的空对象
// 3. 执行构造函数里面的代码 给这个空对象添加属性和方法
// 4. 返回这个对象
function Star(uname, age, sex) {
this.name = uname;
this.age = age;
this.sex = sex;
this.sing = function(sang) {
console.log(sang);
}
}
var ldh = new Star('刘德华', 18, '男');
</script>
12.3 函数、方法、对象、变量的区别 回到顶部
1.变量和属性的相同点:
他们都是用来存储数据的 。
变量:单独声明并赋值,使用的时候直接写变量名 单独存在
属性:在对象里面的,不需要声明的。使用的时候必须是 对象.属性
2.函数和方法的相同点:
都是实现某种功能。
函数:单独声明,并且调用的 函数名() 单独存在的
方法:在对象里面,调用的时候 对象.方法()
12.4 遍历对象(for in 循环)
for in 对于无序号的对象属性进行遍历
<script>
// 遍历对象
var obj = {
name: '刘德华',
age: 18,
sex: '男',
fn: function() {}
}
// console.log(obj.name);
// console.log(obj.age);
// console.log(obj.sex);
// for in 遍历我们的对象
for (变量 in 对象) {
}
for (var k in obj) {
console.log(k); // k为属性名
console.log(obj[k]); // obj[k] 是 属性值
}
// 我们使用 for in 里面的变量 我们喜欢写 k 或者 key
</script>
12.5 内置对象(直接使用的工具) 回到顶部
定义:JS里自带的一些对象,这些对象提供了一些常用的或是最基本的而必要的功能
例如:Math、Date、Array、String等
12.5.1 Math函数
Math数学对象 不是一个构造函数 ,所以我们不需要new 来调用 而是直接使用里面的属性和方法即可
1、max方法
console.log(Math.PI); // 一个属性 圆周率
console.log(Math.max(1, 99, 3)); // 99
console.log(Math.max(-1, -10)); // -1
console.log(Math.max(1, 99, '其他的东西')); // NaN
console.log(Math.max()); // -Infinity
---------------------------------------------------------------------
2、abs方法(绝对值方法)
console.log(Math.abs(1)); // 1
console.log(Math.abs(-1)); // 1
console.log(Math.abs('-1')); // 隐式转换 会把字符串型 -1 转换为数字型
console.log(Math.abs('abc')); // NaN
---------------------------------------------------------------------
3、三个取整方法
// (1) Math.floor() 地板 向下取整 往最小了取值
console.log(Math.floor(1.1)); // 1
console.log(Math.floor(1.9)); // 1
// (2) Math.ceil() ceil 天花板 向上取整 往最大了取值
console.log(Math.ceil(1.1)); // 2
console.log(Math.ceil(1.9)); // 2
// (3) Math.round() 四舍五入 其他数字都是四舍五入,但是 .5 特殊 它往大了取
console.log(Math.round(1.1)); // 1
console.log(Math.round(1.5)); // 2
console.log(Math.round(1.9)); // 2
console.log(Math.round(-1.1)); // -1
console.log(Math.round(-1.5)); // 这个结果是 -1
---------------------------------------------------------------------
4、随机数方法
random() 返回一个随机的小数 0 <= x < 1
// 这个方法里面不跟参数
// 例子:
console.log(Math.random());
// 1. 得到两个数之间的随机整数 并且 包含这2个整数
// Math.floor(Math.random() * (max - min + 1)) + min;
function getRandom(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
console.log(getRandom(1, 10));
// 2. 随机点名
var arr = ['张三', '张三丰', '张三疯子', '李四', '李思思'];
console.log(arr[getRandom(0, arr.length - 1)]);
12.5.2 Date日期对象(方法) 回到顶部
1、 Date() 日期对象 是一个构造函数 必须使用new 来调用创建我们的日期对象
var arr = new Array(); // 创建一个数组对象
var obj = new Object(); // 创建了一个对象实例
// 1. 使用Date 如果没有参数 返回当前系统的当前时间
var date = new Date();
console.log(date);
// 2. 参数常用的写法 数字型 2019, 10, 01 或者是 字符串型 '2019-10-1 8:8:8'
var date1 = new Date(2019, 10, 1);
console.log(date1); // 返回的是 11月 不是 10月
var date2 = new Date('2019-10-1 8:8:8');
console.log(date2);
--------------------------------------------------------------------
2、 格式化日期 年月日 (其实就是调用Date对象里的方法)
var date = new Date();
console.log(date.getFullYear()); // 返回当前日期的年 2019
console.log(date.getMonth() + 1); // 月份 返回的月份小1个月 记得月份+1
console.log(date.getDate()); // 返回的是 几号
console.log(date.getDay()); // 3 周一返回的是 1 周六返回的是 6 但是 周日返回的是 0
//2019年 5月 1日 星期三
var year = date.getFullYear();
var month = date.getMonth() + 1;
var dates = date.getDate();
var arr = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
var day = date.getDay();
console.log('今天是:' + year + '年' + month + '月' + dates + '日 ' + arr[day]);
---------------------------------------------------------
3、 格式化日期 时分秒
var date = new Date();
console.log(date.getHours()); // 时
console.log(date.getMinutes()); // 分
console.log(date.getSeconds()); // 秒
// 要求封装一个函数返回当前的时分秒 格式 08:08:08
function getTimer() {
var time = new Date();
var h = time.getHours();
h = h < 10 ? '0' + h : h; //三元运算符
var m = time.getMinutes();
m = m < 10 ? '0' + m : m;
var s = time.getSeconds();
s = s < 10 ? '0' + s : s;
return h + ':' + m + ':' + s;
}
console.log(getTimer());
---------------------------------------------------
4、 获得Date总的毫秒数(时间戳)
不是当前时间的毫秒数 而是距离1970年1月1号过了多少毫秒数
// 1. 通过 valueOf() getTime()
var date = new Date();
console.log(date.valueOf()); // 就是 我们现在时间 距离1970.1.1 总的毫秒数
console.log(date.getTime());
// 2. 简单的写法 (最常用的写法)
var date1 = +new Date(); // +new Date() 返回的就是总的毫秒数
console.log(date1);
// 3. H5 新增的 获得总的毫秒数
console.log(Date.now());
倒计时效果案例:
<script>
// 倒计时效果
// 1.核心算法:输入的时间减去现在的时间就是剩余的时间,即倒计时 ,但是不能拿着时分秒相减,比如 05 分减去25分,结果会是负数的。
// 2.用时间戳来做。用户输入时间总的毫秒数减去现在时间的总的毫秒数,得到的就是剩余时间的毫秒数。
// 3.把剩余时间总的毫秒数转换为天、时、分、秒 (时间戳转换为时分秒)
// 转换公式如下:
// d = parseInt(总秒数/ 60/60 /24); // 计算天数
// h = parseInt(总秒数/ 60/60 %24) // 计算小时
// m = parseInt(总秒数 /60 %60 ); // 计算分数
// s = parseInt(总秒数%60); // 计算当前秒数
function countDown(time) {
var nowTime = +new Date(); // 返回的是当前时间总的毫秒数
var inputTime = +new Date(time); // 返回的是用户输入时间总的毫秒数
var times = (inputTime - nowTime) / 1000; // times是剩余时间总的秒数
var d = parseInt(times / 60 / 60 / 24); // 天
d = d < 10 ? '0' + d : d;
var h = parseInt(times / 60 / 60 % 24); //时
h = h < 10 ? '0' + h : h;
var m = parseInt(times / 60 % 60); // 分
m = m < 10 ? '0' + m : m;
var s = parseInt(times % 60); // 当前的秒
s = s < 10 ? '0' + s : s;
return d + '天' + h + '时' + m + '分' + s + '秒';
}
console.log(countDown('2019-5-1 18:00:00'));
var date = new Date();
console.log(date);
</script>
12.5.3 数组对象 回到顶部
一、创建数组的两种方式
1. 利用数组字面量
var arr = [1, 2, 3];
console.log(arr[0]);
2. 利用new Array()
// var arr1 = new Array(); // 创建了一个空的数组
// var arr1 = new Array(2); // 这个2 表示 数组的长度为 2 里面有2个空的数组元素
var arr1 = new Array(2, 3); // 等价于 [2,3] 这样写表示 里面有2个数组元素 是 2和3
console.log(arr1);
-------------------------------------------------------------------------
二、检测是否为数组
(1) instanceof 运算符 它可以用来检测是否为数组
var arr = [];
var obj = {};
console.log(arr instanceof Array); \\true
console.log(obj instanceof Array); \\false
(2) Array.isArray(参数); H5新增的方法 ie9以上版本支持
console.log(Array.isArray(arr)); \\true
console.log(Array.isArray(obj)); \\false
-------------------------------------------------------------------------
三、添加、删除数组元素
1. push() 在我们数组的末尾 添加一个或者多个数组元素
var arr = [1, 2, 3];
console.log(arr.push(4, '呵呵'));//返回的是新数组的长度5
console.log(arr);//(5)[1, 2, 3, 4, 呵呵]
// (1) push 可以给数组追加新的元素
// (2) push() 参数写数组元素即可
// (3) push完毕之后,返回的结果是 新数组的长度
// (4) 原数组也会发生变化
2. unshift 在我们数组的开头 添加一个或者多个数组元素
console.log(arr.unshift('red', 'purple')); //返回的是新数组的长度7
console.log(arr);//[red, purple, 1, 2, 3, 4, 呵呵]
// (1) unshift是可以给数组前面追加新的元素
// (2) unshift() 参数直接写 数组元素就可以了
// (3) unshift完毕之后,返回的结果是 新数组的长度
// (4) 原数组也会发生变化
3. pop() 它可以删除数组的最后一个元素
console.log(arr.pop());
console.log(arr);
// (1) pop是可以删除数组的最后一个元素 一次只能删除一个元素
// (2) pop() 没有参数
// (3) pop完毕之后,返回的结果是 删除的那个元素
// (4) 原数组也会发生变化
4. shift() 它可以删除数组的第一个元素
console.log(arr.shift());
console.log(arr);
// (1) shift是可以删除数组的第一个元素 记住一次只能删除一个元素
// (2) shift() 没有参数
// (3) shift完毕之后,返回的结果是 删除的那个元素
// (4) 原数组也会发生变化
--------------------------------------------------------------------------
四、数组排序
1. 翻转数组 reverse()方法
var arr = ['pink', 'red', 'blue'];
arr.reverse();
console.log(arr);
2. 数组排序(冒泡排序) sort()方法,写法固定(需记忆,单用sort方法只能排0~9之间的数字排序)
var arr1 = [13, 4, 77, 1, 7];
arr1.sort(function(a, b){
// return a - b; 升序的顺序排列
return b - a; // 降序的顺序排列
});
console.log(arr1);
-----------------------------------------------------------------------------
五、获取数组元素索引
1、indexOf(数组元素) 作用就是返回该数组元素的索引号 从前面开始查找
// 它只返回第一个满足条件的索引号
// 它如果在该数组里面找不到元素,则返回的是 -1
// var arr = ['red', 'green', 'blue', 'pink', 'blue'];
var arr = ['red', 'green', 'pink'];
console.log(arr.indexOf('blue')); //-1
2、lastIndexOf(数组元素) 作用就是返回该数组元素的索引号 从后面开始查找
var arr = ['red', 'green', 'blue', 'pink', 'blue'];
console.log(arr.lastIndexOf('blue')); // 4
案例:数组去重
数组去重 ['c', 'a', 'z', 'a', 'x', 'a', 'x', 'c', 'b'] 要求去除数组中重复的元素。
// 1.目标: 把旧数组里面不重复的元素选取出来放到新数组中, 重复的元素只保留一个, 放到新数组中去重。
// 2.核心算法: 我们遍历旧数组, 然后拿着旧数组元素去查询新数组, 如果该元素在新数组里面没有出现过, 我们就添加, 否则不添加。
// 3.我们怎么知道该元素没有存在? 利用 新数组.indexOf(数组元素) 如果返回时 - 1 就说明 新数组里面没有改元素
// 封装一个 去重的函数 unique 独一无二的
function QC(){
var newArr = [];
var arr = ['c', 'a', 'z', 'a', 'x', 'a', 'x', 'c', 'b'];
for(var i =0;i<arr.length;i++){
if(newArr.indexOf(arr[i])==-1){
newArr.push(arr[i]);
}
}
alert(newArr);
}
QC();
数组转化为字符串的方法(两种)
1. toString() 将我们的数组转换为字符串
var arr = [1, 2, 3];
console.log(arr.toString()); // 1,2,3
2. join(分隔符) //默认分隔符为“,”
var arr1 = ['green', 'blue', 'pink'];
console.log(arr1.join()); // green,blue,pink
console.log(arr1.join('-')); // green-blue-pink
console.log(arr1.join('&')); // green&blue&pink
12.5.4 字符串对象 回到顶部
1、基本包装类型:把简单数据类型 包装成为了 复杂数据类型
var str = 'andy';
console.log(str.length);
// 对象 才有 属性和方法 复杂数据类型才有 属性和方法
// (1) 把简单数据类型包装为复杂数据类型
var temp = new String('andy'); //加了new 就是复杂数据类型
// (2) 把临时变量的值 给 str
str = temp;
// (3) 销毁这个临时变量
temp = null;
2、字符串的不可变性
// 字符串的不可变性
var str = 'andy'; //str指向andy
console.log(str); //andy
str = 'red'; //开辟新空间red,str指向red这个内存空间
console.log(str); //red
// 因为我们字符串的不可变所以不要大量的拼接字符串
var str = '';
for (var i = 1; i <= 1000000000; i++) {
str += i;
}
console.log(str);
3、一些字符串的方法
1、字符串对象 根据字符返回位置 str.indexOf('要查找的字符', [起始的位置])
var str = '改革春风吹满地,春天来了'; //[]这个表示可有可无
console.log(str.indexOf('春'));
console.log(str.indexOf('春', 3)); // 从索引号是 3的位置开始往后查找
---------------------------------------------------------------------
2、根据位置返回字符
方法一: charAt(index) 根据位置返回字符
var str = 'andy';
console.log(str.charAt(3)); //y
// 遍历所有的字符
for (var i = 0; i < str.length; i++) {
console.log(str.charAt(i)); //a n d y
}
方法二: charCodeAt(index) 返回相应索引号的字符的ASCII值
目的: 判断用户按下了那个键
console.log(str.charCodeAt(0)); // 97 (a->97)
方法三: str[index] H5 新增的
console.log(str[0]); // a
----------------------------------------------------------------------
3、拼接、截取字符串的方法
1. concat('字符串1','字符串2'....)
var str = 'andy';
console.log(str.concat('red')); //andyred
2. substr('截取的起始位置', '截取几个字符');
var str1 = '改革春风吹满地';
console.log(str1.substr(2, 2)); //春风
// 第一个2 是索引号的2 从第几个开始
// 第二个2 是取几个字符
----------------------------------------------------------------------
4、替换字符串和字符串转化为数组
1. 替换字符 replace('被替换的字符', '替换为的字符') 它只会替换第一个字符
var str = 'andyandy';
console.log(str.replace('a', 'b'));
// 有一个字符串 'abcoefoxyozzopp' 要求把里面所有的 o 替换为 *
var str1 = 'abcoefoxyozzopp';
while (str1.indexOf('o') !== -1) {
str1 = str1.replace('o', '*');
}
console.log(str1); //abc*ef*xy*zz*pp
2. 字符转换为数组 split('分隔符') 前面我们学过 join 把数组转换为字符串
var str2 = 'red, pink, blue';
console.log(str2.split(',')); //,为分隔符
var str3 = 'red&pink&blue';
console.log(str3.split('&')); //&为分隔符
----------------------------------------------------------------------
5、有一个对象 来判断该属性是否存在。对象['属性名']
若存在返回属性值。(注意:0为false)
若不存在返回undefined
var o = {
age: 2
}
if (o['age']!=undefined) {
console.log('里面有该属性');
} else {
console.log('没有该属性');
}
案例:判断一个字符串 ‘abcoefoxyozzopp’ 中出现次数最多的字符,并统计其次数。
//核心算法:利用 charAt() 遍历这个字符串
//把每个字符都存储给对象, 如果对象没有该属性,就为1,如果存在了就 +1
//遍历对象,得到最大值和该字符
var str = 'abcoefoxyozzopp';
var o = {};
for (var i = 0; i < str.length; i++) {
var chars = str.charAt(i); // chars 是 字符串的每一个字符
if (o[chars]) { // o[chars] 得到的是属性值
o[chars]++;
} else {
o[chars] = 1;
}
}
console.log(o);
// 2. 遍历对象
var max = 0;
var ch = '';
for (var k in o) { // k 得到是 属性名
if (o[k] > max) { // o[k] 得到的是属性值
max = o[k];
ch = k;
}
}
console.log(max);
console.log('最多的字符是' + ch);
13、简单数据类型和复杂数据类型 回到顶部
13.1 简单数据类型:基本数据类型、值类型
eg:String、number、boolean、undefined、null
// 特别的:简单数据类型 null 返回的是一个空的对象 object
var timer = null;
console.log(typeof timer);
13.2 复杂数据类型:引用数据类型。
13.3存储方式:
- 简单数据类型 是存放在栈里面 里面直接开辟一个空间存放的是值
- 复杂数据类型 首先在栈里面存放地址 十六进制表示 然后这个地址指向堆里面的数据
六、DOM (一个接口)
1、DOM简介 回到顶部
文档对象模型(Document Object Model,简称 DOM),是 W3C 组织推荐的处理可扩展标记语言(HTML或者XML)的标准编程接口
W3C 已经定义了一系列的 DOM 接口,通过这些 DOM 接口可以改变网页的内容、结构和样式。
1.文档:一个页面就是一个文档,DOM中使用doucument来表示
2.元素:页面中的所有标签都是元素,DOM中使用 element 表示
3.节点:网页中的所有内容都是节点(标签,属性,文本,注释等),DOM中使用node表示
DOM 把以上内容都看做是对象
2、获取元素
2.1 如何获取元素 回到顶部
- 根据 ID 获取
- 根据标签名获取
- 通过 HTML5 新增的方法获取
- 特殊元素获取
2.1.1根据 ID获取
document.getElementById(‘元素’);方法,返回元素的对象
<div id="time">2019-9-9</div>
1. 因为我们文档页面从上往下加载,所以先得有标签 所以我们script写到标签的下面
2. get 获得 element 元素 by 通过 驼峰命名法
3. 参数 id是大小写敏感的字符串
4. 返回的是一个元素对象
var timer = document.getElementById('time');
console.log(timer); //一整个标签全部返回了
console.log(typeof timer); //Object
5. console.dir 打印我们返回的元素对象 更好的查看里面的属性和方法
console.dir(timer);
2.1.2 根据标签名获取
document.getElementsByTagName(‘标签名’);
<ul>
<li>知否知否,应是等你好久11</li>
<li>知否知否,应是等你好久22</li>
<li>知否知否,应是等你好久33</li>
<li>知否知否,应是等你好久44</li>
</ul>
1.返回的是 获取过来元素对象的集合 以伪数组的形式存储的
var lis = document.getElementsByTagName('li');
console.log(lis);
console.log(lis[0]); //<li>知否知否,应是等你好久11</li>
//08 2. 依次打印里面的元素对象我们可以采取遍历的方式
for (var i = 0; i < lis.length; i++) {
console.log(lis[i]);
}
3. 如果页面中只有一个li 返回的还是伪数组的形式
4. 如果页面中没有这个元素 返回的是空的伪数组的形式
5. element.getElementsByTagName('标签名'); 父元素必须是指定的单个元素
// var ol = document.getElementsByTagName('ol'); // [ol]
// console.log(ol[0].getElementsByTagName('li'));
var ol = document.getElementById('ol');
console.log(ol.getElementsByTagName('li'));
2.1.3 H5新增的方法
<div class="box">盒子1</div>
<div class="box">盒子2</div>
<div id="nav">
<ul>
<li>首页</li>
<li>产品</li>
</ul>
</div>
<script>
1、document.getElementsByClassName('类名') 根据类名获得某些元素集合
var boxs = document.getElementsByClassName('box');
console.log(boxs);
2. querySelector 返回指定选择器的第一个元素对象 切记 里面的选择器需要加符号 .box #nav
var firstBox = document.querySelector('.box');
console.log(firstBox);//<div class="box">盒子1</div>
var nav = document.querySelector('#nav');
console.log(nav);//<div id="nav"><ul><li>首页</li><li>产品</li></ul>
</div>
var li = document.querySelector('li'); // <li>首页</li>
console.log(li);
3. querySelectorAll()返回指定选择器的所有元素对象集合
var allBox = document.querySelectorAll('.box');
console.log(allBox); //NodeList(2)0: div.box 1: div.box
var lis = document.querySelectorAll('li');
console.log(lis);//NodeList(2)0: li 1: li
</script>
2.1.4 获取特殊标签(body和html标签)
document.body;
document.documentElement;
// 1.获取body 元素
var bodyEle = document.body;
console.log(bodyEle);
console.dir(bodyEle);
// 2.获取html 元素
// var htmlEle = document.html;错误的
var htmlEle = document.documentElement;
console.log(htmlEle);
3、事件 回到顶部
3.1 事件概述
事件:JavaScript 使我们有能力创建动态页面,而事件是可以被 JavaScript 侦测到的行为。简述为触发—响应机制。
3.2 事件三要素
1、 事件源(谁)
2、 事件类型 (什么事,如何触发 什么事件,绑定事件)(可不绑定事件)
3、 事件处理程序 (会做什么处理,采取函数赋值形式)
例子:
<button id="btn">你</button> //事件源
<script>
var btn = document.getElementById('btn'); //绑定事件
btn.onclick = function() { //事件处理程序
alert('好帅');
}
</script>
3.3 常见的鼠标事件
鼠标事件 | 触发条件 |
---|---|
onclick | 鼠标点击左键触发 |
onmouseover | 鼠标经过触发 |
onmouseout | 鼠标离开触发 |
onfocus | 获得鼠标焦点触发 |
onblur | 失去鼠标焦点触发 |
onmousemove | 鼠标移动触发 |
onmouseup | 鼠标弹起触发 |
onmousedown | 鼠标按下触发 |
4、操作元素 回到顶部
JavaScript 的 DOM 操作可以改变网页内容、结构和样式,我们可以利用 DOM 操作元素来改变元素里面的内容 、属性等。注意以下都是属性
4.1改变元素内容
1、从起始位置到终止位置的内容, 但它去除 html 标签, 同时空格和换行也会去
element.innerText
2、起始位置到终止位置的全部内容,包括 html 标签,同时保留空格和换行(标准,用的也最多)
element.innerHTML
案例:
当我们点击了按钮, div里面的文字会发生变化
// 1. 获取元素
var btn = document.querySelector('button');
var div = document.querySelector('div');
// 2.注册事件
btn.onclick = function() {
// div.innerText = '2019-6-6';
div.innerHTML = getDate();
}
function getDate() {
var date = new Date();
// 我们写一个 2019年 5月 1日 星期三
var year = date.getFullYear();
var month = date.getMonth() + 1;
var dates = date.getDate();
var arr = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
var day = date.getDay();
return '今天是:' + year + '年' + month + '月' + dates + '日 ' + arr[day];
}
// 我们元素可以不用添加事件
var p = document.querySelector('p');
p.innerHTML = getDate();
4.2 innerTest和innerHTML的区别
- innerText 不识别html标签 非标准 去除空格和换行
- innerHTML 识别html标签 W3C标准 保留空格和换行的
<p>
我是文字
<span>123</span>
</p>
<script>
var div = document.querySelector('div');
// div.innerText = '<strong>今天是:</strong> 2019';
div.innerHTML = '<strong>今天是:</strong> 2019';
// 这两个属性是可读写的 可以获取元素里面的内容
//输出:今天是: 2019 ('今天是:'加粗了,识别了strong标签)
var p = document.querySelector('p');
console.log(p.innerText); //去除空格和换行,输出:我是文字 <span>123</span>
console.log(p.innerHTML); //保留了空格和换行,标签识别了 输出:我是文字 123(“我是文字”加粗了)
</script>
4.3 修改元素属性
img的属性(图片)
img.src = "xxx";
//表单属性:
input.value = "xxx"; //默认值
input.type = "xxx"; //类型
input.checked = "xxx"; //是否选中
input.selected = true / false; //是否已被选
input.disabled = true / false; //是否禁用
案例:
<body>
<button id="ldh">刘德华</button>
<button id="zxy">张学友</button> <br>
<img src="images/ldh.jpg" alt="" title="刘德华" style="width:300px">
<script>
// 修改元素属性 src
// 1. 获取元素
var ldh = document.getElementById('ldh');
var zxy = document.getElementById('zxy');
var img = document.querySelector('img');
// 2. 注册事件 处理程序
zxy.onclick = function() {
img.src = 'images/zxy.jpg';
img.title = '张学友思密达';
}
ldh.onclick = function() {
img.src = 'images/ldh.jpg';
img.title = '刘德华';
}
</script>
</body>
4.4 表单元素的属性操作 回到顶部
不能用innerHTML和innerText
type、value、checked、selected、disabled这几个元素。可以通过DOM进行修改。
例子:
<body>
<button>按钮</button>
<input type="text" value="输入内容">
<script>
// 1. 获取元素
var btn = document.querySelector('button');
var input = document.querySelector('input');
// 2. 注册事件 处理程序
btn.onclick = function() {
// input.innerHTML = '点击了'; 这个是 普通盒子 比如 div 标签里面的内容
// 表单里面的值 文字内容是通过 value 来修改的
input.value = '被点击了';
// 如果想要某个表单被禁用 不能再点击 disabled 我们想要这个按钮 button禁用
// btn.disabled = true;
this.disabled = true;
// this 指向的是事件函数的调用者 btn
}
</script>
</body>
4.5 改变样式属性 回到顶部
行内样式操作:
element.style
类名样式操作:
element.className
案例1:
<style>
div {
width: 200px;
height: 200px;
background-color: pink;
}
</style>
-----------------------------------------
<body>
<div></div>
<script>
// 1. 获取元素
var div = document.querySelector('div');
// 2. 注册事件 处理程序
div.onclick = function() {
// div.style里面的属性 采取驼峰命名法
this.style.backgroundColor = 'purple';
div.style.width = '250px'; //div和this的都可以
}
</script>
</body>
注意:
1.JS 里面的样式采取驼峰命名法 比如 fontSize、 backgroundColor
2.JS 修改 style 样式操作,产生的是行内样式,CSS 权重比较高
3.如果样式修改较多,可以采取操作类名方式更改元素样式
4.class 因为是个保留字,因此使用className来操作元素类名属性
5.className 会直接更改元素的类名,会覆盖原先的类名
案例2:
<style>
div {
width: 100px;
height: 100px;
background-color: pink;
}
.change {
background-color: purple;
color: #fff;
font-size: 25px;
margin-top: 100px;
}
</style>
</head>
<body>
<div class="first">文本</div>
<script>
// 1. 使用 element.style 获得修改元素样式 如果样式比较少 或者 功能简单的情况下使用
var test = document.querySelector('div');
test.onclick = function() {
// this.style.backgroundColor = 'purple';
// this.style.color = '#fff';
// this.style.fontSize = '25px';
// this.style.marginTop = '100px';
// 让我们当前元素的类名改为了 change
// 2. 我们可以通过 修改元素的className更改元素的样式 适合于样式较多或者功能复杂的情况
// 3. 如果想要保留原先的类名,我们可以这么做 多类名选择器
// this.className = 'change';
this.className = 'first change';
}
</script>
</body>
总结:
4.6 排他思想 回到顶部
如果有同一组元素,我们相要某一个元素实现某种样式,需要用到循环的排他思想算法:
1、所有元素全部清除样式(干掉其他人,清除所有元素的某一样式)
2、给当前元素设置样式 (留下我自己,设置自己的样式)
3、注意顺序不能颠倒,首先干掉其他人,再设置自己
<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
<button>按钮4</button>
<button>按钮5</button>
<script>
// 1. 获取所有按钮元素
var btns = document.getElementsByTagName('button');
// btns得到的是伪数组 里面的每一个元素 btns[i]
for (var i = 0; i < btns.length; i++) {
btns[i].onclick = function() {
// (1) 我们先把所有的按钮背景颜色去掉 干掉所有人
for (var i = 0; i < btns.length; i++) {
btns[i].style.backgroundColor = '';
}
重点:这里只能用this,不能用btns[i]。因为外层循环的i只是给每一个按钮绑定事件(声明事件),并不会执行里面的代码。内外层的i在循环完后,都变成了i=5,故不可以。i成了固定值
// (2) 然后才让当前的元素背景颜色为pink 留下我自己
this.style.backgroundColor = 'pink';
}
}
//2. 首先先排除其他人,然后才设置自己的样式 这种排除其他人的思想我们成为排他思想
</script>
4.7 自定义属性
目的:保存并使用数据
4.7.1 获取自定义属性
1、获取内置属性值(元素本身自带的属性)
element.属性;
2、获取自定义的属性(自己可以添加属性,自己添加的就是自定义属性)
element.getAttribute('属性');
4.7.2 设置自定义属性值
1、设置内置属性值
element.属性 = '值';
2、主要设置自定义的属性值
element.setAttribute('属性');
4.7.3 移除属性
element.removeAttribute('属性');
综合:
var div = document.querySelector('div');
// 1. 获取元素的属性值
// (1) element.属性
console.log(div.id);
//(2) element.getAttribute('属性') get得到获取 attribute 属性的意思 我们程序员自己添加的属性我们称为自定义属性 index
console.log(div.getAttribute('id'));
console.log(div.getAttribute('index'));
// 2. 设置元素属性值
// (1) element.属性= '值'
div.id = 'test';
div.className = 'navs';
// (2) element.setAttribute('属性', '值'); 主要针对于自定义属性
div.setAttribute('index', 2);
div.setAttribute('class', 'footer'); // class 特殊 这里面写的就是class 不是className
// 3 移除属性 removeAttribute(属性)
div.removeAttribute('index');
4.8 H5自定义属性 回到顶部
自定义属性目的:
保存并保存数据,有些数据可以保存到页面中而不用保存到数据库中
注:有些自定义属性很容易引起歧义,不容易判断到底是内置属性还是自定义的,所以H5有了规定
4.8.1 设置H5自定义属性
H5规定自定义属性 data-开头作为属性名并赋值
<div data-index = "1"></>
// 或者使用JavaScript设置
div.setAttribute('data-index',1);
4.8.2 获取H5自定义属性
兼容性获取:
element.getAttribute(‘data-index’)
H5新增的:
element.dataset.index 或element.dataset[‘index’] IE11才开始支持
<body>
<div getTime="20" data-index="2" data-list-name="andy"></div>
<script>
var div = document.querySelector('div');
// console.log(div.getTime);
console.log(div.getAttribute('getTime'));
div.setAttribute('data-time', 20);
console.log(div.getAttribute('data-index'));
console.log(div.getAttribute('data-list-name'));
// h5新增的获取自定义属性的方法 它只能获取data-开头的
// dataset 是一个集合里面存放了所有以data开头的自定义属性
console.log(div.dataset);
console.log(div.dataset.index);
console.log(div.dataset['index']);
// 如果自定义属性里面有多个-链接的单词,我们获取的时候采取 驼峰命名法
console.log(div.dataset.listName);
console.log(div.dataset['listName']);
</script>
</body>
5、节点 回到顶部
获取元素通常使用两种方式:
1.利用DOM提供的方法获取元素 | 2.利用节点层级关系获取元素 |
---|---|
document.getElementById() | 利用父子兄节点关系获取元素 |
document.getElementsByTagName() | 逻辑性强,但是兼容性较差 |
document.querySelector 等 | |
逻辑性不强,繁琐 |
这两种方式都可以获取元素节点,我们后面都会使用,但是节点操作更简单
一般的,节点至少拥有三个基本属性
5.1节点概述
网页中的所有内容都是节点(标签、属性、文本、注释等),在DOM 中,节点使用 node 来表示。
HTML DOM 树中的所有节点均可通过 JavaScript 进行访问,所有 HTML 元素(节点)均可被修改,也可以创建或删除。
基本属性:
一般的,节点至少拥有nodeType(节点类型)、nodeName(节点名称)和nodeValue(节点值)这三个基本属性。
- 元素节点:nodeType 为1
- 属性节点:nodeType 为2
- 文本节点:nodeType 为3(文本节点包括文字、空格、换行等)
节点操作主要操作的是元素节点
5.2 父级节点
node.parentNode
parentNode属性
可以返回某节点的父结点,注意是最近的一个父结点- 如果指定的节点没有父结点则返回null
<body>
<!-- 节点的优点 -->
<div>我是div</div>
<span>我是span</span>
<ul>
<li>我是li</li>
<li>我是li</li>
<li>我是li</li>
<li>我是li</li>
</ul>
<div class="demo">
<div class="box">
<span class="erweima">×</span>
</div>
</div>
<script>
// 1. 父节点 parentNode
var erweima = document.querySelector('.erweima');
// var box = document.querySelector('.box');
// 得到的是离元素最近的父级节点(亲爸爸) 如果找不到父节点就返回为 null
console.log(erweima.parentNode);
</script>
</body>
5.3 子节点
parentNode.childNodes(标准)
parentNode.childNodes
返回包含指定节点的子节点的集合,该集合为即时更新的集合- 返回值包含了所有的子结点,包括元素节点,文本节点等
- 如果想获取一种的元素节点,要另处理(一般不用这个)
parentNode.children(非标准) (很重要)
- 这是一个只读属性,返回所有的子元素节点
- 它只返回子元素节点,其余节点不返回(重点)
<body>
<!-- 节点的优点 -->
<div>我是div</div>
<span>我是span</span>
<ul>
<li>我是li</li>
<li>我是li</li>
</ul>
<ol>
<li>我是li</li>
<li>我是li</li>
</ol>
<div class="demo">
<div class="box">
<span class="erweima">×</span>
</div>
</div>
<script>
// DOM 提供的方法(API)获取
var ul = document.querySelector('ul');
var lis = ul.querySelectorAll('li');
// 1. 子节点 childNodes 所有的子节点 包含 元素节点 文本节点等等
console.log(ul.childNodes);
console.log(ul.childNodes[0].nodeType);
console.log(ul.childNodes[1].nodeType);
// 2. children 获取所有的子元素节点 也是我们实际开发常用的
console.log(ul.children);
</script>
</body>
5.3.1 第一个子结点 回到顶部
parentNode.firstChild 或 parentNode.firstElementChild
前面的:(parentNode.firstChild)
1、返回第一个子节点,找不到则返回null
2、包含所有的节点
后面的:(parentNode.firstElementChild)
1、同上
2、有兼容性问题,IE9以上才支持
5.3.2 最后一个子节点
parentNode.lastChild 或 parentNode.lastElementChild
前面的:
1、返回第一个子节点,找不到则返回null
2、同样,也是包含所有的节点
后面的:
1、同上
2、有兼容性问题,IE9以上才支持
5.3.3 实际开发使用
第一个子元素节点:parentNode.chilren[0]
最后一个子元素节点:(children为伪数组,里面存的是子元素的数量)parentNode.chilren[parentNode.chilren.length - 1]
例子:
<body>
<ol>
<li>我是li1</li>
<li>我是li2</li>
<li>我是li3</li>
<li>我是li4</li>
<li>我是li5</li>
</ol>
<script>
var ol = document.querySelector('ol');
// 1. firstChild 第一个子节点 不管是文本节点还是元素节点
console.log(ol.firstChild);
console.log(ol.lastChild);
// 2. firstElementChild 返回第一个子元素节点 ie9以上才支持
console.log(ol.firstElementChild);
console.log(ol.lastElementChild);
// 3. 实际开发的写法 既没有兼容性问题又返回第一个子元素
console.log(ol.children[0]); //利用伪数组
console.log(ol.children[ol.children.length - 1]); //最后一个子元素
</script>
</body>
5.4 兄弟节点
5.4.1下一个兄弟节点
node.nextSibling 或node.nextElementSibling
- 返回当前元素的下一个兄弟节点,找不到则返回null
- 包含所有的节点
- 后者: 有兼容性问题,只返回兄弟元素节点
5.4.2 上一个兄弟节点
node.previousSibling 或node.previousElementSibling
- 返回当前元素上一个兄弟元素节点,找不到则返回null
- 包含所有的节点
- 后者: 有兼容性问题,只返回兄弟元素节点
列子:
<body>
<div>我是div</div>
<span>我是span</span>
<script>
var div = document.querySelector('div');
// 1.nextSibling 下一个兄弟节点 包含元素节点或者 文本节点等等
console.log(div.nextSibling);
console.log(div.previousSibling);
// 2. nextElementSibling 得到下一个兄弟元素节点
console.log(div.nextElementSibling);
console.log(div.previousElementSibling);
</script>
</body>
解决兼容性问题:自己封装一个兼容性的函数
function getNextElementSibling(element) {
var el = element;
while (el = el.nextSibling) {
if (el.nodeType === 1) {
return el;
}
}
return null;
}
5.5 创建节点 回到顶部
document.createElement('tagName');
- 方法创建由 tagName 指定的HTML 元素
- 因为这些元素原先不存在,是根据我们的需求动态生成的,所以我们也称为动态创建元素节点
5.5.1 添加节点
node.appendChild(child)
- 该方法将一个节点添加到指定父节点的子节点列表的末尾。类似于 CSS 里面的 after 伪元素。(子节点列表的最后面)
node.insertBefore(child,指定元素)
- 该方法将一个节点添加到父节点的指定子节点前面。类似于 CSS 里面的 before 伪元素。(子节点列表的最前面)
创建和添加元素示例:
<body>
<ul>
<li>123</li>
</ul>
<script>
// 1. 创建节点元素节点
var li = document.createElement('li');
// 2. 添加节点 node.appendChild(child) node 父级 child 是子级 后面追加元素 类似于数组中的push
var ul = document.querySelector('ul');
ul.appendChild(li);
// 3. 添加节点 node.insertBefore(child, 指定元素);
var lili = document.createElement('li');
ul.insertBefore(lili, ul.children[0]);
// 4. 我们想要页面添加一个新的元素 : 1. 创建元素 2. 添加元素
</script>
</body>
5.5.2 删除节点
node.removeChild(child)
- 该方法从 DOM 中删除一个子节点,返回删除的节点
5.5.3 克隆节点 回到顶部
node.cloneNode()
- 返回调用该方法的节点的一个副本。 也称为克隆节点/拷贝节点
- 如果括号参数为空或者为 false ,则是浅拷贝,即只克隆复制节点本身,不克隆里面的子节点
- 如果括号参数为 true ,则是深度拷贝,会复制节点本身以及里面所有的子节点
<body>
<ul>
<li>1111</li>
<li>2</li>
<li>3</li>
</ul>
<script>
var ul = document.querySelector('ul');
// 1. node.cloneNode(); 括号为空或者里面是false 浅拷贝 只复制标签不复制里面的内容
// 2. node.cloneNode(true); 括号为true 深拷贝 复制标签复制里面的内容
var lili = ul.children[0].cloneNode(true);
ul.appendChild(lili);
</script>
</body>
-------
5.5.4 三种动态创建元素的区别
- doucument.write()
- element.innerHTML()
- document.createElement()
区别:
doucument.write()
直接将内容写入页面的内容流,但是文档流执行完毕,则它会导致页面全部重绘
element.innerHTML()
将内容写入某个 DOM 节点,不会导致页面全部重绘
element.innerHTML()
创建多个元素效率更高(不要拼接字符串,采取数组形式拼接),结构稍微复杂
document.createElement()
创建多个元素效率稍低一点点,但是结构更清晰
<script>
// window.onload = function() {
// document.write('<div>123</div>');
// }
// 1. innerHTML 创建元素
var inner = document.querySelector('.inner');
for (var i = 0; i <= 100; i++) {
inner.innerHTML += '<a href="#">百度</a>'
} //创建100个a标签,创造多个元素时,效率高
var arr = [];
for (var i = 0; i <= 100; i++) {
arr.push('<a href="#">百度</a>');
} //效率不同,效率最高(不拼接字符串)
inner.innerHTML = arr.join('');
// 2. document.createElement() 创建元素 //慢些
var create = document.querySelector('.create');
for (var i = 0; i <= 100; i++) {
var a = document.createElement('a');
create.appendChild(a);
}
</script>
总结:
不同浏览器下, innerHTML 效率要比 createElement 高
6、DOM核心 回到顶部
对于DOM操作,我们主要是操作子元素
创建,增,删,改,查,属性操作,时间操作。
6.1创建
- document.write
- innerHTML
- createElement
6.2 增
- appendChild
- insertBefore
6.3 删
- removeChild
6.4 改
主要修改dom的元素属性,dom元素的内容、属性、表单的值等
1、 修改元素属性:src、href、title 等
2、 修改普通元素内容:innerHTML、innerText
3、 修改表单元素:value、type、disabled
4、 修改元素样式:style、className
6.5 查
- DOM提供的API方法:getElementById、 getElementsByTagName (古老用法,不推荐)
- H5提供的新方法:querySelector、querySelectorAll (提倡)
- 利用节点操作获取元素:父(parentNode)、子(children)、兄(previousElementSibling、nextElementSibling) 提倡
6.5 属性操作
- 主要针对于自定义属性
- setAttribute:设置dom的属性值
- getAttribute:得到dom的属性值
- removeAttribute:移除属性
7、事件高级 回到顶部
7.1 注册事件(绑定事件)
给元素添加事件,称为注册事件或者绑定事件。
注册事件有两种方式:传统方式和方法监听注册方式。
传统注册方式 | 方法监听注册方式 |
---|---|
利用 on 开头的事件 onclick | w3c 标准推荐方式 |
<button onclick = “alert(“hi”)”> | addEventListener() 它是一个方法 |
btn.onclick = function() {} | IE9 之前的 IE 不支持此方法,可使用 attachEvent() 代替 |
特点:注册事件的唯一性 | 特点:同一个元素同一个事件可以注册多个监听器 |
同一个元素同一个事件只能设置一个处理函数,最后注册的处理函数将会覆盖前面注册的处理函数 | 按注册顺序依次执行 |
7.1.1 addEventListener事件监听方式(重点)
eventTarget.addEventListener()
方法将指定的监听器注册到 eventTarget(目标对象)上。
当该对象触发指定的事件时,就会执行事件处理函数
eventTarget.addEventListener(type,listener[,useCapture])
三个参数: 查看常见的鼠标事件
- type:事件类型字符串,比如click,mouseover,注意这里不要带on
- listener:事件处理函数,事件发生时,会调用该监听函数
- useCapture:可选参数,是一个布尔值,默认是 false。学完 DOM 事件流后,我们再进一步学习
<body>
<button>传统注册事件</button>
<button>方法监听注册事件</button>
<button>ie9 attachEvent</button>
<script>
var btns = document.querySelectorAll('button');
// 1. 传统方式注册事件
btns[0].onclick = function() {
alert('hi');
}
btns[0].onclick = function() {
alert('hao a u');
} //只弹出hao a u
// 2. 事件侦听注册事件 addEventListener
// (1) 里面的事件类型是字符串 必定加引号 而且不带on
// (2) 同一个元素 同一个事件可以添加多个侦听器(事件处理程序)
btns[1].addEventListener('click', function() {
alert(22);
})
btns[1].addEventListener('click', function() {
alert(33); //先弹出22后弹出33
})
// 3. attachEvent ie9以前的版本支持
btns[2].attachEvent('onclick', function() {
alert(11);
})
</script>
</body>
7.1.2 addEvent 事件监听方式(兼容ie8及以前)
eventTarget.addEventListener()方法将指定的监听器注册到 eventTarget(目标对象)上
当该对象触发指定的事件时,就会执行事件处理函数
eventTarget.attachEvent(eventNameWithOn, callback)
两个参数:
- eventNameWithOn:事件类型字符串,比如 onclick 、onmouseover ,这里要带 on
- callback: 事件处理函数,当目标触发事件时回调函数被调用
7.1.3 注册事件兼容性解决方案
兼容性处理的原则:首先照顾大多数浏览器,再处理特殊浏览器
function addEventListener(element, eventName, fn) {
// 判断当前浏览器是否支持 addEventListener 方法
if (element.addEventListener) {
element.addEventListener(eventName, fn); // 第三个参数 默认是false
} else if (element.attachEvent) {
element.attachEvent('on' + eventName, fn);
} else {
// 相当于 element.onclick = fn;
element['on' + eventName] = fn;
}
7.2 删除事件(解绑事件) 回到顶部
7.2.1 removeEventListener删除事件方式
eventTarget.removeEventListener(type,listener[,useCapture]);
三个参数:
- type:事件类型字符串,比如click,mouseover,注意这里不要带on
- listener:事件处理函数,事件发生时,会调用该监听函数
- useCapture:可选参数,是一个布尔值,默认是 false。学完 DOM 事件流后,我们再进一步学习
7.2.2 detachEvent删除事件方式(兼容)
eventTarget.detachEvent(eventNameWithOn,callback);
两个参数:
- eventNameWithOn:事件类型字符串,比如 onclick 、onmouseover ,这里要带 on
- callback:事件处理函数,当目标触发事件时回调函数被调用
- ie9以前的版本支持
7.2.3 传统事件删除方式
eventTarget.onclick = null;
示例:
<body>
<div>1</div>
<div>2</div>
<div>3</div>
<script>
var divs = document.querySelectorAll('div');
divs[0].onclick = function() {
alert(11);
// 1. 传统方式删除事件
divs[0].onclick = null;
}
// 2. removeEventListener 删除事件
divs[1].addEventListener('click', fn) // 里面的fn 不需要调用加小括号
function fn() {
alert(22);
divs[1].removeEventListener('click', fn);
}
// 3. detachEvent
divs[2].attachEvent('onclick', fn1);
function fn1() {
alert(33);
divs[2].detachEvent('onclick', fn1);
}
</script>
</body>
7.2.4 删除事件兼容性解决方案
function removeEventListener(element, eventName, fn) {
// 判断当前浏览器是否支持 removeEventListener 方法
if (element.removeEventListener) {
element.removeEventListener(eventName, fn); // 第三个参数 默认是false
} else if (element.detachEvent) {
element.detachEvent('on' + eventName, fn);
} else {
element['on' + eventName] = null;
}
7.3 DOM事件流
- 事件流描述的是从页面中接收事件的顺序
- 事件发生时会在元素节点之间按照特定的顺序传播,这个传播过程即DOM事件流
- 事件冒泡: IE 最早提出,事件开始时由最具体的元素接收,然后逐级向上传播到到 DOM 最顶层节点的过程。
- 事件捕获: 网景最早提出,由 DOM 最顶层节点开始,然后逐级向下传播到到最具体的元素接收的过程。
形象比喻:
我们向水里面扔一块石头,首先它会有一个下降的过程,这个过程就可以理解为从最顶层向事件发生的最具体元素(目标点)的捕获过程;之后会产生泡泡,会在最低点( 最具体元素)之后漂浮到水面上,这个过程相当于事件冒泡。
7.3.1 捕获阶段
document -> html -> body -> father -> son
先来看个例子:
两个盒子嵌套,一个父盒子一个子盒子,我们的需求是当点击父盒子时弹出 father ,当点击子盒子时弹出 son
<body>
<div class="father">
<div class="son">son盒子</div>
</div>
<script>
// dom 事件流 三个阶段
// 1. JS 代码中只能执行捕获或者冒泡其中的一个阶段。
// 2. onclick 和 attachEvent(ie) 只能得到冒泡阶段。
// 3. 捕获阶段 如果addEventListener 第三个参数是 true 那么则处于捕获阶段 document -> html -> body -> father -> son
var son = document.querySelector('.son');
son.addEventListener('click', function() {
alert('son');
}, true);
var father = document.querySelector('.father');
father.addEventListener('click', function() {
alert('father');
}, true);
捕获阶段:以上代码的结果:点击子元素,先弹出“father”,关掉后,再弹出“son”。(最开始检查document是否监听,一次向下检查,由于DOM流的影响)
这是因为捕获阶段由 DOM 最顶层节点开始,然后逐级向下传播到到最具体的元素接收
- document -> html -> body -> father -> son
- 先看 document 的事件,没有;再看 html 的事件,没有;再看 body 的事件,没有;再看 father 的事件,有就先执行;再看 son 的事件,再执行。
7.3.2 冒泡阶段
- son -> father ->body -> html -> document
同理:冒泡则是反过来的,先检查son是否有监听器后依次向上检查。
addEventListener 第三个参数是 false 或 省略,则处于冒泡阶段。第三个参数为true则为捕获阶段
<body>
<div class="father">
<div class="son">son盒子</div>
</div>
<script>
// 4. 冒泡阶段 如果addEventListener 第三个参数是 false 或者 省略 那么则处于冒泡阶段 son -> father ->body -> html -> document
var son = document.querySelector('.son');
son.addEventListener('click', function() {
alert('son');
}, false);
var father = document.querySelector('.father');
father.addEventListener('click', function() {
alert('father');
}, false);
document.addEventListener('click', function() {
alert('document');
})
</script>
</body>
我们点击子盒子,会依次弹出 son、father、document的提示框。
这是因为冒泡阶段开始时由最具体的元素接收,然后逐级向上传播到到 DOM 最顶层节点
- son -> father ->body -> html -> document
总结:
- JS 代码中只能执行捕获或者冒泡其中的一个阶段
onclick
和attachEvent
只能得到冒泡阶段addEventListener(type,listener[,useCapture])
第三个参数 | 阶段 |
---|---|
true | 捕获阶段 |
false 或 不写 | 冒泡阶段 |
- 实际开发中我们很少使用事件捕获,我们更关注事件冒泡。
- 有些事件是没有冒泡的,比如 onblur、onfocus、onmouseenter、onmouseleave
7.4 事件对象 回到顶部
eventTarget.onclick = function(event) {}
eventTarget.addEventListener('click', function(event) {})
// 这个 event 就是事件对象,我们还喜欢的写成 e 或者 evt
-.①.-官方解释:
event 对象代表事件的状态,比如键盘按键的状态、鼠标的位置、鼠标按钮的状态。
-.②.-简单理解:
事件发生后,跟事件相关的一系列信息数据的集合都放到这个对象里面,这个对象就是事件对象
event,它有很多属性和方法:
- 谁绑定了这个事件
- 鼠标触发事件的话,会得到鼠标的相关信息,如鼠标位置
- 键盘触发事件的话,会得到键盘的相关信息,如按了哪个键
+.③.+这个 event 是个形参,系统帮我们设定为事件对象,不需要传递实参过去。
+.④.+当我们注册事件时, event 对象就会被系统自动创建,并依次传递给事件监听器(事件处理函数)
<body>
<div>123</div>
<script>
// 事件对象
var div = document.querySelector('div');
div.onclick = function(e) {
// console.log(e);
// console.log(window.event);
// e = e || window.event;
console.log(e);
}
// div.addEventListener('click', function(e) {
// console.log(e);
// })
// 1. event 就是一个事件对象 写到我们侦听函数的 小括号里面 当形参来看
// 2. 事件对象只有有了事件才会存在,它是系统给我们自动创建的,不需要我们传递参数
// 3. 事件对象 是 我们事件的一系列相关数据的集合 跟事件相关的 比如鼠标点击里面就包含了鼠标的相关信息,鼠标坐标啊,如果是键盘事件里面就包含的键盘事件的信息 比如 判断用户按下了那个键
// 4. 这个事件对象我们可以自己命名 比如 event 、 evt、 e
// 5. 事件对象也有兼容性问题 ie678 通过 window.event 兼容性的写法 e = e || window.event;
</script>
</body>
7.4.1 兼容性方案
事件对象本身的获取存在兼容问题:
- 标准浏览器中是浏览器给方法传递的参数,只需要定义形参 e 就可以获取到。
- 在 IE6~8 中,浏览器不会给方法传递参数,如果需要的话,需要到 window.event 中获取查找
解决兼容性问题的代码:
e = e || window.event;
7.4.2 事件对象的常见属性和方法
事件对象属性方法 | 说明 |
---|---|
e.target | 返回触发事件的对象 标准 |
e.srcElement | 返回触发事件的对象 非标准 ie6-8使用 |
e.type | 返回事件的类型 比如click mouseover 不带on |
e.cancelBubble | 该属性阻止冒泡,非标准,ie6-8使用 |
e.returnValue | 该属性阻止默认行为 非标准,ie6-8使用 |
e.preventDefault() | 该方法阻止默认行为 标准 比如不让链接跳转 |
e.stopPropagation() | 阻止冒泡 标准 |
e.target 和 this 的区别:
- this 是事件绑定的元素, 这个函数的调用者(绑定这个事件的元素)
- e.target 是事件触发的元素。
<body>
<div>123</div>
<ul>
<li>abc</li>
<li>abc</li>
<li>abc</li>
</ul>
<script>
// 1. e.target 返回的是触发事件的对象(元素) this 返回的是绑定事件的对象(元素)
// 区别 : e.target 点击了那个元素,就返回那个元素 this 那个元素绑定了这个点击事件,那么就返回谁
var div = document.querySelector('div');
div.addEventListener('click', function(e) {
console.log(e.target); //<div>123</div>
console.log(this);//<div>123</div>
})
var ul = document.querySelector('ul');
ul.addEventListener('click', function(e) {
// 我们给ul 绑定了事件 那么this 就指向ul
console.log(this); //<ul>...</ul>
console.log(e.currentTarget);//<li>abc</li>
// e.target 指向我们点击的那个对象 谁触发了这个事件 我们点击的是li e.target 指向的就是li
console.log(e.target);
})
</script>
</body>
7.5 事件对象阻止默认行为
利用:
e.preventDefault()
标准写法returnValue
非标准写法:低版本浏览器 ie678 returnValue 属性
示例:
<body>
<div>123</div>
<a href="http://www.baidu.com">百度</a>
<form action="http://www.baidu.com">
<input type="submit" value="提交" name="sub">
</form>
<script>
// 常见事件对象的属性和方法
// 1. 返回事件类型
var div = document.querySelector('div');
div.addEventListener('click', fn);
div.addEventListener('mouseover', fn);
div.addEventListener('mouseout', fn);
function fn(e) {
console.log(e.type);
}
// 2. 阻止默认行为(事件) 让链接不跳转 或者让提交按钮不提交
var a = document.querySelector('a');
a.addEventListener('click', function(e) {
e.preventDefault(); // dom 标准写法
})
// 3. 传统的注册方式
a.onclick = function(e) {
// 普通浏览器 e.preventDefault(); 方法
// e.preventDefault();
// 低版本浏览器 ie678 returnValue 属性
// e.returnValue;
// 我们可以利用return false 也能阻止默认行为 没有兼容性问题 特点: return 后面的代码不执行了, 而且只限于传统的注册方式
return false;
alert(11);
}
</script>
</body>
7.6 阻止事件冒泡
- 标准写法
e.stopPropagation();
- 非标准写法: IE6-8 利用对象事件 cancelBubble属性
e.cancelBubble = true;
代码示例:
<body>
<div class="father">
<div class="son">son儿子</div>
</div>
<script>
// 常见事件对象的属性和方法
// 阻止冒泡 dom 推荐的标准 stopPropagation()
var son = document.querySelector('.son');
son.addEventListener('click', function(e) {
alert('son');
e.stopPropagation(); // stop 停止 Propagation 传播
e.cancelBubble = true; // 非标准 cancel 取消 bubble 泡泡
}, false);
var father = document.querySelector('.father');
father.addEventListener('click', function() {
alert('father');
}, false);
document.addEventListener('click', function() {
alert('document');
})
</script>
</body>
7.7 事件委托
- 事件委托也称为事件代理,在 jQuery 里面称为事件委派
- 目的:提高执行代码效率
- 事件委托的原理
- 不是每个子节点单独设置事件监听器,而是事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点
<body>
<ul>
<li>知否知否,点我应有弹框在手!</li>
<li>知否知否,点我应有弹框在手!</li>
<li>知否知否,点我应有弹框在手!</li>
<li>知否知否,点我应有弹框在手!</li>
<li>知否知否,点我应有弹框在手!</li>
</ul>
<script>
// 事件委托的核心原理:给父节点添加侦听器, 利用事件冒泡影响每一个子节点
var ul = document.querySelector('ul');
ul.addEventListener('click', function(e) {
// alert('知否知否,点我应有弹框在手!');
// e.target 这个可以得到我们点击的对象
e.target.style.backgroundColor = 'pink';
// 点了谁,就让谁的style里面的backgroundColor颜色变为pink
})
</script>
</body>
以上案例:给 ul 注册点击事件,然后利用事件对象的 target 来找到当前点击的 li,因为点击 li,事件会冒泡到 ul 上, ul 有注册事件,就会触发事件监听器。
7.8 常见的鼠标事件 回到顶部
鼠标事件 | 触发条件 |
---|---|
onclick | 鼠标点击左键触发 |
onmouseover | 鼠标经过触发 |
onmouseout | 鼠标离开触发 |
onfocus | 获得鼠标焦点触发 |
onblur | 失去鼠标焦点触发 |
onmousemove | 鼠标移动触发 |
onmouseup | 鼠标弹起触发 |
onmousedown | 鼠标按下触发 |
7.8.1 禁止鼠标右键与鼠标选中
contextmenu
主要控制应该何时显示上下文菜单,主要用于程序员取消默认的上下文菜单selectstart
禁止鼠标选中
<body>
<h1>我是一段不愿意分享的文字</h1>
<script>
// 1. contextmenu 我们可以禁用右键菜单
document.addEventListener('contextmenu', function(e) {
e.preventDefault(); // 阻止默认行为
})
// 2. 禁止选中文字 selectstart
document.addEventListener('selectstart', function(e) {
e.preventDefault();
})
</script>
</body>
7.8.2 鼠标事件对象
- event对象代表事件的状态,跟事件相关的一系列信息的集合
- 现阶段我们主要是用鼠标事件对象 MouseEvent 和键盘事件对象 KeyboardEvent。
鼠标事件对象 | 说明 |
---|---|
e.clientX | 返回鼠标相对于浏览器窗口可视区的X坐标 |
e.clientY | 返回鼠标相对于浏览器窗口可视区的Y坐标 |
e.pageX(重点) | 返回鼠标相对于文档页面的X坐标 IE9+ 支持 |
e.pageY(重点) | 返回鼠标相对于文档页面的Y坐标 IE9+ 支持 |
e.screenX | 返回鼠标相对于电脑屏幕的X坐标 |
e.screenY | 返回鼠标相对于电脑屏幕的Y坐标 |
相对于可视窗:
相对于文档页面:
<body>
<script>
// 鼠标事件对象 MouseEvent
document.addEventListener('click', function(e) {
// 1. client 鼠标在可视区的x和y坐标
console.log(e.clientX);
console.log(e.clientY);
console.log('---------------------');
// 2. page 鼠标在页面文档的x和y坐标,相对于其他,更重要
console.log(e.pageX);
console.log(e.pageY);
console.log('---------------------');
// 3. screen 鼠标在电脑屏幕的x和y坐标
console.log(e.screenX);
console.log(e.screenY);
})
</script>
</body>
7.9 常见的键盘事件
键盘事件 | 触发条件 |
---|---|
onkeyup | 某个键盘按键被松开时触发 |
onkeydown | 某个键盘按键被按下时触发 |
onkeypress | 某个键盘按键被按下时触发,但是它不识别功能键,比如 ctrl shift 箭头等 |
- 如果使用addEventListener 不需要加 on
onkeypress
和前面2个的区别是,它不识别功能键,比如左右箭头,shift 等- 三个事件的执行顺序是: keydown –》 keypress —》 keyup
<body>
<script>
// 常用的键盘事件
//1. keyup 按键弹起的时候触发
// document.onkeyup = function() {
// console.log('我弹起了');
// }
document.addEventListener('keyup', function() {
console.log('我弹起了');
})
//3. keypress 按键按下的时候触发 不能识别功能键 比如 ctrl shift 左右箭头啊
document.addEventListener('keypress', function() {
console.log('我按下了press');
})
//2. keydown 按键按下的时候触发 能识别功能键 比如 ctrl shift 左右箭头啊
document.addEventListener('keydown', function() {
console.log('我按下了down');
})
// 4. 三个事件的执行顺序 keydown -- keypress -- keyup
</script>
</body>
键盘对象属性
键盘事件对象 属性 | 说明 |
---|---|
keyCode | 返回该键值的ASCII值 |
onkeydown
和onkeyup
不区分字母大小写,onkeypress
区分字母大小写。- 在我们实际开发中,我们更多的使用keydown和keyup, 它能识别所有的键(包括功能键)
Keypress
不识别功能键,但是keyCode
属性能区分大小写,返回不同的ASCII值
<body>
<script>
// 键盘事件对象中的keyCode属性可以得到相应键的ASCII码值
// 1. 我们的keyup 和keydown事件不区分字母大小写 a 和 A 得到的都是65
// 2. 我们的keypress 事件 区分字母大小写 a 97 和 A 得到的是65
document.addEventListener('keyup', function(e) {
console.log('up:' + e.keyCode);
// 我们可以利用keycode返回的ASCII码值来判断用户按下了那个键
if (e.keyCode === 65) {
alert('您按下的a键');
} else {
alert('您没有按下a键')
}
})
document.addEventListener('keypress', function(e) {
console.log('press:' + e.keyCode);
})
</script>
</body>
六、BOM 回到顶部
1.BOM概述
- BOM(Browser Object Model)即浏览器对象模型
- 它提供了独立于内容而与浏览器窗口进行交互的对象,其核心对象是 window。
- BOM 由一系列相关的对象构成,并且每个对象都提供了很多方法与属性。
- BOM 缺乏标准,JavaScript 语法的标准化组织是 ECMA,DOM 的标准化组织是 W3C,BOM 最初是Netscape 浏览器标准的一部分。
DOM | BOM |
---|---|
文档对象模型 | 浏览器对象模型 |
DOM 就是把 文档 当作一个对象来看待 | 把 浏览器当作一个对象来看待 |
DOM 的顶级对象是 document | BOM 的顶级对象是 window |
DOM 主要学习的是操作页面元素 | BOM 学习的是浏览器窗口交互的一些对象 |
DOM 是 W3C 标准规范 | BOM 是浏览器厂商在各自浏览器上定义的,兼容性较差 |
1.1BOM的构成
- window 对象是浏览器的顶级对象,它具有双重角色
1、 它是 JS 访问浏览器窗口的一个接口
2、它是一个全局对象。定义在全局作用域中的变量、函数都会变成 window 对象的属性和方法。
在调用的时候可以省略 window,前面学习的对话框都属于 window 对象方法,如 alert
注意:window下的一个特殊属性 window.name
<body>
<script>
// window.document.querySelector()
var num = 10;
console.log(num); //结果一样。全局变量会变成window对象的属性
console.log(window.num);//10
----------------------------------------------------------
function fn() { //全局方法也会变成window对象的方法
console.log(11);
}//11
console.dir(window);
// var name = 10; name为window下的特殊属性,不能自己命名一个
console.log(window.name);
</script>
</body>
2.window 对象的常见事件 回到顶部
2.1 窗口加载事件
window.onload
是窗口(页面)加载事件,当文档内容完全加载完成会触发该事件(包括图像,脚本文件,CSS文件等),就调用的处理函数。
window.onload = function(){ //传统注册方式一
};
// 或者,使用监听器(用得最多),方式二
window.addEventListener("load",function(){});
一些注意点:
- 有了
window.onload
就可以把JS代码写到页面元素的上方 window.onload
传统注册事件方式,只能写一次- 如果有多个,会以最后一个
window.onload
为准 - 如果使用
addEventListener
(监听器) 则没有限制
方式三:
document.addEventListener('DOMContentLoaded',function(){})
两个参数:
DOMCountentLoaded
事件触发时,仅当DOM加载完成,不包括样式表,图片,flash等等- 使用场景:如果页面的图片很多的话, 从用户访问到onload触发可能需要较长的时间
- 交互效果就不能实现,必然影响用户的体验,此时用
DOMContentLoaded
事件比较合适。
2.1.1两种方法的区别
load
等页面内容全部加载完毕,包括页面dom元素,图片,flash,css等DOMContentLoaded
是DOM加载完毕,不包含图片 flash css 等就可以执行,加载速度比load更快一些
<script>
// window.onload = function() {
// var btn = document.querySelector('button');
// btn.addEventListener('click', function() {
// alert('点击我');
// })
// }
// window.onload = function() {
// alert(22);
// }
window.addEventListener('load', function() {
var btn = document.querySelector('button');
btn.addEventListener('click', function() {
alert('点击我');
})
})
window.addEventListener('load', function() {
alert(22);
})
document.addEventListener('DOMContentLoaded', function() {
alert(33);
})
// load 等页面内容全部加载完毕,包含页面dom元素 图片 flash css 等等
// DOMContentLoaded 是DOM 加载完毕,不包含图片 falsh css 等就可以执行 加载速度比 load更快一些
</script>
<body>
<button>点击</button>
</body>
2.2调整窗口大小事件
window.onresize
是调整窗口大小加载事件,当触发时就调用的处理函数
window.onresize = function() {} //传统方式
// 或者 监听器
window.addEventListener('resize',function(){});
- 只要窗口大小像素发生变化,就会触发这个事件
- 我们经常利用这个事件完成响应式布局。
window.innerWidth
当前屏幕的宽度window.innerheight
当前屏幕的高度
<body>
<script> //在body里,即要等页面加载完毕。再执行
window.addEventListener('load', function() {
var div = document.querySelector('div');
window.addEventListener('resize', function() {
console.log(window.innerWidth);
console.log('变化了'); //当屏幕像素宽度小于800像素,则该盒子(div)隐藏。
if (window.innerWidth <= 800) {
div.style.display = 'none';
} else {
div.style.display = 'block';
}
})
})
</script>
<div></div>
</body>
3.定时器 回到顶部
window 对象给我们提供了两个定时器
第一种:
setTimeout()
第二种:
setInterval()
3.1 setTimeout()定时器
setTimeout()
方法用于设置一个定时器,该定时器在定时器到期后执行调用函数。
window.setTimeout(调用函数,[延迟的毫秒数]);
一些注意点:
- window可以省略
- 调用函数:
- 可以直接写函数
- 可以写函数名
- 可以采取字符串 ‘函数名()’ (不推荐) - 延迟的毫秒数省略默认是0,如果写,必须是毫秒
- 因为定时器可能有很多,所以我们经常给定时器赋值一个标识符
setTimeout()
这个调用函数我们也称为回调函数 callback- 普通函数是按照代码顺序直接调用,而这个函数,需要等待事件,事件到了才会去调用这个函数,因此称为回调函数。
<body>
<script>
// 1. setTimeout
// 语法规范: window.setTimeout(调用函数, 延时时间);
// 1. 这个window在调用的时候可以省略
// 2. 这个延时时间单位是毫秒 但是可以省略,如果省略默认的是0
// 3. 这个调用函数可以直接写函数 还可以写 函数名 还有一个写法 '函数名()'
// 4. 页面中可能有很多的定时器,我们经常给定时器加标识符 (名字)
// setTimeout(function() {
// console.log('时间到了');
// }, 2000);
function callback() {
console.log('爆炸了');
}
var timer1 = setTimeout(callback, 3000);
var timer2 = setTimeout(callback, 5000);
// setTimeout('callback()', 3000); // 我们不提倡这个写法
</script>
</body>
3.2 clearTimeout()停止定时器 回到顶部
clearTimeout()
方法取消了定时器 ( 先前通过调用setTimeout()
建立的定时器)
window.clearTimeout(timeoutID)
注意:
window
可以省略- 里面的参数就是定时器的标识符
<body>
<button>点击停止定时器</button>
<script>
var btn = document.querySelector('button');
var timer = setTimeout(function() {
console.log('爆炸了');
}, 5000);
btn.addEventListener('click', function() {
clearTimeout(timer);
})
</script>
</body>
3.3 setInterval()定时器
setInterval()
方法重复调用一个函数,每隔这个时间,就去调用一次回调函数
window.setInterval(回调函数,[间隔的毫秒数]);
-
window可以省略
-
这个回调函数:
- 可以直接写函数
- 或者写函数名
- 或者采取字符 ‘函数名()’
-
第一次执行也是间隔毫秒数之后执行,之后每隔毫秒数就执行一次
<body>
<script>
// 1. setInterval
// 语法规范: window.setInterval(调用函数, 延时时间);
setInterval(function() {
console.log('继续输出');
}, 1000);
// 2. setTimeout 延时时间到了,就去调用这个回调函数,只调用一次 就结束了这个定时器
// 3. setInterval 每隔这个延时时间,就去调用这个回调函数,会调用很多次,重复调用这个函数
</script>
</body>
3.4 clearInterval()停止定时器
clearInterval()
取消定时器(由setInterval()建立的定时器)
注意:
window
可以省略- 里面的参数就是定时器的标识符
<body>
<button class="begin">开启定时器</button>
<button class="stop">停止定时器</button>
<script>
var begin = document.querySelector('.begin');
var stop = document.querySelector('.stop');
var timer = null; // 全局变量 null是一个空对象
begin.addEventListener('click', function() {
timer = setInterval(function() {
console.log('ni hao ma');
}, 1000);
})
stop.addEventListener('click', function() {
clearInterval(timer);
})
</script>
</body>
3.5 this指向
this
的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁
现阶段,我们先了解一下几个this指向
重点- 全局作用域或者普通函数中
this
指向全局对象window
(注意定时器里面的this指向window)—|---(window.fn window.setTimeout等等,window省略) - 方法调用中谁调用
this
指向谁 - 构造函数中
this
指向构造函数实例,对象里的this
指向自己
<body>
<button>点击</button>
<script>
// this 指向问题 一般情况下this的最终指向的是那个调用它的对象
// 1. 全局作用域或者普通函数中this指向全局对象window( 注意定时器里面的this指向window)
console.log(this);
function fn() {
console.log(this);
}
window.fn();
window.setTimeout(function() {
console.log(this);
}, 1000);
// 2. 方法调用中谁调用this指向谁
var o = {
sayHi: function() {
console.log(this); // this指向的是 o 这个对象
}
}
o.sayHi();
var btn = document.querySelector('button');
// btn.onclick = function() {
// console.log(this); // this指向的是btn这个按钮对象
// }
btn.addEventListener('click', function() {
console.log(this); // this指向的是btn这个按钮对象
})
// 3. 构造函数中this指向构造函数的实例
function Fun() {
console.log(this); // this 指向的是fun 实例对象
}
var fun = new Fun();
</script>
</body>
4.JS执行机制 回到顶部
4.1 JS是单线程
- JavaScript 语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。这是因为 Javascript 这门脚本语言诞生的使命所致——JavaScript 是为处理页面中用户的交互,以及操作 DOM 而诞生的。比如我们对某个 DOM 元素进行添加和删除操作,不能同时进行。 应该先进行添加,之后再删除。
- 单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。这样所导致的问题是: 如果 JS 执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞的感觉。
4.2 同步和异步
-
为了解决这个问题,利用多核 CPU 的计算能力,HTML5 提出 Web Worker 标准,允许 JavaScript 脚本创建多个线程
-
于是,JS 中出现了同步和异步。
-
同步:
- 前一个任务结束后再执行后一个任务 -
异步:
- 在做这件事的同时,你还可以同时去处理其他事情 -
同步任务:
- 同步任务都在主线程上执行,形成一个 执行栈 -
异步任务:
-
JS中的异步是通过回调函数实现的
-
异步任务有以下三种类型
- 普通事件,如click
,resize
等
- 资源加载,如load
,error
等
- 定时器,包括setInterval
,setTimeout
等(这些定时器为同步任务,定时器里的回调函数是异步任务) -
异步任务相关回调函数添加到任务队列中
执行顺序:
1、 先执行 执行栈 中的同步任务。
2、异步任务(回调函数)放入任务队列中
3、一旦执行栈中的所有同步任务执行完毕,系统就会按次序读取任务队列中的异步任务,于是被读取的异步任务结束等待状态,进入执行栈,开始执行
例子1:
console.log(1);
setTimeout(function() {
console.log(3);
},1000);
console.log(2); //结果为:1、2、3
例子2:
console.log(1);
setTimeout(function() {
console.log(3);
},0);
console.log(2); //结果为:1、2、3
例子3:
console.log(1);
document.onclick = function() { //若未点击,则为1、2、3(3为等3秒后出现)
console.log('click');
}
console.log(2); //若点击,且在三秒后点击,结果为1、2、3、click(点一
setTimeout(function() { //下一个就有click)
console.log(3)
}, 3000) //若在3秒内点击,结果为1、2、click(可有多个,多点几
//下)、3、(click)(后面可以继续点击)
事件循环:由于主线程不断的重复获得任务、执行任务、再获取任务、再执行,所以这种机制被称为事件循环( event loop)
5.location对象 回到顶部
- window 对象给我们提供了一个
location
属性用于获取或者设置窗体的url,并且可以解析url。因为这个属性返回的是一个对象,所以我们将这个属性也称为 location 对象。
5.1 url
统一资源定位符(uniform resouce locator)是互联网上标准资源的地址。互联网上的每个文件都有一个唯一的 URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它。
url 的一般语法格式为:
protocol://host[:port]/path/[?query]#fragment
http://www.itcast.cn/index.html?name=andy&age=18#link
组成 | 说明 |
---|---|
protocol | 通信协议 常用的http,ftp,maito等 |
host | 主机(域名) www.itheima.com |
port | 端口号,可选 |
path | 路径 由零或多个’/'符号隔开的字符串 |
query | 参数 以键值对的形式,通过&符号分隔开来 |
fragment | 片段 #后面内容 常见于链接 锚点 |
5.2 location对象属性
location对象属性 | 返回值 |
---|---|
location.host | 返回主机(域名)www.baidu.com |
location.href | 获取或者设置整个URL |
location.port | 返回端口号,如果未写返回空字符串 |
location.pathname | 返回路径 |
location.search | 返回参数 |
location.hash | 返回片段 #后面内容常见于链接 锚点 |
href 和 search
例子1(5秒后跳转页面):
<body>
<button>点击</button>
<div></div>
<script>
var btn = document.querySelector('button');
var div = document.querySelector('div');
var timer = 5;
setInterval(function() {
if (timer == 0) {
location.href = 'http://www.itcast.cn';
} else {
div.innerHTML = '您将在' + timer + '秒钟之后跳转到首页';
timer--;
}
}, 1000);
</script>
</body>
5.3 location对象方法
location对象方法 | 返回值 |
---|---|
location.assign() | 跟href一样,可以跳转页面(也称为重定向页面) |
location.replace() | 替换当前页面,因为不记录历史,所以不能后退页面 |
location.reload() | 重新加载页面,相当于刷新按钮或者 f5 ,如果参数为true 强制刷新 ctrl+f5 |
<body>
<button>点击</button>
<script>
var btn = document.querySelector('button');
btn.addEventListener('click', function() {
// 记录浏览历史,所以可以实现后退功能
// location.assign('http://www.itcast.cn');
// 不记录浏览历史,所以不可以实现后退功能
// location.replace('http://www.itcast.cn');
location.reload(true);
})
</script>
</body>
5.4 获取URL参数
我们写一个网页,有登录框的,点击登录跳转到 index.html
<body>
<form action="index.html">
用户名: <input type="text" name="uname">
<input type="submit" value="登录">
</form>
</body>
再写index.html
<body>
<div></div>
<script>
console.log(location.search); // ?uname=andy
// 1.先去掉? substr('起始的位置',截取几个字符);
var params = location.search.substr(1); // uname=andy
console.log(params);
// 2. 利用=把字符串分割为数组 split('=');
var arr = params.split('=');
console.log(arr); // ["uname", "ANDY"]
var div = document.querySelector('div');
// 3.把数据写入div中
div.innerHTML = arr[1] + '欢迎您';
</script>
</body>
这样就能获得URL参数了
6、navigator对象 回到顶部
- navigator 对象包含有关浏览器的信息,它有很多属性
- 我们常用的是
userAgent
,该属性可以返回由客户机发送服务器的user-agent
头部的值
下面前端代码可以判断用户是用哪个终端打开页面的,如果是用 PC 打开的,我们就跳转到 PC 端的页面,如果是用手机打开的,就跳转到手机端页面
if((navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i))) {
window.location.href = "XXXXX.html"; //手机
} else {
window.location.href = "xxx/XXXX.html"; //电脑
}
7、history对象 回到顶部
- window 对象给我们提供了一个 history 对象,与浏览器历史记录进行交互
- 该对象包含用户(在浏览器窗口中)访问过的 URL。
history对象方法 | 作用 |
---|---|
back() | 可以后退功能 |
forward() | 前进功能 |
go(参数) | 前进后退功能,参数如果是 1 前进1个页面 如果是 -1 后退1个页面 |
<body>
<a href="list.html">点击我去往列表页</a>
<button>前进</button>
<script>
var btn = document.querySelector('button');
btn.addEventListener('click', function() {
// history.forward();
history.go(1);
})
</script>
</body>