
正文
2022最新JavaScript+jQuery笔记
提示:扫一扫查出行【扫一扫了解最新限行尾号】
复制提示
浏览器执行js简介
- 渲染引擎:解析css和html
- js引擎:编译js代码,逐行解析
- js是基于对象和事件驱动的松散性,解释性语言。
<script type="null">
alert('我是编程语言,用来控制电脑网页弹出你好'); alert('我是编程语言,用来控制电脑网页弹出你好');
</script>
各个浏览器的js引擎也不相同,所以也会有兼容行问题。
相关问答
Q1: js组成
- EcmaScript:JavaScript基本语法
- DOM:页面文档对象模型(对页面中的文档进行操作)
- BOM:浏览器对象模型(对浏览器窗口做出操作)
Q2: 书写位置
- 行内式
<!-- 1.行内式的js 直接写到元素内部 -->
<input type="button" value="唐伯虎" onclick="alert('秋香姐')">
- 内嵌式
- 最好放到html下部分
<script>
// alert('沙漠骆驼');
</script>
- 外部
- 结构更加易读。
<!-- 3.外部js写法 双标签 -->
<script src="my.js"></script>
javascript标签中无需写代码,否则会被忽略!
Q3: 思维导图


JS中 let和var的区别
- ES6 新增了
let命令,用来声明局部变量。它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效,而且有暂时性死区的约束。
先看个var的常见变量提升的面试题目:
题目1:
var a = 99; // 全局变量a
f(); // f是函数,虽然定义在调用的后面,但是函数声明会提升到作用域的顶部。
console.log(a); // a=>99, 此时是全局变量的a
function f() {
console.log(a); // 当前的a变量是下面变量a声明提升后,默认值undefined
var a = 10;
console.log(a); // a => 10
}
// 输出结果:
undefined
10
99
Q4: ES6可以用let定义块级作用域变量
在ES6之前,我们都是用var来声明变量,而且JS只有函数作用域和全局作用域,没有块级作用域,所以{}限定不了var声明变量的访问范围。
例如:
{
var i = 9;
}
console.log(i); // 9
ES6新增的let,可以声明块级作用域的变量。
{
let i = 9; // i变量只在 花括号内有效!!!
}
console.log(i); // Uncaught ReferenceError: i is not defined
Q5: let 配合for循环的独特应用
let非常适合用于 for循环内部的块级作用域。JS中的for循环体比较特殊,每次执行都是一个全新的独立的块作用域,用let声明的变量传入到 for循环体的作用域后,不会发生改变,不受外界的影响。看一个常见的面试题目:
for (var i = 0; i <10; i++) {
setTimeout(function() { // 同步注册回调函数到 异步的 宏任务队列。
console.log(i); // 执行此代码时,同步代码for循环已经执行完成
}, 0);
}
// 输出结果
10 共10个
// 这里面的知识点: JS的事件循环机制,setTimeout的机制等
如果把 var改成 let声明:
// i虽然在全局作用域声明,但是在for循环体局部作用域中使用的时候,变量会被固定,不受外界干扰。
for (let i = 0; i < 10; i++) {
setTimeout(function() {
console.log(i); // i 是循环体内局部作用域,不受外界影响。
}, 0);
}
// 输出结果:
0 1 2 3 4 5 6 7 8 9
Q6: let没有变量提升与暂时性死区
用let声明的变量,不存在变量提升。而且要求必须 等let声明语句执行完之后,变量才能使用,不然会报Uncaught ReferenceError错误。
console.log(aicoder); // 错误:Uncaught ReferenceError ...
let aicoder = 'aicoder.com';
// 这里就可以安全使用aicoder
ES6 明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。
总之,在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。
Q7: let变量不能重复声明
let不允许在相同作用域内,重复声明同一个变量。否则报错:
Uncaught SyntaxError: Identifier 'XXX' has already been declared
例如:
let a = 0;
let a = 'sss';
// Uncaught SyntaxError: Identifier 'a' has already been declared
Q8: 总结
ES6的let让js真正拥有了块级作用域,也是向这更安全更规范的路走,虽然加了很多约束,但是都是为了让我们更安全的使用和写代码。
字面量
在计算机科学中,字面量(Literal)是在计算机中描述 事/物
Q9: javascript是否写分号结尾
- 根据具体情况实际选择
- 写和不写都可以
Q10: javaScript输入输出语句
| 方法 | 说明 | 归属 |
|---|---|---|
| alert(msg) | 浏览器弹出警示框 | 浏览器 |
| console.log(msg) | 浏览器控制台打印输出信息 | 浏览器 |
| prompt(info) | 浏览器弹出输入框,用户可以输入 | 浏览器 |
| doucument.write() | 页面输出内容,识别标签 | 浏览器 |
注意:
alert主要用来显示消息给用户,console.log()用来给程序员查看自己运行时的消息。
prompt取过来的值是字符类型的
变量
- 属性值:var(variable的缩写)
- 装数据的盒子
Q11: 变量语法拓展
- 更新变量:变量值以最后一次赋的值为准
- 同时声明多个变量:声明一个变量后,中间用逗号隔开
- let声明变量
let即关键字(let:允许,许可,让,要),所谓关键字是系统专门提供的用来声明的变量的词语
var myfirstname = 99,
kjlj = 54;
Q12: 声明变量的特殊情况
| 情况 | 说明 | 结果 |
|---|---|---|
| var age;console.log(age); | 只声明不赋值 | undefined(未定义) |
| console.log(age); | 不声明,不赋值,直接使用 | 报错 |
| age = 10;console.log(age); | 不声明,只赋值 | 10 |
Q13: 变量的命名规范
- 由
字母,数字,下划线,美元符号组成 - 严格区分大小写
- 不能以数字开头。18age是错误的
- 不能是
关键字,保留字命名:var,fo,while - 变量名必须有意义
- 遵循
驼峰命名,首字母小写,后面单词的首字母大写:myFirstName - 推荐翻译网站:
有道
常量
- 概念:使用const声明的变量为‘常量’
- 使用场景:当一个变量永远不会改变的时候,使用 const来声明,而不是let.
- 命名规范:和变量一致
注意:常量不允许重新赋值,声明的时候必须赋值(初始化)
小技巧:不需要重新赋值的数值用const
Q14: 变量声明关键字总结
let - 现在实际开发的声明方式(2022)
var - 以前的声明变量的方式,会有很多问题(2019)
const -类似于let ,但是变量值无法被修改
数据类型
- js的变量数据类型是只有程序在运行过程中,根据等号右边的值来确定的。
- js是动态语言,变量的数据类型是可以变化的。
- typeo检测变量的数据类型
- 可以通过控制台输出的字体颜色来判断到底是哪个字符类型(蓝色,数字;黑色,字符串;灰色 ,未定义)
Q15: 数据类型的分类
简单数据类型(Number,String,Boolean,Underfined,Null)引用数据类型(object)
简单数据类型(栈)
| 简单数据类型 | 说明 | 默认值 | typeof结果 |
|---|---|---|---|
| Number | 数字型,包含整型值和浮点型值,如:21,0.21 | 0 | |
| Booolean | 布尔值类型,如true,false,等价于0,1 | false | |
| symbol | 定义的值具有唯一性 | ||
| string | 字符串类型 | “” | |
| Undefined | var a;声明了变量a,但没有给值,此时a=undefined | undefined | undefined |
| Null | var a= null;声明了变量a为空值 | null | object |
数字型Number
- 可以是整数,小数,正数,负数。
- 最常见的有二进制,八进制,十六进制。
-
isNaN():这个方法用来判断非数字,并且返回一个值,如果是数字返回 false ,如果不是返回的是true。

特殊值
-
Infinity,无穷大 -
-Infinity, 无穷小 -
Number.Max_Value,数字型最大值 -
Number.Min_Value,数字型最小值 -
NaN,缩写:not a number,代表一个非数值
//1.八进制 0~7
var num1 = 010;
console.log(num1);
//2.十六进制 0~9 a~f
var num2 = 0x9;
console.log(num2);
//数字型最大值
console.log(Number.MAX_VALUE);
//无穷大
console.log(Number.MAX_VALUE * 2); //Infinity
//数字型的最小值
console.log(Number.MIN_VALUE);
//无穷小
console.log(Number.MIN_VALUE * 2); //-Infinity
//非数字 NaN
NaN代表一个计算错误。它是一个不正确的或者未定义的数学操作所到的的结果
NaN是
粘性的。任何对NaN的操作都会返回NaN在Js中八进制前面加
0,十六进制前面加0X
未定义类型(undefined)
未定义是比较特殊的类型,只有一个值 undefined.
- 什么情况下出现未定义类型
只声明变量,不赋值的情况下,变量默认值为 undefined,一般很少【直接】为某个变量赋值为
字符串型String
- 字符串可以是引导中的任意文本,其语法为双引号(“ ”),和单引号(' ')或反引号包裹的数据( ``` `)
-
html使用双引号,js推荐使用单引号 - 字符串嵌套(外单内双)
| 转义符 |解释说明|
|:-----?:------?
| \n | 换行符|
| \ |斜杠|
| '|'单引号|
| ''|''双引号|
| \t|tab缩进|
| \b|空格,b是blank的意思|
注意事项:
- 引号必须成对出现
- 单引号和双引号可以相互嵌套,口诀
外双内单,或者外单内双- 必要时可以使用转义符
\,输出单引号或双引号
引用数据类型(堆)
- 包括:
1、对象(Object)类型,是一组由键、值组成的无序集合;数据类型 object
2、数组(Array)类型,是一组按顺序排列的数据的集合;数据类型 object
3、函数(Function)类型,是一段具有特定功能的代码块。数据类型 function
字符串拼接
Q16: 引号拼接字符串(ES5)
场景:+运算符可以实现字符串的拼接。
口诀:数字相加,字符相连
<script>
//1.检测获取字符串的长度 length
var str = 'my name is andy';
console.log(str.length); //15
//2.字符串拼接+,'数值相加,字符相连'
console.log('沙漠' + '骆驼');
console.log('小李' + 18 + '岁');
var age = 18;
console.log('小李' + age + '岁');
console.log(24 + 24); //48
</script>
Q17: 模板字符串(ES6)
- 使用场景:
拼接字符串和变量
在没有它之前,要拼接字符串比较麻烦 - 语法
反引号··
内容拼接变量时,用${}包住变量
<script>
let age = 18
document.write(`我今年${age}岁了`)
var nan = 10 ,nv = 44;
console.log(`本班男生${nan}人,女生${nv}人,共计${nan + nv}人`);
</script>

数据类型的转换
Q18: 隐式转换
某些运算符(除加法四则运算),if条件被执行时,系统内部自动将数据类型进行转换,这种转换称为隐式转换。
- 规则:
+号两边只要有一个是字符串,就会把另外一个转成字符串(拼接)
除了+以外的算术运算符,比如 - * /等都会把数据转换成数据类型。 - 缺点
转换类型不明显,靠经验总结 - 小技巧
+号作为正号解析可以转换成字符串类型
任何数据和字符串相加的结果都是字符串
加法:操作数是number型;
操作数是undefined,null,boolean,隐式调用
Number()进行数据类型的转换
Q19: 强制转换
转换为字符串
| 方式 | 说明 | 案例 |
|---|---|---|
| toString() | 转换成字符串 | var vm = 1;alert(num.toString()) |
| String()强制转换 | 转换成字符串 | var num =1;slert(String(num)); |
| 加号 拼接字符串 | 和字符串拼接的结果都是字符串 | var num =1;alert(num+"我是字符串") |
<script>
// 1.把数字类型转换为字符串型 变量.toString()
var num = 10;
var str = num.toString();
console.log(str);
console.log(typeof str);
// 2.利用String(变量)
console.log(String(num));
//3.利用+拼接字符串的方法实现转换效果,隐式转换
console.log(num + '');
</script>
转换为数字型(重点)
| 方式 | 说明 | 案例 |
|---|---|---|
| parselnt(string) | 将stirng类型转成整数数值型 | parselnt('78') |
| parseFloat(string) | 将string类型转换成浮点数数值型 | parseFloat('78.21') |
| Number()强制转换函数 | 将string类型转换成数值型 | Number('12') |
| js隐式转换(. * / ) | 利用算数运算隐式转换为数值型 | '12'-0 |
转换为布尔型
- 代表
空,否定的值会被转换成false,如''(空字符串),0,NAN,null,underfined - 其余值都会转换成true
- 隐式转换:
- 有字符串的加法
""+1,结果是"1" - 减法 - (像大多数运算一样)只能用于数字,它会使空字符串""转换为 0
- null经过数字转换后会变为
0 - underfined经过数字转换后会变为
NaN
| 方式 |说明|案例|
|:-----?:------?:------?
| Boolean()函数|其他类型转换成布尔值|Boolean('true')|
运算符
Q20: 前置递增
- 变量先加一,然后返回结果
var num = 0
++num
Q21: 后置递增
- 先表达式返回原值,后面变量再自加一
var num = 0
num++
Q22: 比较运算符
| 运算符名称 | 说明 | 案例 | 结果 |
|---|---|---|---|
| == | 判断号(会转型) | 37 == 37 | true |
| === !== | 全等要求值和数据类型都一致 | 37 === ‘37’ | false |
Q23: 逻辑运算符
| 逻辑运算符号 | 说明 | 案例 |
|---|---|---|
| && | 逻辑与,and | true&&false |
| || | 逻辑或,or | true||or |
| ! | 逻辑非,not | !true |
Q24: 逻辑中断
- 短路运算的原理:当有多个表达式时,左边的表达式可以确定结果时,就不再继续运算右边表达式的值;
逻辑与
- 语法:表达式1&&表达式2
- 如果第一个表达式值为真,则返回表达式2
- 如果第一个表达式值为假,则返回表达式1
逻辑或
- 语法:表达式1 | | 表达式2
- 如果第一个表达式值为真,则返回表达式1
- 如果第一个表达式值为假,则返回表达式2
Q25: 赋值运算符
- 概念:用来把数据赋值给变量的运算符
| 赋值运算符号 |说明|案例|
|:-----?:------?:------?
| = |直接赋值|var user='sss'|
| +=,-= |加,减一个数后再赋值|var age=10;age+=5;//5|
| * =,/=,%= |乘,除,取模后赋值|var age=2;age * =5//10 |
运算符优先级
| 优先级 | 运算符 | 顺序 |
|---|---|---|
| 1 | 小括号 | () |
| 2 | 一元运算符 | ++,-,! |
| 3 | 算数运算符 | 先 * / %后+ - |
| 4 | 关系运算符 | > >= < <= |
| 5 | 相等运算符 | == != === !== |
| 6 | 逻辑运算符 | **先&& 后 |
| 7 | 赋值运算符 | = |
| 8 | 逗号运算符 | . |
注意:
&&的权重比||高
Q26: 不同数字类型运算符之间的操作
比较运算符 : > ,< >= , <= ,== ,!=, =, !,返回值是布尔类型
- 都是number型,大小进行比较
- 都是string型,按位按照
ASCII表[1]进行比较- number,string :隐式调用Number()把string 转为number进行计算
==:值相等===:值相等,数据类型相同
console.log(2 > "100"); //false "100"转为 100 与2进行比较
console.log("234" > "100"); //true 这种比较为ASCII码比较,依次取每个字符,字符转为ASCII码进行比 较
console.log("15" > "9"); //false
console.log(15 > 9); //ture
console.log(12 == "12"); //true
console.log(1 == true); //ture Number(true)转换成1
console.log(0 === false); //false
console.log(0 == undefined); //false Number(undefined)转换成NaN
console.log(0 == ""); //true
console.log(0 == " "); //true
算术运算符:+,-,*,/,%,++,--,**
console.log(1 + 133); //134
console.log(1 + "133"); //1133
console.log(1 - "133"); //-132
console.log(1 - "abc"); //NAN 直接是非数字类型
逻辑运算符:隐式调用Boolean()判断真假
0,false,null,undefined,NaN,""这些为假&&:返回第一个假值,运用(短路原则)会返回第一个假值||: 返回第一个真值(短路原则)
var num = 10, bool = true, str = "abc";
console.log(num && bool && 0); //0
console.log(num && str); //"abc"
console.log(bool && str); //"abc"
console.log(0 && str); //0
console.log(false && num); //false
console.log(undefined && num); //undefined
console.log(str && false); //false
console.log(0 && ""); //0
console.log("" && 0); // ""
console.log(num || bool || 0); //10
console.log(num || str); //10
console.log(bool || str); //true
console.log(0 || str); //"abc"
console.log(false || num); //10
console.log(undefined || num); //10
console.log(str || false); //10
console.log(0 || ""); //"" 没真值,只能返回第二个
console.log("" || 0); //0
取反:!
真变假,假变真
var num = 10, bool = true, str = "abc";
console.log(!true); //false
console.log(!0); //true
console.log(!str); //false
短路的代码不会执行
console.log(str && num++); //10 && 期望返回第一个假值,没有假值,就返回最后一个真值,两个都是真值,返回第二个num++
console.log(num); //11
console.log(false && ++num); //false
console.log(num); //11 被短路的代码不运行了,所以还是11
console.log(num++ || 0); //11 最后做自增运算 12
console.log(0 || ++num); //13
console.log(0 || str > num); //fales 返回 str>num 的结果NaN
console.log(num); //13
表达式和语句
- 表达式:
表达式是可以被求值的代码,javaScript引擎会计算出一个结果
let x = 7
3+4
num++
- 语句;
语句是一段可以执行的代码。
比如:prompt( )可以弹出一个输入框,还有if语句 for循环语句等等
区别:
表达式:表达式可以被求值,所以它可以写在赋值语句的右侧
语句:而语句不一定有值,比如alert()for 和break等语句就不能用于赋值。
Q27: 流程控制
- 顺序结构
- 分支结构
- 根据不同的条件,执行不同的路径,得到不同的结果。
if语句
<script>
//1. if 的语法结构
// if (条件表达式) {
// //执行语句
// }
if (3 > 5) {
alert('沙漠骆驼');
}
</script>
案例(判断闰年)
- 算法:可以被4整除且不能整除100的为润年或者可以被400整除的就是润年
三元表达式
条件表达式?表达式1:表达式2
- 如果条件表达式结果为正,则返回表达式一的值,否则返回表达式二的值
数字补零案例
<script>
var time = prompt('输入数字')
var resule = time < 10 ? '0' + time : time;
alert(resule);
</script>
switch语句
- switch语句是多分支语句,可以实现多对一。
<script>
switch (表达式) {
case value1:
执行语句1;
break;
case value2:
执行语句2;
break;
default:
执行最后的语句
}
在判断条件中,条件为真的情况
- 如果是数字:0是否,1是真
- 如果是字符串:字符串不空是真,字符串空是假
if/else和switch的区别
- 一般情况下可以相互替换
- switch...case语句通常在处理case为比较确定值的情况,而if...else..语句更加灵活,通常用与范围判断(大于,等于某个范围)
- switch语句进行条件判断后直接执行程序的条件语句,效率更高是。而if...else.语句有几种条件,就得判断多次。
- 分支比较小的情况下,if...else语句执行效率比switch高。
- 分支比较多的情况下,switch语句执行效率高,而且结构清晰。
- 循环结构
- 执行规律任务,重复执行多次语句
for循环
掌握 for 循环语句,让程序具备重复执行能力
for 是 JavaScript 提供的另一种循环控制的话句,它和 while 只是语法上存在差异。
for语句的基本使用
- 实现循环的 3 要素
<script>
// 1. 语法格式
// for(起始值; 终止条件; 变化量) {
// // 要重复执行的代码
// }
// 2. 示例:在网页中输入标题标签
// 起始值为 1
// 变化量 i++
// 终止条件 i <= 6
for(let i = 1; i <= 6; i++) {
document.write(`<h${i}>循环控制,即重复执行<h${i}>`)
}
</script>
-
变化量和死循环,
for循环和while一样,如果不合理设置增量和终止条件,便会产生死循环。 -
跳出和终止循环
<script>
// 1. continue
for (let i = 1; i <= 5; i++) {
if (i === 3) {
continue // 结束本次循环,继续下一次循环
}
console.log(i)
}
// 2. break
for (let i = 1; i <= 5; i++) {
if (i === 3) {
break // 退出结束整个循环
}
console.log(i)
}
</script>
结论:
-
JavaScript提供了多种语句来实现循环控制,但无论使用哪种语句都离不开循环的3个特征,即起始值、变化量、终止条件,做为初学者应着重体会这3个特征,不必过多纠结三种语句的区别。 - 起始值、变化量、终止条件,由开发者根据逻辑需要进行设计,规避死循环的发生。
- 当如果明确了循环的次数的时候推荐使用
for循环,当不明确循环的次数的时候推荐使用while循环
注意:
for的语法结构更简洁,故for循环的使用频次会更多。
循环嵌套
利用循环的知识来对比一个简单的天文知识,我们知道地球在自转的同时也在围绕太阳公转,如果把自转和公转都看成是循环的话,就相当于是循环中又嵌套了另一个循环。

实际上 JavaScript 中任何一种循环语句都支持循环的嵌套,如下代码所示:

// 1. 外面的循环 记录第n天
for (let i = 1; i < 4; i++) {
document.write(`第${i}天 <br>`)
// 2. 里层的循环记录 几个单词
for (let j = 1; j < 6; j++) {
document.write(`记住第${j}个单词<br>`)
}
}
记住,外层循环循环一次,里层循环循环全部
倒三角
// 外层打印几行
for (let i = 1; i <= 5; i++) {
// 里层打印几个星星
for (let j = 1; j <= i; j++) {
document.write('★')
}
document.write('<br>')
}

九九乘法表
样式css
span {
display: inline-block;
width: 100px;
padding: 5px 10px;
border: 1px solid pink;
margin: 2px;
border-radius: 5px;
box-shadow: 2px 2px 2px rgba(255, 192, 203, .4);
background-color: rgba(255, 192, 203, .1);
text-align: center;
color: hotpink;
}
javascript
// 外层打印几行
for (let i = 1; i <= 9; i++) {
// 里层打印几个星星
for (let j = 1; j <= i; j++) {
// 只需要吧 ★ 换成 1 x 1 = 1
document.write(`
<div> ${j} x ${i} = ${j * i} </div>
`)
}
document.write('<br>')
}

Q28: while循环
- 条件为true,执行循环语句,否则推出循环
do while循环
- do while循环其实是while循环的一个变体,该循环会先执行一次代码块,然后对条件表达式进行判断,如果为真,就会重复执行循环体,否则退出循环。
continue关键字
- 用于立即跳出本次循环,继续下一次循环(本次循环中,continue之后的代码就会少执行一次)
break关键字
- 立即跳出整个循环(循环结束)
数组(Array)
知道什么是数组及其应用的场景,掌握数组声明及访问的语法。
- 数组就是一组数据的集合,存储在单个变量下的优雅方式。
- 数组里面的数据一定要逗号隔开
- 数组里面的数据比如,1,2,我们称为数组元素。
- 任意数据类型都可以放入
- 数组在 JavaScript 中并不是新的数据类型,它属于对象类型。
<script>
// 1. 语法,使用 [] 来定义一个空数组
// 定义一个空数组,然后赋值给变量 classes
// let classes = [];
// 2. 定义非空数组
let classes = ['小明', '小刚', '小红', '小丽', '小米']
</script>
通过 [] 定义数组,数据中可以存放真正的数据,如小明、小刚、小红等这些都是数组中的数据,我们这些数据称为数组单元,数组单元之间使用英文逗号分隔。
Q29: 创建数组
- 利用new 创建数组
<script>
var arry = new Array(); //创建了个一空数组
</script>
- 利用数组字面量创建数组
<script>
var arr = []; //创建了一个空数组
var arr1 = [1, 2, 'pingk老师', true];
//数组里面的数据一定要逗号隔开
//数组里面的数据比如,1,2,我们称为数组元素。
</script>
- 进阶
<script>
var arr = new Array(2);//这个2表示数组长度为2,里面有两个空值
var arr1 = new Array(2,3);//等价于[2,3]
console.log(arr1);
</script>
Q30: 获取数组元素
1.数组的索引
- 下标:用来访问数组元素的序号(数组下标从零开始)
console.log(arr1[2]);
Q31: 检测数组方法
- Instanceof 运算符 它可以用来检测是否是数组
<script>
var arr = [];
var obj ={};
console.log(arr instanceof Array);//true
console.log(ogj instanceof Array);//false
</script>
- Array.isArray(参数);H5新增的方法,ie9以上版本支持
console.log(Array.isArray(arr));//true
Q32: 遍历数组
<script>
var arr = ['red', 'green', 'blue'];
for (var i = 0; i <= 2; i++) {
console.log(arr[i]);
}
</script>
Q33: 案例(求数组最大值)
<script>
var max = 1;
var arr = [1, 2, 3, 66, 78, 234, 123, 12, 345, 435];
for (var i = 0; i <= arr.length; i++) {
if (max < arr[i]) {
max = arr[i];
}
}
console.log(max);
Q34: 案例(数组转换为分割字符串)
<script>
var str = '';
var arr = ['red', 'blue', 'green'];
var step = '|'
for (var i = 0; i < arr.length; i++) {
str += arr[i] + step;
}
console.log(str);
</script>
Q35: 数组长度
- 数组名后面加.length属性可以得到数组长度;
- 数组长度是元素个数,不要跟索引号混淆;
- arr.length是动态检测数组元素的个数;
<script>
var arr = ['red', 'green', 'blue'];
for (var i = 0; i <= arr.length; i++) {
console.log(arr[i]);
}
</script>
Q36: 数组新增元素
- 可以通过修改length长度新增数组元素。
<script>
var arr = ['red', 'blue', 'green'];
console.log(arr.length);
arr.length = 5; //数组长度修改为5
console.log(arr);//修改后最后两个元素没有给值,所以是undefined
</script>
- 可以通过修改数组索引新增数组元素(追加数组元素)
<script>
var arr1 = ['red', 'blue', 'green'];
arr1[3] = 'pink';
console.log(arr1);
arr1[0] = 'yellow'; //替换原来的数组元素
</script>
Q37: 筛选数组
- 方法一
<script>
var arr = [2, 0, 1, 22, 121, 454, 3, 35, 435, 45];
var newArry = [];
var j = 0;
for (var i = 0; i < arr.length; i++) {
if (arr[i] >= 10) {
newArry[j] = arr[i];
j++;
}
}
console.log(newArry);
</script>
- 方法二
- 注意:方法二用新数组的长度来代替方法一中的j变量;
<script>
var arr1 = [2, 0, 1, 22, 121, 454, 3, 35, 435, 45];
var newArry1 = [];
for (var i = 0; i < arr.length; i++) {
if (arr1[i] >= 10) {
newArry1[newArry1.length] = arr[i];
}
}
console.log(newArry1);
</script>
Q38: 操作数组
数组做为对象数据类型,不但有 length 属性可以使用,还提供了许多方法:
- push 动态向数组的尾部添加一个单元
- unshit 动态向数组头部添加一个单元
- pop 删除最后一个单元
- shift 删除第一个单元
- splice 动态删除任意单元
使用以上4个方法时,都是直接在原数组上进行操作,即成功调任何一个方法,原数组都跟着发生相应的改变。并且在添加或删除单元时 length 并不会发生错乱。
<script>
// 定义一个数组
let arr = ['html', 'css', 'javascript']
// 1. push 动态向数组的尾部添加一个单元
arr.push('Nodejs')
console.log(arr)
arr.push('Vue')
// 2. unshit 动态向数组头部添加一个单元
arr.unshift('VS Code')
console.log(arr)
// 3. splice 动态删除任意单元
arr.splice(2, 1) // 从索引值为2的位置开始删除1个单元
console.log(arr)
// 4. pop 删除最后一个单元
arr.pop()
console.log(arr)
// 5. shift 删除第一个单元
arr.shift()
console.log(arr)
</script>
Q39: 冒泡排序
- 是一种算法,把一系列的数据按照一定的顺序进行排列显示(从小到大,或者从大到小),一次比较两个元素,如果顺序错误就把他们交换过来,走访数列的工作是重复进行的,直到没有需要再交换,也就是说该数列已经排序完成。
<body>
<script>
let arr = [6, 23, 1, 56, 78, 86]
for (let i = 0; i < arr.length - 1; i++) {
for (let j = 0; j < arr.length - i - 1; j++) {
//开始交换
if (arr[j] > arr[j + 1]) {
//交换两个变量
let temp = arr[j + 1]
arr[j + 1] = arr[j]
arr[j] = temp
}
}
}
console.log(arr);
</script>
</body>
注意:一共需要的趟数是 arr. length-1,每一趟需要交换的次数是 arr.length -i - 1。i是外侧循环
Q40: 数组重要方法操作
<script>
var arr = [1, 2, 3, 4, 5]
console.log(arr);
// forEach 遍历
arr.forEach(function (v, i) {
// console.log(v);
// console.log(i);
})
//push向数组末尾添加一个或者多个元素,会改变原数组
arr.push("a", "b", "10")
console.log(arr);
//every() 当元素全部满足条件的时候返回true,有一个不满足就会返回false
var result = arr.every(function (v, i) {
return v > 5;
})
//some()只要有一个满足就返回true
console.log(result);
var result1 = arr.some(function (v, i) {
return v > 5;
})
console.log(result1);
//splice(位置(元素下标),删除的元素个数) 删除 会影响原数组
arr.splice(2, 2)
console.log(arr);
//findIndex返回满足条件的元素,首次出现的位置 ,如果没有就返回-1
var result2 = arr.findIndex(function (v, i) {
return v == 5;
})
console.log(result2);
//join() 把数组转换成字符串,不会影响原数组
console.log(arr.join("-"));
//filter() 过滤 返回满足条件的元素,构成新数组
var result3 = arr.filter(function (v, i) {
return v < 5;
})
console.log(result3);
//map() 映射
var result4 = arr.map(function (v, i) {
return v * 4
})
console.log(result4);
</script>

函数
- 封装了一段可以重复执行的代码块
- 实例(求num1~num2的累加和)
<script>
//函数
function getSum(num1, nmu2) {
var sun = 0;
for (var i = num1; i <= nmu2; i++) {
sun += i;
}
console.log(sun);
}
getSum(1, 100)//调用函数
</script>
Q41: 函数分类
具名函数
funcation fn(){}
fn()
匿名函数
没有名字的函数,无法直接使用。
使用方式:
- 函数表达式
将匿名函数赋值给一个变量,并且通过变量名称进行调用,我们称这个为函数表达式。
语法:
let fn = function(){
//函数体
}
- 立即执行函数
场景介绍:避免全局变量之间的污染
语法:
//方式一
(function () { console.log(11); }());
//方式二
(function () { console.log(11); })();
//不需要调用,立即执行
(function (x, y) { console.log(x + y); })(1, 2);
注意:多个立即执行函数需要用分号
;隔开
注意:
函数表达式和具名函数不同,如果是具名函数,那它的调用可以用在任何位置(函数体上下都可以)
函数表达式不行,因为let的关系,只能在声明后才可以调用。
Q42: 函数使用
- 声明函数
<script>
function 函数名() {
函数体
}
</script>
- funcation是声明函数的关键字,全部小写
- 函数是做某件事情,函数名一般是动词
- 函数不调用自己不执行
- 调用函数
- 调用函数时,一定不要忘记添加小括号!
函数名();
Q43: 函数的参数
形参
- 在声明函数的小括号里面是形参(形式上的参数)
- 形参是用来接受实参的,形参类似于变量(不用声明的变量)
function 函数名(形参1, 形参2...) {
}
实参
- 在函数调用的小括号里是实参(实际的参数)
函数名(实参1, 实参2...);
Q44: 函数形参和实参匹配问题
<script>
function getSum(num1, nmu2) {
console.log(num1 + num2);
}
getSum(1, 2); //实参个数和形参个数一致,正常输出结果
getSum(1, 2, 3); //实参个数多于形参的个数,会取到形参的个数
getSum(1); //形参可以看作是不用声明的变量, num2是一个变量但是没有接收值 结果就是undefined
</script>
注意:
- 实参多于形参, 多的不参与运算,多的会保存到
arguments对象中(数组类型)- 实参少于形参,少的就时undefined
Q45: retuen语句
- 函数只是实现某种功能,最终的结果需要返回函数的调用者,通过return实现的
-
retuen 终止函数,retuen后面的代码不会被执行。
function 函数名() {
return 需要返回的结果;
}
function fn() {
return 20;
}
console.log(fn())
注意:当函数(fn)调用时,相当于调用者 fn( ) = 返回值
console.log( fu( ) )才能拿着到20
函数有返回值时,就返回该值,没有返回值就返回 undefined
Q46: arguments使用
- arguments对象中存储了传递过来的实参。
- argunmets是伪数组:1.具有数组的length属性,按照索引的方式进行存储。
- 可以按照数组的方式遍历arguments
作用域
- javaScript作用域:就是代码名字在某个范围内起作用和效果,是为了提高程序的可靠性,更重要的是减少命名冲突。
Q47: 作用域(es5)分为两种
-
全局作用域:整个script标签,或者是单独的js文件
全局有效 -
局部作用域(函数作用域):在函数内部就是局部作用域,这个代码的名字就只在函数内部起效果。
局部有效
注意:
变量有一个坑
如果函数内部,变量没有声明,直接赋值,也会当全局变量来看,但是强烈不推荐。
Q48: 变量的作用域
- 全局变量:在全局作用下的变量分为
用var声明的和不用var声明的(不推荐) - 局部变量:在局部作用域下的变量,后者在函数内部的变量就是局部变量,
形参属于局部变量
执行效率
-
全局变量只有浏览器关闭时才会销毁,比较占用内存资源 -
局部变量当程序执行完毕就会销毁,节约内存资源
Q49: 块级作用域
- 现阶段我们js,我们没有块级作用域(2015年已经有了ES6)
- es6后新增块级作用域
Q50: 作用域链(就近原则)
- 内部函数访问外部函数的变量,采取的是链式查找的方式来决定值,这种结构我们称为作用域链
Q51: 变量的访问原则
- 只要是代码,就至少有一个作用域
- 写在函数内部的局部作用域
- 如果函数中还有函数,那么在这个作用域中就可以诞生一个作用域
- 访问原则:
在能够访问到的情况下,先局部,局部没有在找全局
js预解析
- 我们js引擎运行js分为两步:
预解析代码执行
- 预解析:js引擎会把js里面所有的
var还有funcation提升到当前作用域的最前面,进行提前声明和定义. - 代码执行:按照代码书写顺序从上往下执行
- 预解析分为变量预解析(变量提升)和函数预解析(函数提升)
- 变量提升:就是把所有变量的声明提升到当前作用域的最前面,不提升赋值操作
- 函数提升:就是把所有
函数声明提升到当前作用域提升前面,不调用函数。
<script>
console.log(num); //错误
var num = 10;
//相当于执行以下代码
var num;
console.log(num);
num = 10;
</script>
<script>
fun(); //错误
var fun = function() {
console.log(22);
}
//相当于执行以下代码
var fun;
fun();
fun = function() {
console.log(22);
}
</script>
<script>
//案例一
var num = 10;
fun();
function fun() {
console.log(num);//undefined
var num = 20;
}
//相当于执行以下操作
var num;
function fun() {
var num;
console.log(num);
num = 20;
}
num = 10;
fun();
</script>
<script>
//案例二
var num = 10;
function fn() {
console.log(num);
var num = 20;
console.log(num);
}
fun();
//相当于执行以下操作
var num;
function fn() {
var num;
console.log(num); //undefinde
num = 20;
console.log(num); //20
}
num = 10;
fun();
</script>
alert(a); //a函数
var a = 1;
alert(a); //1
function a() {
return false;
}
//相当于执行
var a;
function a(){
return false;
}
alert(a);
a = 1;
alert(a);
注意:
同级时,
函数的优先级高于变量
var a = 18;
f1();
function f1() {
var b = 9;
console.log(a); //undefined
console.log(b); //9
var a = '123';
}
//相当于执行
var a ;
funcation f1(){
var b;
var a;
b = 9;
console.log(a);
console.log(b);
a = '123';
}
f1();
Q52: 面试题(价值高)
<script>
//案例四
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); //9
console.log(b); //9
console.log(c); //9
}
f1();
console.log(c); //9
console.log(b); //9
console.log(a); //报错 undefined
</script>
js对象
- 什么是对象:对象是一个具体的事物。
- 在js中,对象是一组无序的相关属性和方法的集合
Q53: 创建对象的三种方式
- 利用字面量创建对象
- 就是用
花括号{}里面包含了表达这个具体事物的对象和方法。
<script>
var obj = {
uname: '李宇',
age: 18,
sex: '男',
sayHi: function drink() {
console.log('drink');
}
}
console.log(obj.age);
</script>
- 利用
new object创建对象
- 利用等号赋值的方法,添加对象的属性和方法。
- 每个属性和方法之间用分号结束。
var obj1 = new Object();
obj1.uname = 'zzkj';
obj1.age = 18;
ocj1.sex = 'bna';
obj1.sayh = function() {
console.log(hi);
}
console.log(obj1.uname);
console.log(obj1['sex']);
obj1.sayh();
- 创建对象实例
function Star(uname, sex) {
this.uname = uname;
this.sex = sex;
this.sing = function(sang) {
console.log(sang);
}
}
var ldh = new Star('刘德华', '男'); //调用函数返回对象。
ldh.sing('并与');
- 利用
构造函数创建对象
- 为啥需要用到构造函数?:以上两种方法一次只能创建一个对象。
- 构造函数就是把对像里面的相同的属性和方法抽象出来封装到函数里面。
- 规范:
构造函数首字母要大写。 - 构造函数不需要return,就可以返回结果。
function 构造函数名() {
this.属性 = 值;
this.方法 = function() {}
}
new 构造函数名();
Q54: 变量,属性,函数,方法的区别
- 存储位置有区别,变量的基本数据类型存储在栈内存、变量的函数和对象存储在堆内存(存疑)
- 变量:单独声明赋值,单独存在
- 属性:对象里面的变量称为属性,不需要声明,用来描述该对象的特征
- 函数:单独存在的了,通过“函数名()”的方法就可以调用,方法用来描述该对象的行为和功能。
Q55: new 关键字
new在执行时会做的四件事情
<script>
//1.构造函数在内存中创建了一个空的对象
//2.this 就会指向刚才创建的空对象
//2.执行构造函数里面的代码,给这个空对象添加属性和方法。
//4.返回这个对象。
function Star(uname, sex) {
this.uname = uname;
this.sex = sex;
this.sing = function(sang) {
console.log(sang);
}
}
var ldh = new Star('刘德华', '男'); //调用函数返回对象。
ldh.sing('并与');
</script>
Q56: 遍历对象
- 使用for in遍历
<script>
var obj = {
name: 'pink老师',
age: 18,
sex: '男',
fn: function() {}
}
// for in 遍历我们的对象
for (var k in obj) {
console.log(k); //k代表的属性名,方法名
console.log(obj[k]); //得到的是里面的属性值
}
</script>
Q57: 内置对象
javaScript中的对象
- 分三种:自定义对象,内置对象,浏览器对象
- 前两种对象是js基础内容,属于EcMAScript;第三个浏览器对象属于我们js独有的,我们JSAPI讲解
什么是内置对象
- 内置对象就是指Js语言里面自带的一些对象,这些对象供给开发者使用,并提供了一些常用的或是最基本而必要的功能(属性或者方法)
- 内置对象最大的优点就是帮助我们快速开发
- javaScript提供了多种内置对象:Math,Date,Array,String等
查阅文档
MDN首页
exec 内置对象
exec() 方法用于检索字符串中的正则表达式的匹配。
如果字符串中有匹配的值返回该匹配值,否则返回 null。
- 语法
RegExpObject.exec(string)
| 参数 | 描述 |
|---|---|
| string | Require The string to be searched |
- 实例
var str="Hello world!";
//查找"Hello"
var patt=/Hello/g;
var result=patt.exec(str);
document.write("返回值: " + result);
//查找 "RUNOOB"
patt=/RUNOOB/g;
result=patt.exec(str);
document.write("<br>返回值: " + result);
- 输出
Returned value: Hello
Returned value: null
Math内置对象
- Math对象是一个静态对象,不用new ,直接使用就可以。
<script>
console.log(Math.PI); //圆周率
console.log(Math.max(1, 9, 3, 4)); //9
console.log(Math.max(-1, -10)); //-1
console.log(Math.max(-1, 'pingk')); //NAN
console.log(Math.max()); //-Inginity
</script>
封装自己的数学对象(最大最小值案例)
<script>
var Mymath = {
PI: 3.,
max: function() {
var max = arguments[0];
for (var i = 1; i < arguments.length; i++) {
if (arguments[i] > max) {
max = arguments[i];
}
}
return max;
},
min: function() {
var min = arguments[0];
for (var i = 1; i < arguments.length; i++) {
if (arguments[i] < min) {
min = arguments[i];
}
}
return min;
}
}
console.log(Mymath.PI);
console.log(Mymath.max(1, 5, 9));
console.log(Mymath.min(1, 5, 9));
</script>
Math绝对值和三个取整方法
Math.abs绝对值
console.log(Math.abs(1)); //1
console.log(Math.abs(-1)); //1
console.log(Math.abs('-1')); //隐式转换,会把字符串型-1转换成1
console.log(Math.abs('pink')); //NAN
Math.floor()向下取整 往小了的取值
Math.floor() //向下取整 往小了的取值
Math.ceil()向上取整,往最大了取值
Math.ceil() //向上取整,往最大了取值
Math.round()四舍五入
- 注意:其他数字都是四舍五入,但是 .5 特殊,它往大了取。
console.log(Math.round(1.9)); //2
console.log(Math.round(-1.5)); //这个结果是-1
console.log(Math.round(-1.6)); //这个结果是-2
Math.random()随机数
- 返回一个随机的小数 0=< x <1
- 这个方法不需要参数
- 代码验证
console.log(Math.random());
取两个数之间的随机整数,包括这两个数(重要)
- 公式:Math.floor(math.random() * (max - min + 1)) + min;
<script>
console.log(Math.random());
//得到两个数之间的随机整数,包括这两个数
//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));
//5.随机点名
var arr = ['这姑娘三', '里斯', '李书记', '时看见立刻'];
console.log(arr[getRandom(1, 3)]);
</script>
猜数字游戏(案例)
<script>
function getRandom(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
var random = getRandom(1, 10);
while (true) {
//死循环
var num = prompt('你来猜');
if (num > random) {
alert('你猜大了');
} else if (num < random) {
alert('你猜小了');
} else {
alert('你猜对了!');
break;//跳出循环
}
}
Date日期对象
- 注意:Date() 日期对象,是一个构造函数,必须使用new 来调用创建我们的日期对象
- date处理日期和时间
- 获取当前时间必须实例化
var arr = new Array(); //创建了一个数组对象
var obj = new Object(); //创建了一个对象实例
//1. 使用Date,没有参数,返回当前系统的当前时间
var date = new Date();
console.log(date);
- Date()构造函数的参数
- 如果括号里面有时间,就返回参数里面的时间。例如日期格式字符串为'2019-5-1',可以写成new Date('2019-5-1')或者new Date('2019/5/1')
//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);
Q58: Date.getFullYear():年
- 返回当年
Q59: Date.getMonth():月
- 获取当月(0-11)
- 返回的月份小一个月
console.log(date.getMonth() + 1);
Q60: Date.getDate():日
- 返回的是几号
var datas = date.getDate();
Q61: Date.getDay():星期几
- 返回周几(周0到周六)
var day = date.getDay();
- 显示当前时间(案例)
var date = new Date();
//2022年3月9日星期三
var year = date.getFullYear();
var moth = date.getMonth() + 1;
var datas = date.getDate();
var arr = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六', ];
var day = date.getDay();
console.log('今天是:' + year + '年' + moth + '月' + datas + '日 ' + arr[day]);
- 输出效果
今天是:2022年3月9日星期三
Date.getHours():时
Date.getMinutes():分
Date.getSeconds():秒
Q62: 返回当前时分秒案例:格式 08:08:08
function getTime() {
var time = new Date();
var h = time.getHours();
var h = h < 10 ? '0' + h : h;
var m = time.getMinutes();
var m = m < 10 ? '0' + m : m;
var s = time.getSeconds();
return h + ':' + m + ':' + s;
var s = s < 10 ? '0' + s : s;
}
console.log(getTime());
Date总的毫秒数(时间戳)
- 获得Date总的毫秒数(时间戳),不是当前时间的毫秒数,而是距离1970年1月1日过了多少毫秒数
- 通过ValueOf( ) getTIme()
Q63: 倒计时案例
- 核心分析:输入时间减去现在时间就是剩余时间,即倒计时,但是不能拿着时分秒相减,比如05分减去25分,结果会是负数。
- 用时间戳来做,用户输入时间总毫秒减去现在时间的总毫秒数,得到的就是剩余时间的毫秒数。
- 把剩余时间总毫秒数转换成天,时,分,秒
- 转换公式
| 计算公式 |解释说明|
|:-----?:------?
| d = parselnt(总秒数/60/60/24)| 计算天数|
| h = parselnt(总秒数/60/60%24) |计算小时|
| m = parselnt(总秒数/60%60)|计算分数|
| s = parselnt(总秒数%60)|计算当前秒数|
<script>
function conutDown(time){
var nowTime = +new Date();//返回当前时间总毫秒数
var inputTime = +new Date(time);//返回用户输入时间总的毫秒数
var times = (inputTime - nowTime)/1000;//剩余时间总的秒数
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(conutDown('2022-3-10 22:00:00'));
</script>
数组对象
Q64: 添加删除数组元素的方法(重点)
| 方法名 | 说明 | 返回值 |
|---|---|---|
| push(参数1...) | 末尾添加一个或者多个元素,注意修改原数组 | 并返回新的长度 |
| pop() | 删除数组最后一个元素,把数组长度减1无参数,修改原数组 | 返回它删除的元素的值 |
| unshift(参数1...) | 向数组的开头添加一个或者多个元素,注意修改原数组 | 并返回新的长度 |
| shift() | 删除数第一个元素,把数组长度减1无参数,修改原数组 | 并返回第一个元素的值 |
var arr = [1,2,3];
// 尾添加
// arr.push(4,'liyu');//push添加末尾
console.log(arr.push(4,'liyu'));//5
console.log(arr);//输出数组
//头添加
console.log(arr.unshift('red','purple'));
// arr.unshift('red','purple');
console.log(arr);
//尾删除,一次只能删除一个元素
//返回删除的那个元素
console.log(arr.pop());
console.log(arr);
//头删除,一次只能删除一个元素
console.log(arr.shift());
console.log(arr);
Q65: 筛选数组(案例,运用数组对象)
- 代码
<script>
var arr= [1500,1200,2100,1800];
var newArry = [];
for (var i = 0;i<arr.length;i++){
if(arr[i]<2000){
newArry.push(arr[i]);
}
}
console.log(newArry);
</script>
- 输出结果
(3)[1500, 1200, 1800]0: : : 1800length: 3[[Prototype]]: Array(0)
Q66: 数组排序
| 方法名 | 说明 | 是否修改原数组 |
|---|---|---|
| reverse() | 颠倒数组中元素的顺序,无参数 | 该方法会改变原来数组,返回新数组 |
| sort() | 对数组元素进行排序 | 该方法会改变原来数组,返回新数组 |
<script>
//翻转数组
var arr = ['pink','red','pink']
arr.reverse();
console.log(arr);
//数组排序(冒泡排序)
var arr1=[1,3,4,2,5,6];
arr1.sort(function(a,b){
// return a - b;//按照升序排序
return b - a;//按照降序排序
});
console.log(arr1);
</script>
注意:当使用 b-a 时,说明后面的大,是降序。使用a-b时,说明前面大,是升序(默认)
Q67: 数组索引方法
| 方法名 | 说明 | 返回值 |
|---|---|---|
| indexOf() | 数组中查找给指定元素的第一个索引 | 如果存在,返回索引号,如果不存在,则返回-1 |
| lastIndex() | 在数组中的最后一个索引 | 如果存在返回索引号 如果不存在,则返回-1 |
<script>
//它只返回第一个满足条件的索引号
var arr = ['red','blue','pink','blue']
console.log(arr.indexOf('blue'));//返回1
console.log(arr.indexOf('green'));//返回-1
console.log(arr.lastIndexOf('blue'));//返回3
console.log(arr.lastIndexOf('green'));//返回-1
</script>
Q68: 数组去重(重点案例)
- 目标:把旧数组里面不重复的元素选取出来放到新数组中,重复的元素只留一个,放到新数组中去重。
- 核心原理:遍历旧数组,然后拿着旧数组元素去查询新数组,如果该元素在新数组没有,则添加
<script>
// var arr = ['c','a','x','a','c','b','z','c','c'];
function unique(arr){
var newArry = [];
for (var i = 0;i< arr.length;i++){
if(newArry.indexOf(arr[i]) === -1){
newArry.push(arr[i]);
}
}
return newArry;
}
var demo = unique(['c','a','x','a','c','b','z','c','c'])
console.log(demo);
</script>
Q69: 数组转换成字符串
| 方法名 | 说明 | 返回值 |
|---|---|---|
| toString() | 把数组转换成字符串,逗号分隔没一项 | 返回一个字符串 |
| join('分隔符') | 方法用于把数组中得到所有元素转换成一个字符串 | 返回一个字符串 |
- 代码示例
<script>
//1.toString数组转换为字符串
var arr = [1,2,3];
console.log(arr.toString());//1,2,3
//2.join(分隔符)
console.log(arr.join('-'));
</script>
- 输出结果
1,2,3
数组转换为字符串.html:13 1-2-3
基本包装类型
- 把简单数据类型包装为复杂数据类型,基本数据类型就有了属性和方法。
- 下面代码有什么问题?
//基本包装类型
var str = 'andy';
console.log(str.length);
//对象才有属性和方法,复杂数据类型里才有属性和方法
//简单数据类型里为何有length属性呢?
- 实际执行过程
//(1)把简单数据类型包装为复杂数据类型
var temp = new String('andy');
//(2)把临时变量值给str
str = temp;
// (3) 销毁这个临时变量
temp = null;
Q70: 字符串对象
字符串不可变
- 指的是里面的值不可变,虽然看似可以改变内容,但其实地址变了,内存中开辟了一个内存空间.
- 因为我们字符串的不可变,所以不要大量拼接字符串.
根据字符返回位置
| 方法名 | 说明 |
|---|---|
| indexOf('要查找的字符',开始的位置) | 返回指定内容,在元字符串中的位置,如果找不到就返回-1,开始的位置是Index索引号 |
| LastIndexOf() | 从后往前找,只找第一个匹配的 |
<script>
//字符串对象 根据字符串返回位置 str.indexOf('要查找的字符串',[起始位置])
var str = '改革春风吹满地,春天来了';
console.log(str.indexOf('春'));//2
console.log(str.indexOf('春',3));//8
</script>
返回字符位置(案例)
- 返回字符串"scjlkdodfsooadsjosdfa''中所有o出现的位置以及次序.
- 核心算法:
- 先查找第一个o出现的位置
- 然后只要indexOf()返回的结果不是-1,就继续往后查找
- 因为IndexOf只能查找第一个,所以后面查找,利用第二个参数,当前索引加1,从而继续查找.
<body>
<script>
var str = "abscedsljposdfosdsof";
var index = str.indexOf('o');
console.log(index);
while(index != -1){
console.log(index);
str.indexOf('o',index+1);
}
</script>
</body>
根据位置返回字符串(重点)
| 方法名 | 说明 | 使用 |
|---|---|---|
| charAt(index) | 返回指定位置的字符(index 字符串的索引号) | str.charAt(0) |
| charCodeAt(index) | 获取指定位置处字符的ASCII码(index索引号) | str.charCodeAt(0) |
| str[index] | 获取指定位置处字符 | HTML5,IE8支持,和charat(等效) |
<script>
//1. charAt('index')
var str = 'andy';
console.log(str.charAt(3));
//遍历所有字符
for(var i=0;i<str.length;i++){
console.log(str.charAt(i));
}
//2.charCodeAt(index)返回相应索引号的字符ASCII值,目的:判断用户按下哪个键
console.log(str.charCodeAt(0)); //97
//3.str[index] H5新增
console.log(str[0]);//a
</script>
统计出现次数最多的字符
<script>
//用一个对象来判断是否
// var o = {
// age:18
// }
// if (o['age']) {
// console.log('里面有属性');
// }else{
// console.log('里面没有此属性');
// }
var str = 'asfHKjkajdkfjakjhfkjahdf';
var o = {};
for (var i= 0;i<str.length;i++){
var chars = str.charAt(i)//chars是字符串的每一个字符
if(o[chars]){
o[chars]++;
}else{
o[chars] = 1;
}
}
console.log(o);
var max = 0;
var ch = '';
//遍历对象
for(var k in o){
//k得到的数属性名
//o[k]得到的是属性值
if(o[k] >max){
max = o[k];
ch = k;
}
}
console.log(k+':'+max);
</script>
- 输出结果
ObjectH: 1K: 1a: 4d: 2f: 4h: 2j: 5k: 4s: 1[[Prototype]]: Object
h:5
字符串的操作方法
| 方法名 | 说明 |
|---|---|
| concat(st) | concat()方法用于连接两个或者多个字符串,拼接字符串,等效于+,+更常用 |
| substr(start,length) | 从start位置开始(索引号),length取的个数,重点记住这个 |
| slice(start,end) | 从start位置开始,截取到end位置,end取不到(他们两都是索引号) |
| substring(start,end) | 从start位置开始,截取到end位置,end取不到,基本和slice相同,但是不接受负值 |
| replace('被替换字符','替换为的字符') | 它只会替换第一个字符 |
| split('分割符') | 字符转换为数组,前面我们学过join把数组转换成字符串 |
| replace('被替换字符','替换为的字符') | 它只会替换第一个字符 |
| toUpperCase() | 转换大写 |
| toLowerCase() | 转换小写 |
简单数据类型和复杂数据类型导读
Q71: 简单数据类型与复杂数据类型
- 简单类型又叫基本数据类型或者值类型,复杂类型又叫做引用类型
- 值类型:简单数据类型/基本数据类型,在存储变量中存储的是值本身,因此叫做值类型,string ,number,boolean,undefined,null;
- 引用类型:复杂数据对象,在存储时变量中存储仅仅是地址(引用),因此叫做引用数据类型,通过new 关键字创建的对象(系统对象,自定义对象),如Object,Array,Date等
Q72: 堆和栈
- 简单数据类型放到栈里面,里面直接开辟一块内存空间,存放的是值
- 复杂数据类型,首先在栈里面存放地址,十六进制表示,然后这个地址指向堆里面的数据。
Q73: 简单数据类型传参
- 函数形参可以看作变量,当我们把一个值类型变量作为参数传给函数形参时,其实是把变量在栈空间里的值负值了一份给形参,那么在方法内部对形参做任何修改都不会影响到外部变量。
Q74: 复杂数据类型传参
- 函数形参可以看作变量,当我们把一个引用类型变量传给形参时,其实是把变量在栈空间里保存的堆地址复制给了形参,形参和实参其实保存的的是同一个堆地址,所以操作的是同一个对象。
Web APls
Q75: 前阶段是学的js基础,这个阶段是DOM,BOM
- Web APIs是js的应用,大量使用JS基础语法做交互效果
Q76: API
- 理解:API是给程序员提供的一种工具,以便更轻松的实现想要完成的功能。
Web API
- Web AP:是浏览器提供的一套操作浏览器功能和页面元素的API(BOM和DOM)
- 主要针对浏览器做交互效果
- 一般都有输入和输出,很多都是方法
Q77: DOM
- 文档对象模型(document Object Model)是处理可扩展标记语言(HTML或者XML)的标准接口,可以改变网页的内容,结构和样式。
DOM树
- 文档:一个页面就是一个文档,DOM中用document表示
- 元素:页面中的所有标签就是元素,DOM中使用element表示
- 节点:网页中的所有内容都是节点(标签,属性,文本,注释等),DOM中使用node表示。
- DOM把以上内容都看做对象
- DOM树
获取元素
Q78: 根据ID获取
getELementById
script写到标签下面- get获得element元素by通过驼峰命名法
- 参数id是大小写敏感的字符串
- 返回的是一个元素对象
- console.dir 打印我们返回的元素对象 更好的查看里面的属性和方法。
<body>
<div id = "time">2019-09-09</div>
<script>
var timer = document.getElementById('time');
console.log(timer);
console.log(typeof timer);
console.dir(timer);
</script>
</body>
- 返回结果
2019-09-09
object
div#time
getElementsByTagName
- 返回的是 获取过来元素对象的
集合,以伪数组的形式存储 - 如果页面中只有一个li返回都是伪数组
- 页面中没有这个元素,返回的是空的伪数组
- 还可以获取某个元素(父元素)内部所有指定标签名的子元素。
- 注意:父元素必须是单个对象(必须指明是哪个元素对象)。获取的时候不包括父元素自己。
<body>
<ul>
<li>支付方式覅哈哈1</li>
<li>支付方式覅哈哈2</li>
<li>支付方式覅哈哈3</li>
<li>支付方式覅哈哈4</li>
<li>支付方式覅哈哈5</li>
</ul>
<ol id="ol">
<li>支付方式1</li>
<li>支付方式2</li>
<li>支付方式3</li>
<li>支付方式4</li>
<li>支付方式5</li>
</ol>
<script>
//1. 返回的是 获取过来元素对象的集合,一伪数组的形式存储
var list = document.getElementsByTagName('li');
console.log(list);
console.log(list[0]);
//2. 依次打印里面的元素对象
for(var i=0;i<list.length;i++){
console.log(list[i]);
}
//3.如果页面中只有一个li返回都是伪数组
//4.页面中没有这个元素,返回的是空的伪数组
//5.element.getElementsByTagName('标签名')
// var ol = document.getElementsByTagName('ol')
var ol = document.getElementById('ol');
console.log(ol.getElementsByTagName('li'));
</script>
</body>
Q79: 通过html5新增的方法获取 (getElementsByClassName)
-
getElementsByClassName:根据类名获得某些元素的集合 -
querySelector:返回指定选择器的`第一个元素对象.切记,里面的选择器要加符号: .box #nav -
querySelectorAll:返回指定选择器的所有对象的集合
<body>
<div class="box">盒子1</div>
<div class="box">盒子2</div>
<div id="nav">
<ul>
<li>产品</li>
<li>产品</li>
</ul>
</div>
<script>
var box = document.getElementsByClassName('box');//返回伪数组
console.log(box);
var firstBox = document.querySelector('.box');
console.log(firstBox);
var nav = document.querySelector('#nav')
console.log(nav);
var li = document.querySelector('li')
console.log(li);
var allBox = document.querySelectorAll('.box');
console.log(allBox);
</script>
</body>
获取body和html标签
获取body标签
var bodeEle = document.body;
console.log(bodeEle);
console.dir(bodeEle);
获取html元素
var htmlEle = document.documentElement;
console.log(htmlEle);
事件
Q80: 事件三要素
- 事件源:事件被触发的对象
- 事件类型:鼠标点击触发,鼠标经过,键盘按下
- 事件处理程序:通过函数赋值的方式 完成
<body>
<button id="btn">离开家离开</button>
<script>
var btn = document.getElementById('btn')
btn.onclick = function(){
alert('点秋香');
}
</script>
</body>
Q81: 操作元素
- javaScript的DOM操作会改变网页内容,结构和样式,我们可以利用DOM操作元素来改变元素里面的内容。
改变元素的内容
| 属性 | 说明 |
|---|---|
| element.innerText | 从起始内容到终点内容,但它去除html标签,同时空格和换行也会去掉 |
| element.innerHTML | 起始位置到终点位置的全部内容,包含html标签,同时保留空格和换行(W3C推荐) |
<body>
<button>显示当前时间</button>
<div>某个时间</div>
<p></p>
<script>
//点击按钮,div里面会变化
var btn = document.querySelector('button');
var div = document.querySelector('div');
btn.onclick = function () {
div.innerText = getDate();
}
function getDate() {
var date = new Date();
//2022年3月9日星期三
var year = date.getFullYear();
var moth = date.getMonth() + 1;
var datas = date.getDate();
var arr = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六',];
var day = date.getDay();
return '今天是:' + year + '年' + moth + '月' + datas + '日 ' + arr[day];
}
//获取标签
var p = document.querySelector('p');
p.innerText = getDate();
</script>
</body>
操作元素修改元素属性
- innerText,innerHTML改变元素内容
- src,href
- id,alt,title
柏林,莫斯科案例(随便瞎起的,别当真,俄罗斯和德国打不起来的)
<style>
img {
display: block;
}
</style>
<body>
<button id="p1">图片一</button>
<button id="p2">图片二</button>
<img src="./1.jpg" alt="老照片" title="柏林">
<script>
var p1 = document.getElementById('p1');
var p2 = document.getElementById('p2');
var img = document.querySelector('img');
p2.onclick = function () {
img.src = './2.jpg';
img.title = '莫斯科';
}
p1.onclick = function () {
img.src = './1.jpg';
img.title = '柏林';
}
</script>
</body>
分时间案例
- 注意:innerHTML赋值要注意,第一次弄错了!
<style>
img {
width: 300px;
}
div {
margin-top: 12px;
height: 13px;
font-size: 16px;
}
</style>
<body>
<img src="./1.jpg" alt="">
<div>上午好</div>
<script>
var img = document.querySelector('img');
var div = document.querySelector('div');
var date = new Date();
var h = date.getHours();
if (h < 12) {
img.src = './2.jpg';
// div.innerHTML('好好写代码')错误写法!!!
div.innerHTML = '好好写代码'
} else if (h < 18) {
img.src = './1.jpg';
div.innerHTML = '下午好好写代码';
} else if (h < 24) {
img.src = './2.jpg';
div.innerHTML = '晚上好好写代码';
}
</script>
</body>
表单元素的属性操作
- 利用DOM可以操作如下表单属性
- type, value, checked,selected,disabled;
<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 = '点击了'; 不起作用
//表单里面的值是通过value修改的
input.value = '点击了';
//如果想让某个表单被禁用,不能点击用disabled我们想要这个按钮button按钮
// btn.disabled = true;
// this 是指向事件函数的调用者btn
this.disabled = true;
}
</script>
</body>
仿京东隐藏显示隐藏密码明文案例
- 示例代码
<style>
.box {
width: 400px;
border-bottom: 1px solid #ccc;
margin: 100px auto;
}
.box input {
width: 370px;
height: 30px;
border: 0;
outline: none;
}
</style>
<body>
<div class="box">
<button>显示</button>
<input type="password" name="" id="pwd">
</div>
<script>
var btn = document.querySelector('button');
var input = document.getElementById('pwd')
var flag = 0;
btn.onclick = function () {
if (flag == 0) {
input.type = 'text';
btn.innerHTML = '隐藏';
flag = 1;
} else {
input.type = 'password';
btn.innerHTML = '显示';
flag = 0;
}
}
</script>
</body>
操作元素-修改样式属性
- 我们可以通过JS修改元素的大小,颜色,位置等样式。
| 属性 |说明|使用情况|
|:-----?:------?:------?
| element.style| 行内样式操作|样式少,功能简单可以使用|
| element.className | 类名样式操作|样式多,功能复杂使用|
<style>
div {
width: 200px;
height: 200px;
background-color: pink;
}
</style>
<body>
<div></div>
<script>
var div = document.querySelector('div');
div.onclick = function () {
//里面的属性采取驼峰命名法
this.style.backgroundColor = 'red';
this.style.width = '300px';
}
</script>
</body>
-
注意:1.JS里面的样式采取驼峰命名,比如:fontSize. 2.JS修改style样式操作,产生的是行内样式,css权重比较高。
仿淘宝二维码案例
<style>
.box {
position: relative;
height: 88px;
border: 1px solid #ccc;
margin: 100px auto;
font-size: 12px;
text-align: center;
color: #f40;
}
.box img {
width: 60px;
margin-top: 5px;
}
.close-btn {
position: absolute;
top: -1px;
left: 16px;
width: 14px;
height: 14px;
border: 1px solid #ccc;
line-height: 14px;
font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;
cursor: pointer;
}
</style>
<body>
<div class="box">
<img src="./1.jpg" alt="">
<div class="close-btn">x</div>
</div>
<script>
var box = document.querySelector('.box');
var btn = document.querySelector('.close-btn');
btn.onclick = function () {
box.style.display = 'none';
}
</script>
</body>
显示隐藏文本框内容
| 属性 | 说明 |
|---|---|
| onfocus | 获得焦点 |
| onblur | 失去焦点 |
<body>
<input type="text" value="手机">
<script>
//1.获取元素
var text = document.querySelector('input');
text.onfocus = function () {
// console.log('得到了焦点');
if (this.value === '手机') {
this.value = '';
}
//获得焦点需要变黑(文字)
this.style.color = '#333';
}
text.onblur = function () {
// console.log('失去了焦点');
if (this.value === '') {
this.value = '手机';
}
his.style.color = '#999';
}
</script>
</body>
使用className修改样式属性
- 使用className可以修改大量属性,不同于style(只可以修改单个属性)
- 样式少,功能简单可以使用style
- 样式多,功能复杂使用className
- 注意:要先把修改后的样式写在css里,后调用!
-
className会直接覆盖原来的类名,如果想要保存原来的类名
<style>
.first {
width: 300px;
height: 300px;
background-color: pink;
}
.change {
background-color: purple;
color: #fff;
font-size: 25px;
margin-top: 100px;
}
</style>
<body>
<div class="first">文本</div>
<script>
var text = document.querySelector('div');
text.onclick = function () {
// this.style.backgroundColor = 'skyblue';
//当前元素的类名改为change
this.className = 'change';//注意不加点
// 如果想要保存原来的类名
this.className = 'fisrt change';
}
</script>
</body>
密码框验证信息(案例)
<style>
div {
width: 600px;
margin: 100px auto;
}
.message {
display: inline-block;
font-size: 12px;
color: #999;
background: url() no-repeat left center;
padding-left: 20px;
}
.wrong {
color: red;
background-image: url();
}
</style>
<body>
<div class="register">
<input type="password" class="ipt">
<p class="message">请输入6~16位密码</p>
</div>
<script>
var ipt = document.querySelector('.ipt');
var message = document.querySelector('.message');
ipt.onblur = function () {
//根据表单里面
if (this.value.length < 6 || this.value.length > 16) {
message.className = 'wrong message';
message.innerHTML = '您输入的位数不对';
}
}
</script>
</body>
排他思想(算法)
- 先排除其他人的样式,然后再设置自己的样式。
<body>
<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
<button>按钮4</button>
<button>按钮5</button>
<script>
var btn = document.getElementsByTagName('button');
//btn得到的是为数组,里面的每个一元素btn[i]
for (var i = 0; i < btn.length; i++) {
btn[i].onclick = function () {
//1.先把所有按钮的背景颜色去掉
for (var i = 0; i < btn.length; i++) {
btn[i].style.backgroundColor = '';
}
//2.让当前背景颜色为pink
this.style.backgroundColor = 'pink';
}
}
</script>
</body>
表格隔行变色效果
- 新的鼠标事件
| 属性 |说明|
|:-----?:------?
| onmouseover| 鼠标经过|
| onmouseout |鼠标离开|
表单全选取消全选案例
- 全选和取消全选的做法:让下面所有复选框的checked属性(选中状态)跟随,全选按钮即可
<script>
// 1. 全选和取消全选做法: 让下面所有复选框的checked属性(选中状态) 跟随 全选按钮即可
// 获取元素
var j_cbAll = document.getElementById('j_cbAll'); // 全选按钮
var j_tbs = document.getElementById('j_tb').getElementsByTagName('input'); // 下面所有的复选框
// 注册事件
j_cbAll.onclick = function() {
// this.checked 它可以得到当前复选框的选中状态如果是true 就是选中,如果是false 就是未选中
console.log(this.checked);
for (var i = 0; i < j_tbs.length; i++) {
j_tbs[i].checked = this.checked;
}
}
// 2. 下面复选框需要全部选中, 上面全选才能选中做法: 给下面所有复选框绑定点击事件,每次点击,都要循环查看下面所有的复选框是否有没选中的,如果有一个没选中的, 上面全选就不选中。
for (var i = 0; i < j_tbs.length; i++) {
j_tbs[i].onclick = function() {
// flag 控制全选按钮是否选中
var flag = true;
// 每次点击下面的复选框都要循环检查者4个小按钮是否全被选中
for (var i = 0; i < j_tbs.length; i++) {
if (!j_tbs[i].checked) {
flag = false;
break; // 退出for循环 这样可以提高执行效率 因为只要有一个没有选中,剩下的就无需循环判断了
}
}
j_cbAll.checked = flag;
}
}
</script>
自定义属性的操作
- 获取属性值
- element.属性 获取属性值
- element.getArrtibute('属性');
- 设置属性值
- element.属性值 = '值'
- element.setAttribute('属性','值') 主要针对自定义属性
- 移除属性
- removeAttribute('属性')
- 区别:
- element.属性 获取内置属性值(元素本身自带的属性)
- element.getAttribute('属性');主要获得自定义的属性(标准)我们程序员自定义的属性
<body>
<div id="demo" index="1" class="nav"></div>
<script>
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';//改的是div的class
// (2) element.setAttribute('属性', '值'); 主要针对于自定义属性
div.setAttribute('index', 2);
div.setAttribute('class', 'footer'); // class 特殊 这里面写的就是class 不是className
// 3 移除属性 removeAttribute(属性)
div.removeAttribute('index');
</script>
</body>
Tab栏切换布局分析(重点案例)
- 排他思想重点了解
<div class="tab">
<div class="tab_list">
<ul>
<li class="current">商品介绍</li>
<li>规格与包装</li>
<li>售后保障</li>
<li>商品评价()</li>
<li>手机社区</li>
</ul>
</div>
<div class="tab_con">
<div class="item" style="display: block;">
商品介绍模块内容
</div>
<div class="item">
规格与包装模块内容
</div>
<div class="item">
售后保障模块内容
</div>
<div class="item">
商品评价()模块内容
</div>
<div class="item">
手机社区模块内容
</div>
</div>
</div>
<script>
// 获取元素
var tab_list = document.querySelector('.tab_list');
var lis = document.querySelectorAll('li');
var item = document.querySelectorAll('.item');
//for循环绑定点击事件
for (var i = 0; i < lis.length; i++) {
//给某 个li设定索引号
lis[i].setAttribute('index', i);
lis[i].onclick = function () {
//干掉所有人,其余的li清楚class这个类
for (var i = 0; i < lis.length; i++) {
lis[i].className = '';
}
//留下我自己
this.className = 'current ';
//下面模块显示内容
var index = this.getAttribute('index');
// console.log(index);
//排他思想,让其余item这些div隐藏
for (var i = 0; i < item.length; i++) {
item[i].style.display = 'none';
}
item[index].style.display = 'block';
}
}
</script>
H5自定义属性
- 目的:是为了保存和使用数据,有些数据可以保存到页面中而不用保存到数据库中.
1. 设置H5自定义属性
- H5规定自定义属性data-开头为属性名,并且赋值
- 比如:< div data-index='1'> < /div>
- 使用JS设置
- element.setAttribute('data-index',2);
2.获取H5自定义属性
- 兼容性获取 element.getAttribute('data-index');
- H5新增element.dataset.index 或者 element.dataset['index']** ie 11** 才开始支持
<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>
节点操作(页面中所有内容都算节点)
- 利用节点的父子关系获取元素
逻辑性强,兼容性差- 网页中所有元素都是节点,在DOM中,节点使用node表示
-
HTML,DOM树中的所有节点都可以通过javaScript来进行访问,所有的html都可以被修改,也可以被创建和删除.
Q82: 节点概述
一般的,节点至少拥有node Type(节点类型),nodename(节点名称)和nodeValue(节点值)这3个基本属性
- 元素节点 nodeType为1
- 属性节点nodeType为2
- 文本节点 nodeType为3(文本节点包含文字,空格,换行等)
- 实际操作时元素节点
Q83: 节点层级
夫级节点
<script>
// 1. 父节点 parentNode
var erweima = document.querySelector('.erweima');
// var box = document.querySelector('.box');
// 得到的是离元素最近的父级节点(亲爸爸) 如果找不到父节点就返回为 null
console.log(erweima.parentNode);
</script>
子节点
- DOM 提供的方法(API)获取
- 子节点 childNodes 所有的子节点 包含 元素节点 文本节点等等
- children 获取所有的子元素节点 也是我们实际开发常用的
<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>
Q84: 节点操作之第一个子节点和最后一个子节点
- firstChild返回第一个子节点,不管是文本还是元素节点
- firstElemtChild
返回第一个子元素节点,ie9才支持,找不到就返回null - lastElementChild
返回最后一个子元素
<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>
ie9以上才支持
兄弟节点
| 属性 | 说明 | 兼容性 |
|---|---|---|
| node.nextSibling | 下个兄弟节点 | 都可以使用 |
| node.previousSibling | 上个兄弟节点 | 都可以使用 |
node.nextElementSibling |
下个兄弟(元素)节点 | IE9才支持 |
| node.previousElementSibling | 上个兄弟(元素)节点 | IE9才支持 |
var div = document.querySelector('div');
console.log(div.nextSibling);
console.log(div.previousSibling);
console.log(div.nextElementSibling);
console.log(div.previousElementSibling);//unll
如何解决兼容性问题
- 答:自己封装一个兼容性函数
function getNextElementSibling(element) {
var el = element;
while (el = el.nextSibling) {
if (el.nodeType === 1) {
return el;
}
}
return null;
}
获取首位元素几点(避免兼容性问题)
解决方法:
如果想要第一个元素的子节点,可以使用parentNode.children[0]
如果想要最后一个子元素节点,可以使用parentNode.childern[parentNode.chilren.length - 1]
创建节点
- 这些元素原先不存在,是根据我们的需求
动态产生的,所以我们也称为动态创建元素节点。
- 创建节点元素节点
var li = document.createElement('li');
括号内的参数里面永远是标签名比如
li,div,p,span
- 添加节点 node.appendChild(child) node 父级 child 是子级
后面追加元素 类似于数组中的push
ul.appendChild(li);
- 添加节点 node.insertBefore(child, 指定元素);
- 将一个节点添加到父节点的
指定节点的前面,类似于css里面的before伪元素。
var lili = document.createElement('li');
ul.insertBefore(lili, ul.children[0]);
- 我们想要页面添加一个新的元素 : 1. 创建元素 2. 添加元素
发布留言案例
- 留言后没有时间
<body>
<textarea name="" id=""></textarea>
<button>发布</button>
<ul>
</ul>
<script>
// 1. 获取元素
var btn = document.querySelector('button');
var text = document.querySelector('textarea');
var ul = document.querySelector('ul');
// 2. 注册事件
btn.onclick = function () {
if (text.value == '') {
alert('抱歉,没有输入内容')
} else {
// console.log(text.value);
var li = document.createElement('li');
li.innerHTML = text.value;
ul.insertBefore(li, ul.children[0]);
}
}
</script>
</body>
- 留言后有时间显示,可以对留言进行删除,且有按键监听,按下
s光标定到输入框,按下enter留言发布。
注意点:
获取ul节点,然后通过ul.innerHTML+(凭借好的字符串)实现元素的添加,innerHTML是识别标签的。
使用bootstrap框架
Date对象的使用
添加keyup,用来监听键盘按键
- html
<!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css"
integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">
<script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"
integrity="sha384-aJ21OjlMXNL5UyIl/XNwTMqvzeRMZH2w8c5cRVpzpU8Y5bApTppSuUkhZXN0VxHd"
crossorigin="anonymous"></script>
<body>
<div class="container" style="padding-top: 100px;">
<textarea class="form-control" rows="5" placeholder="请留言"></textarea>
<button type="button" class="btn btn-success">发布</button>
<ul class="list-group" style="margin-top: 20px;">
</ul>
<div class="alert alert-warning alert-dismissible" role="alert" style="height: 49px; display: none;">
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true" class="sp">×</span>
</button>
<strong>错误!</strong>你最好输入一些东西后再按按钮
</div>
</div>
</body>
</body>
- js
<script>
var date = new Date();
var year = date.getFullYear();
var moth = date.getMonth() + 1;
var datas = date.getDate();
var btn = document.querySelector("button")
var text = document.querySelector("textarea")
var alerts = document.querySelector(".alert")
var ul = document.querySelector('ul');
var span = document.querySelector(".sp")
//对时间进行格式化
function getTime() {
var thme = new Date();
var h = thme.getHours();
var h = h < 10 ? '0' + h : h
var m = thme.getMinutes();
var m = m < 10 ? '0' + m : m
var s = thme.getSeconds()
var s = s < 10 ? '0' + s : s;
return h + ':' + m + ':' + s;
}
//按钮点击
btn.addEventListener('click', function () {
if (text.value.length == 0) {
alerts.style.display = "block"
} else {
var li = document.createElement('li');
var str = `<li class="list-group-item">${text.value} <span class="date">${year}.${moth}.${datas}-${getTime()}</span><a href="javascript:;">×</a> </li>`
ul.innerHTML = str + ul.innerHTML
//1. 获取所有的a标签
//2. 添加点击事件
//3. 通过a找到父节点li,移除节点方法移除
// for (let i = 0; i < deletea.length; i++) {
// deletea[i].addEventListener('click', function () {
// console.log(this);
// console.log(deletea[i]);
// ul.removeChild(this.parentNode)
// })
// console.log(i);
// deletea[i].onclick = function () {
// console.log(deletea[i]);
// ul.removeChild(this.parentNode)
// }
// }
var deletea = document.querySelectorAll("a");
console.log(deletea);
deletea.forEach(function (item, index) {
item.onclick = function () {
console.log(item);
ul.removeChild(item.parentNode)
}
})
for (let i = 0; i < deletea.length; i++) {
deletea[i].onclick = function () {
console.log(this.parentNode);
ul.removeChild(this.parentNode);
}
}
text.value = ""
}
})
//点击后,隐藏报错框
span.addEventListener('click', function () {
alerts.style.display = "none"
})
//添加按键监听
document.addEventListener('keyup', function (e) {
if (e.keyCode == 83) {
text.focus();
} else if (e.keyCode == 13) {
btn.click();
}
})
//删除
/***
* 获取所有的a,循环添加点击事件,this代表当前点击的a
* 1. 全局this,指向window
* 2. 构造函数内部 this 指向实例化的对象
* 3. 事件处理函数中 this
* */
</script>
- css
<style>
body {
background-image: linear-gradient(120deg, #84fab0 0%, #8fd3f4 100%);
}
div {
/* display: flex; */
width: 100%;
height: 100vh;
/* padding: 200px; */
}
textarea {
margin-bottom: 20px;
resize: none;
}
.date {
float: right;
}
</style>
- 效果

删除节点
- node.removeChild(child)中,删除一个是子节点,返回删除的元素。
- 获取元素
- 删除元素 node.removeChild(child)
- 击按钮依次删除里面的孩子
<body>
<button>删除</button>
<ul>
<li>熊大</li>
<li>熊二</li>
<li>光头强</li>
</ul>
<script>
// 1.获取元素
var ul = document.querySelector('ul');
// 2. 删除元素 node.removeChild(child)
// ul.removeChild(ul.children[0]);
// 3. 点击按钮依次删除里面的孩子
var btn = document.querySelector('button');
btn.onclick = function () {
if (ul.children.length == 0) {
this.disabled = true;
} else {
ul.removeChild(ul.children[0]);
}
}
</script>
</body>
删除留言的案例
- 阻止链接跳转需要添加javascript:void(0);或者javascript:;
<script>
// 1. 获取元素
var btn = document.querySelector('button');
var text = document.querySelector('textarea');
var ul = document.querySelector('ul');
// 2. 注册事件
btn.onclick = function() {
if (text.value == '') {
alert('您没有输入内容');
return false;
} else {
// console.log(text.value);
// (1) 创建元素
var li = document.createElement('li');
// 先有li 才能赋值
li.innerHTML = text.value + "<a href='javascript:;'>删除</a>";
// (2) 添加元素
// ul.appendChild(li);
ul.insertBefore(li, ul.children[0]);
// (3) 删除元素 删除的是当前链接的li 它的父亲
var as = document.querySelectorAll('a');
for (var i = 0; i < as.length; i++) {
as[i].onclick = function() {
// node.removeChild(child); 删除的是 li 当前a所在的li this.parentNode;
ul.removeChild(this.parentNode);
}
}
}
}
</script>
复制节点(克隆节点)
- node.closeNode( ) :该方法返回调用该方法的节点的一个副本。也称为克隆节点/拷贝节点
| 属性值|解释说明|
|:-----?:------?
| node.cloneNode()| 括号为空或者里面是false 浅拷贝 只复制标签不复制里面的内容|
| node.cloneNode(true) |括号为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>
动态生成表格-创建学生数据
- 案例分析:因为里面的学生数据都是动态的,我们需要js动态生成,这里我们模拟数据,自己定义好数据。数据采取对象形式存储。
三种动态创建元素的区别
| 属性 | 说明 |
|---|---|
| element.innerHtml | 当创建多的时候,效率不如createElement()(采用的拼接字符串),创建多个元素效率更高(采用数组形式拼接),结构稍微复杂 |
| document.write() | 直接将内容写入页面的内容流,但是文档流执行完毕,则它会导致页面全部重绘 |
| document.createElement() | 创建多个元素效率低一点点,但是结构清晰 |
DOM重点核心
Q85: 创建
- docoment.write
- innerHTHL (识别html标签)
- createElement (不识别html标签)
Q86: 增
- appendChild (后面添加)
- insertBefore (前面添加)
Q87: 删
1.removeChild
Q88: 改
- 修改元素属性:src,href,title等
- 修改元素内容:innerHTML,innerText
- 修改表单元素:value,type,displed等
- 修改样式属性:style,className
Q89: 查
- DOM提供的API方法:getElementById,getElementByTagName(古老用噶,不太推荐)
- H5提供的新方法:querySelector,querySelectorAll 提倡
- 利用节点操作获取元素:父(parentNode),子(children),兄(previousElementSibling , nextElementSibling ) 提倡。
Q90: 属性操作
- 主要针对自定义属性
- setAttribute:设置dom的属性值
- getAttribute:得到dom的属性值
- removeAttribute:移除属性
Q91: 事件操作
| 鼠标事件 | 触发条件 |
|---|---|
| onclick | 鼠标点击左键时触发 |
| onmouseover | 鼠标经过时触发 |
| onmouseout | 鼠标离开时触发 |
| onfocus | 获得鼠标焦点时触发 |
| oninput | 每次输入都会触发(配合表单更佳) |
| onblur | 失去鼠标焦点时触发 |
| onmousemove | 鼠标移动触发 |
| onmousedown | 鼠标按下时触发 |
事件高级
Q92: 注册事件
- 给元素添加事件,称为注册事件或者绑定事件
- 注册事件有两种方式:传统方式和方法监听注册方式
传统的注册方式:
- 特点:唯一性
- 同一个元素同一个事件只能设置一个处理函数,最后注册的处理函数将会覆盖前面注册的处理函数。
btns[0].onclick = function()
方法监听注册方式:
- w3c标准推荐方式
- addEventListener() 它是一个方法
- IE9之前的IE不支持此方法,可使用attachEvent( ) 代替
- 特点:同一个元素同一个事件可以注册多个监听器
- 按注册顺序依次执行
addEventLIstener 事件监听方式
eventTarget.addEventListener(type,listener[, useCapture])- eventTarget.addEventListene( ) 方法将指定的监听器注册到 eventTarget(目标对象) 上,当该对象触发指定的事件时,就会执行事件处理函数。
三个参数
- type:事件类型字符串,比如click,mouseover,注意这里不带on
- listener:事件处理函数,事件发生时,会调用该监听函数
- useCapture:可选参数,是一个布尔值,默认是
false是冒泡型事件流,也可以是true,这样就会给当前事件添加捕获型事件流。
- 注意:1. 里面的事件类型是字符串 必定加引号 而且不带on;2. 同一个元素 同一个事件可以添加多个侦听器(事件处理程序)
<body>
<button>传统注册事件</button>
<button>方法监听注册事件</button>
<button>ie9 attachEvent</button>
<div>点击我</div>
<script>
var btns = document.querySelectorAll('button');
var div = document.querySelector("div")
// 1. 传统方式注册事件,on+type 缺点:同一事件源,同一事件的唯一性。
btns[0].onclick = function () {
alert('hi');
}
btns[0].onclick = function () {
alert('hao a u');
}
// 2. 事件侦听注册事件 addEventListener ,通过一个事件源中绑定不同的事件处理函数
// (1) 里面的事件类型是字符串 必定加引号 而且不带on
// (2) 同一个元素 同一个事件可以添加多个侦听器(事件处理程序)
//第一种注册方式
btns[1].addEventListener('click', function () {
alert('22');
})
btns[1].addEventListener('click', function () {
alert('33');
})
//第二种注册方式,函数外部声明,后引入
div.addEventListener('click', fn, false)
function fn() {
console.log(3);
}
</script>
</body>
attachEvent 事件监听方式(i9版本之间适用)
- eventTarget.attachEvent(eventNameWitchOn ,callBack)
- eventTarget.attachEvent( )方法把指定的监听器注册到eventTarget(目标对象上),当该对象触发指定事件时,指定的回调函数就会被执行
- 该方法接受两个参数:
- eventNameWithOn: 事件类型字符串,比如onclick,onmouseover,这里要带on
- callback:事件处理函数,当目标触发事件时回调函数被调用
btns[2].attachEvent('onclick', function () {
alert('11');
})
注册事件兼容性方案
- 兼容性处理的原则:首先照顾大多数浏览器,再处理特殊浏览器
function addEventListener(element, evenName, 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;
}
}
Q93: 删除事件(解绑事件)
删除事件的方式
1. 传统注册方式
- element.onclick = null
divs[0].onclick = null;
2. 方法监听注册方式
- eventTarget.romoveEventListener(type,listne [, useCapture]);
- eventTarget.datachEvent(eventNameWithOn,callBack);
删除事件兼容性方案
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;
}
}
DOM事件流
- 事件流:描述的是从页面中接受事件的顺序
- 事件发生时会在元素之间
按照特定的顺序传播,这个传播过程即DOM事件流
<body>
<div class="father">
<div class="son">
</div>
</div>
<script>
var father = document.querySelector(".father")
var son = document.querySelector(".son")
console.log(father);
console.log(son);
onclick只能是冒泡
on + type
son.onclick = function () {
console.log("son");
}
father.onclick = function () {
console.log("faher");
}
document.body.onclick = function () {
console.log("body");
}
document.documentElement.onclick = function () {
console.log("html");
}
</script>

<body>
<div class="father">
<div class="son">
</div>
</div>
<script>
var father = document.querySelector(".father")
var son = document.querySelector(".son")
console.log(father);
console.log(son);
//如果为true就是捕获,从根节点开始
son.addEventListener('click', function () {
console.log("son");
},true)
father.addEventListener('click', function () {
console.log("father");
},true)
father.parentNode.addEventListener('click', function () {
console.log("body");
},false)
document.documentElement.addEventListener('click', function () {
console.log("html");
},false)
</script>
</body>

注意:
- true在那个元素上,哪个元素的事件流就是捕获
- 上面案例中的dody元素和html元素的事件流是冒泡
- 当父子注册的事件一样时,才会有事件流
Q94: 三个阶段
捕获阶段当前目标阶段冒泡阶段
- 事件冒泡:IE最早提出,事件开始时由最
具体的元素吸收,然后逐级向上传播到DOM最顶层节点的过程。 - 事件捕获:网景最早提出,由
DOM最顶层节点开始,然后逐级向下传播到最具体的元素接收的过程。

注意
- JS代码中只能执行或者捕获冒泡其中的一个阶段
- onclick和attachEvent只能得到冒泡阶段。
- addEventListener(type,listener[,useCapture])第三个参数如果是true,表示在事件捕获阶段调用事件处理程序;如果是false(不写默认就是false),表示在事件冒泡阶段调用事件处理程序。
- 实际开发中我们很少使用事件捕获,我们更关注事件冒泡
- 有些事情是没有冒泡的,比如
onblur,onfocus,onmouseenter,onmouseleave。 - 冒泡需要合理运用,负责会带来麻烦。
-
捕获阶段 如果addEventListener 第三个参数是 true 那么则处于捕获阶段 document -> html -> body -> father -> son
-
冒泡阶段 如果addEventListener 第三个参数是 false 或者 省略 那么则处于冒泡阶段 son -> father ->body -> html -> document
三个阶段
事件对象
-
event就是一个事件对象写到我们侦听函数的 小括号里面当形参来看 - 事件对象只有有了事件才会存在,它是系统给我们自动创建的,不需要我们传递参数
- 事件对象 是 我们事件的一系列相关数据的集合 跟事件相关的 比如鼠标点击里面就包含了
鼠标的相关信息,鼠标坐标,如果是键盘事件里面就包含的键盘事件的信息 比如 判断用户按下了那个键 - 这个事件对象我们可以自己命名 比如
event、evt、e - 事件对象也有兼容性问题 ie678 通过
window.event兼容性的写法e = e || window.event;
var div = document.querySelector('div');
div.onclick = function(e) {
// console.log(e);
// console.log(window.event);
// e = e || window.event;
console.log(e);
}
兼容性处理
e = e || window.event;
Q95: 事件对象常见属性和方法
| 事件对象属性方法 | 说明 |
|---|---|
| e.target | 返回触发事件的对象 标准 |
| e.srcElement | 返回触发事件的对象 非标准 ie6-8使用 |
| e.type | 返回事件类型 比如click mouseover 不带on
|
| e.cancelBubble | 该属性阻止冒泡 非标准 ie6-8使用 |
| e.returnValue | 该属性阻止默认事件(默认行为) 非标准 ie6 - 8不使用 比如不让链接跳转 |
| e.preventDefault() | 该方法阻止默认事件(默认行为) 标准 比如不让链接跳转 |
| e.stopPropagtion() | 阻止冒泡 标准 |
- e.target: 返回的是触发事件的对象(元素) this 返回的是绑定事件的对象(元素)
var ul = document.querySelector('ul');
ul.addEventListener('click', function (e) {
// 我们给ul 绑定了事件 那么this 就指向ul
console.log(this);
console.log(e.target);
// e.target 指向我们点击的那个对象 谁触发了这个事件 我们点击的是li e.target 指向的就是li
})
this 和 e.target的区别
- 区别 :
e.target 点击了哪个元素,就返回哪个元素,this: 哪个元素绑定了这个点击事件,那么就返回谁 - 注意:跟 this 有个非常相似的属性 currentTarget ie678不认识(了解1)
this是事件绑定的元素,是函数的调用者(绑定这个事件的元素)
e.target是事件触发的元素
Q96: 阻止默认行为
- 阻止默认行为(事件)
让链接不跳转或者让提交按钮不提交
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);
}
Q97: 阻止冒泡
- stopPropagation
<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>
阻止事件冒泡的兼容性解决方案
if(e && e.stopPropagation){
e.stopPropagation();
}else {
window.event.cancleBubble = true;
}
事件委托(代理,委派)
- 事件委托:也称为事件代理,在jQuery里面称为事件委派
- 原理:不要给每个字节点单独设置事件监听器,而是事件监听器设置在其父节点上,通过
e.target进行判断,然后利用冒泡原理影响设置每个子节点。 - 事件委派的作用:只操作一次DOM,提高了程序执行的性能。
- 使用场景:
-
大量元素添加事件,提高性能,减少dom操作
-
动态创建的元素
<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';
})
</script>
</body>
<body>
ul>li*10{&&} emm语法,快速生成
<ul>
<li>01</li>
<li>02</li>
<li>03</li>
<li>04</li>
<li>05</li>
<li>06</li>
<li>07</li>
<li>08</li>
<li>09</li>
<li>10</li>
</ul>
<script>
//操作dom10次
var lis = document.querySelectorAll("li")
lis.forEach(function (v, i) {
v.onclick = function () {
this.style.color = "red"
}
})
//事件委派,操作dom一次,给父元素添加事件
var ul = document.querySelector("ul")
ul.onclick = function (e) {
e = e || window.event;
e.target.style.color = "red"
console.log(e.target);
}
</script>
</body>
<!-- 事件三要素:
注册事件的方式:on+type,事件监听(兼容性问题)
事件流:捕获阶段,目标阶段,冒泡阶段
事件对象:鼠标事件对象,键盘事件对象
事件委派:冒泡型事件流
1. 大量元素添加事件,提高性能,减少dom操作
2. 动态创建的元素
-->
事件委派的好处
常用的鼠标事件
- 静止鼠标右键菜单
- contentmenu主要控制应该何时显示上下文菜单,主要用于程序员取消默认的上下文菜单
<body>
我是一段不愿意分享的文字
<script>
// 1. contextmenu 我们可以禁用右键菜单
document.addEventListener('contextmenu', function(e) {
e.preventDefault();
})
// 2. 禁止选中文字 selectstart
document.addEventListener('selectstart', function(e) {
e.preventDefault();
})
</script>
</body>
- 禁止鼠标选中(selectstart 开始选中)
document.addEventListener('selectstart', function (e) {
e.preventDefault();
})
Q98: 鼠标事件对象
| 鼠标事件对象 | 说明 |
|---|---|
| e.clientX | 返回鼠标相对于浏览器可视区的X坐标 |
| e.clientY | 返回鼠标相对于浏览器窗口可视区的Y坐标 |
| e.apgeX | 返回鼠标相当于文档页面的X坐标 IE9+支持 |
| e.pageY | 返回鼠标相当于文档页面的Y坐标 IE9+支持 |
| e.screenX | 返回鼠标相对于电脑屏幕的X坐标 |
| e.screenY | 返回鼠标先对于电脑屏幕的Y坐标 |
- e.clientX: 返回鼠标在可视区的x坐标
- e.clientY: 返回鼠标在可视区的y坐标
console.log(e.clientX);
console.log(e.clientY);
- e.pageX:鼠标在页面文档的x坐标
- e.pageY:鼠标在页面文档的y坐标
console.log(e.pageX);
console.log(e.pageY);
- e.screenX:creen 鼠标在电脑屏幕的x坐标
- e.screenY:creen 鼠标在电脑屏幕的y坐标
console.log(e.screenX);
console.log(e.screenY);
跟随小天使案例
<body>
<img src="./images/angel.gif" alt="">
<script>
var pic = document.querySelector('img');
document.addEventListener('mousemove', function (e) {
// 1. mousemove只要我们鼠标移动1px 就会触发这个事件
// console.log(1);
// 2.核心原理: 每次鼠标移动,我们都会获得最新的鼠标坐标, 把这个x和y坐标做为图片的top和left 值就可以移动图片
var x = e.pageX;
var y = e.pageY;
//3 . 千万不要忘记给left 和top 添加px 单位
pic.style.left = x - 50+ 'px';
pic.style.top = y - 40+ 'px';
});
</script>
</body>
常用的键盘事件
keycode对照表
| 键盘事件 | 触发条件 | 使用keycode的情况 |
|---|---|---|
| onkeyup | 某个键盘按键被松开时触发 | 不区分大小写 |
| onkeydown | 某个键盘按键被按下时触发 | 不区分大小写 |
| onkeypress | 某个键盘被按下时触发 但是它不识别功能键 比如: ctrl shift等 |
区分大小写 |
<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>
- 注意:三个事件的执行顺序 keydown -- keypress -- keyup
ASCII表[1:1]
- 键盘事件对象
- 注意:我们的onkeyup 和onkeydown事件不区分字母大小写,onkeypress 事件 区分字母大小写 .我们在实际开发中,我们更多的使用keydown和keyup,他可以识别所有的键(包括功能键),keypress不识别功能键,但是keycode属性能区分大小写,返回不同的ASCII值。
| 键盘对象属性 |属性|
|:-----?:------?
| keyCode| 返回该键的ASCII值|
模拟京东按键输入的内容
- 核心思路:检测用户是否按下了s 键,如果按下s 键,就把光标定位到搜索框里面;
- 使用键盘事件对象里面的keyCode 判断用户按下的是否是s键;
- 搜索框获得焦点: 使用 js 里面的 focus() 方法;
<body>
<input type="text">
<script>
// 核心思路: 检测用户是否按下了s 键,如果按下s 键,就把光标定位到搜索框里面
// 使用键盘事件对象里面的keyCode 判断用户按下的是否是s键
// 搜索框获得焦点: 使用 js 里面的 focus() 方法
var search = document.querySelector('input');
document.addEventListener('keyup', function (e) {
if (e.keyCode == 83) {
search.focus();
}
});
</script>
</body>
this指向
this的指向在函数定义时是确定不了的,只有函数执行的时候才能确定this到底指向谁,一般情况下this的最终执向的是那个调用它的对象。
- 全局作用域或者普通函数中的this指向全局对象window(注意
定时器里的this指向window) - 方法调用中谁调用this指向谁。
- 构造函数中this指向构造函数的实例。
模拟京东快递快递单号查询案例
案例分析:
1. 快递单号输入内容时, 上面的大号字体盒子(con)显示(这里面的字号更大)
2. 表单检测用户输入: 给表单添加键盘事件
3. 同时把快递单号里面的值(value)获取过来赋值给 con盒子(innerText)做为内容
4. 如果快递单号里面内容为空,则隐藏大号字体盒子(con)盒子、
5. 当我们失去焦点,就隐藏这个con盒子
6. 当我们获得焦点,就显示这个con盒子
- 注意:keydown和keypress在文本框里面的特点:他们两个事件触发的时候,文字还没有落入文本框中。keyup事件触发的时候文字以及落入文本框里了。
BOM概述
- BOM:即浏览器对象模型,它提供了独立于内容而与浏览器窗口进行交互的对象,其核心对象是window.
- BOM:由一系列相关的对象构成,并且每个对象都提供了很多方法和属性。
- 浏览器对象模型
- 把浏览器当作一个对象来看待
- BOM的顶级对象是window
- BOM学习的是浏览器窗口的交互的一些对象
- BOM是浏览器厂商在浏览器上定义的,兼容性较差。








