17.对象
1、对象:⽤来存储多个数据的 是由多个键值对/key value对组成的 ⽤来描述⼀个事物的
相当于多个变量的集合
2、格式 :{key:value,key:value} 键/值对 属性名:属性值
3、对象的属性值是不限制数据类型的,甚至还可以是对象类型的数据
对象的属性名的数据类型⼀定是字符串,所以属性名可以省略引号,如果不加,js会⾃动帮你添加
4、 (1)对象的访问:对象名.属性名
(2)对象的更改/添加:对象名.属性名=新值 如果本身存在这个属性就是更改,本身如果没有那就是添加
如果属性名是用变量表示的,则更改时为:对象名[属性名]=新值
(3)对象的属性的删除:delete 对象.属性
(4)对象的循环:
for(var 变量名 in 所要遍历的对象){
变量名代表的是属性名,要访问对象的所有属性值时要按照 对象名[属性名]的形式访问。
如console.log(obj[key]);
}
变量名常用key,扮演的就是对象的每个属性名,一对一对的向前推进,直到所有的属性都结束。
如:
var money = 2500
var age = "money"
var obj = { name: "张三", [age]: money, gender: "男", address: "北京" }
//修改对象属性
obj.name = "Lily"
obj.gender = "女"
obj[age] = 5000
obj.abc = "hello"
console.log(obj)
//显示结果:{name: 'Lily', money: 5000, gender: '女', address: '北京', abc: 'hello'}
//删除属性
delete obj.address
console.log(obj)
//显示结果:{name: 'Lily', money: 5000, gender: '女',abc: 'hello'}
//对象的循环
for (var key in obj) {
//console.log(key) //输出的是所有的属性名,循环了4次
console.log(obj[key])//输出的是所有的属性值,key是变量名
}
5、对象的属性名如果是变量的话,想要后续用变量名修改属性名,那么需要给属性名加 [ ]
如:
//属性值和属性名的内容都可以用变量来表示
var name = "张三"
name = "李四"//变量名
var age = "money"//变量名
var money = 2000
var obj = { name: name, [age]: money, gender: "男", address: "北京" }
//属性名age变为了money,用变量来表示属性名要加[],表示当前的不是字符串而是属性名
console.log(obj)
//显示结果:{name: '李四', money: 2000, gender: '男', address: '北京'}
数组VS对象
相同点:都是用来存储多个数据的;内容都是可更改的;
数组:用来存储同类型的数据 (虽然可以存储不同类型的数据,但不这么用);
对象:用多个数据共同描述一个事物;
18.内置对象
⾯向对象编程(老板):通过操作对象去实现需求,不关⼼其中的过程和内部是怎样实现的。
⾯向过程编程(员工):
难点:不知道在什么场合(需求)应该用什么人物(内置对象)在什么时间(某个阶段)释放什么技能(调用什么属性或者什么方法)。
内置对象:js中已经定义好了的现成的对象,有着现成的属性和⽅法供我们直接使⽤。
js中⼀共26个内置对象,如数组
⾃定义对象:我们⾃⼰创建的对象,属性和方法自己去定义。
基本包装类型:它们既是原始数据类型,背后又可以作为对象去调用的属性和方法。为了便于操作“基本类型值”,JS 提供了 三个 特殊的引⽤类型:Boolean、Number、String。这些类型和其他引⽤类型相似,但同时 也具备 与各⾃基本类型相应的特殊⾏为。 实际上:每当读取⼀个基本类型的数据的时候, “后台就会自动创建⼀个与该类型对应的基本包装类型的对象”,从而能够调⽤⼀些⽅法和属性来操作这些数据。
如:var str=”hello”;str.length访问的不是str的length属性,基本数据类型没有属性,而是这些基本数据背后的String对象的属性。
1.String对象(要大写) 字符串是不容更改的
属性:
1、length 返回字符串的长度
方法:
1、toUpperCase() 转⼤写,只针对英文的字符串
2、toLowerCase() 转⼩写,只针对英文的字符串
转换大小写通常用于登录时的验证码忽略大小写的时候。
3、substring(start,end) 截取⼦字符串,含头不含尾 中英文字符串都可以
如果只给⼀个参数,代表从哪⼀位开始截取,截到最后
4、slice()同上 但主要是用于截取子数组的
5、indexOf(所想查找的关键字,从哪一位开始找) 查找关键字,返回的是关键字符的⻆标,找到就结束,找不到返回-1
默认返回的是第一次出现的位置 ,再次出现的不会显示
查找关键字通常用于违禁词汇的检测
如:
/* 违禁词汇用数组来存储*/
var words = ["钱", "转账", "支付宝", "银行卡", "话费"]
var str = "李哥在吗,我是你二大爷啊,我换号了,电话没话费了,给我支付宝转20块钱,我去冲个话费,明天还你"
// var str = "李哥在吗,今晚我想吃鱼了"
//检测是否有违禁词汇,使用循环来检测
for (var i = 0; i < words.length; i++) {
var index = str.indexOf(words[i])
if (index != -1) {
alert("请注意核实对方的身份,保障财产安全")
break;//当一句话中出现多个违禁词汇时,只需要提示一次就可以,使用break当出现违禁词汇后就直接停止循环
}
}
6、toString() 转成字符串,可以把任意的数据类型都转化为字符串类型,显示类型转换
字符串类型的数据和其他类型的数据输出的结果颜色是不同的。
7、split(切割符) 字符串切割 字符串🡪数组 ⼀定会切成数组,即使切不开也会变成数组
如果首字母是切割符,则第一个会产生空字符‘’;如果首字母不是切割符,则按照切割符将字符串分开;如果切割符在字符串中不存在,无法切割开字符串时,还是会变成一项的数组;如果想将字符串的每个字母都切开且不丢失,可以将切割符设置为空字符””
8、concat(字符串1,字符串2… ) 字符串合并 但不使用,直接用+连接字符串即可
//String对象的属性
var str = "Hello"
// 1 length 返回字符串的长度
console.log(str.length)//输出结果:5
//String对象的方法
// 1 toUpperCase() 转大写 用于英文字符串
str.toUpperCase();
console.log(str)//输出结果:Hello,并没有发生改变,因为字符串是不可更改的
console.log(str.toUpperCase())//正确,输出结果:HELLO,直接输出或者将转换后的内容赋值给另一个变量再输出
// 2 toLowerCase() 转小写 用于英文字符串
console.log(str.toLowerCase())//输出结果:hello
/* 3 substring(start,end) 截取子字符串,含头不含尾 若只有一个参数则从该位截取到结尾
用于中英文字符串*/
console.log(str.substring(1, 3))//输出结果:el
console.log(str.substring(1))//输出结果:ello,从该位置截取到结尾
var nstr = "你好呀!!"
console.log(nstr.substring(1))//输出结果:好呀!!
console.log(nstr.substring(0, 2))//输出结果:你好
console.log(nstr.substring(1, 2))//输出结果:好
// 4 slice() 截取子数组的,同substring()的用法
console.log(str.slice(1, 3))//输出结果:el
console.log(str.slice(1))//输出结果:ello,从该位置截取到结尾
var nstr = "你好呀!!"
console.log(nstr.slice(1))//输出结果:好呀!!
console.log(nstr.slice(0, 2))//输出结果:你好
console.log(nstr.slice(1, 2))//输出结果:好
// 5 indexOf(所想查找的关键字,开始查找的位置) 查找关键字
var str = "where are you from"
console.log(str.indexOf("you"))//输出结果:10
console.log(str.indexOf("your"))//输出结果:-1
console.log(str.indexOf("e"))//输出结果:2
console.log(str.indexOf("e", 3))//输出结果:4,从第3位开始查
// 6 toString() 将其他类型的数据转换为字符串
var num = 123
console.log(num)//输出结果:123
console.log(num.toString())//输出结果:123
var arr = [1, 2, 3, 4]
console.log(arr)//输出结果:[1,2,3,4]
console.log(arr.toString())//输出结果:1,2,3,4
// 7 split(切割符) 将字符串切割为数组
//切割符不再首字母上的情况
var str = "h-e-l-l-o"
var arr = str.split("-")
console.log(arr)//输出结果:['h','e','l','l','o']
//切割符在首字母上的情况,第一个产生空字符
var str = "abacad"
var arr = str.split("a")
console.log(arr)//输出结果:['','b','c','d']
var str = "hello"
var arr = str.split("e")
console.log(arr)//输出结果:['h','llo']
var arr = str.split("l")
console.log(arr)//输出结果:['he','','o']
//切割符切不开的情况
var str = "hello"
var arr = str.split("m")
console.log(arr)//输出结果:['hello']
//切割符为空字符的情况
var str = 'hello'
var arr = str.split("")
console.log(arr)//输出结果:['h','e','l','l','o']
// 8 concat(字符串1,字符串2...) 字符串合并
var str1 = "hello "
var str2 = "world"
var str3 = " hi world"
var nstr = str1.concat(str2, str3)
console.log(nstr)//输出结果:hello world hi world
2.Number对象
toString(转成字符串)
toFixed()按⼏位⼩数四舍五⼊
console.log(Number(“400“))//输出结果:400,,将字符串类型的数字转为数字类型的数字
var a = parseInt("255px")//输出结果:255
var a = parseInt("o255px")//输出结果:NaN
var a = parseInt("2a55")//输出结果:2
var a = parseFloat("-255.5px")//输出结果:-255.2
var a = parseFloat("-255px")//输出结果:-255
var a = Number("255") + 10//输出结果:265
console.log(a)
3.Boolean对象
toString(转成字符串)
4.Array对象
4.1 Array对象的属性和方法
属性:
- length
方法:
- toString() 转成字符串
- slice(start,end) 截取⼦数组 含头不含尾 若只有一个参数,代表从该位开始直到结束
- indexOf(所想查找的关键字,从哪一位开始找) 查找关键字
- join(连接符) 数组🡪字符串 把数组链接成字符串,结果⼀定是字符串
连接符写什么就用什么将数组的内容连接起来;如果连接符不写,会自动给加上逗号,就像toString()一样;要是只想将数组的内容连接起来,没有任何符号,可以将连接符设置为空字符””。
- concat(数组1,数组2,数组3…) 连接数组,将多个数组合并为一个数组
- Array.isArray() 判断是不是数组的,因为数组的类型为对象,使用typeof不能区分数组和对象,它们的类型都是object
var arr = [1, 2, 3]
console.log(Array.isArray(arr))//输出结果:true
- map() 对数组的每一项进行操作,返回一个操作后的新数组 自动对数组循环操作
arr.map(function(item,index){return 新值}) item代表的是循环中的每一项,index代表的是角标 必须要有return,return后面的内容就是新数组的每一项,但是数组的长度是不会更改的。 可以使用变量
var arr = [1, 2, 3, 4, 5]
var a = arr.map(function (item) { return "你好" })
console.log(a)//输出结果: ['你好', '你好', '你好', '你好', '你好']
// item代表的就是数组中的每一项,而不是角标
var arr = [1, 2, 3, 4]
var narr = arr.map(function (item) { return "星期" + item })
console.log(narr)//输出结果:['星期1', '星期2', '星期3', '星期4']
for() VS map()
map:需要一个新数组,新数组的每一项都是基于原数组进行改装的,数组的长度不会发生改变,必须有return。
for:对数组中的某些项可以不做处理。
8、filter() 过滤,返回⼀个符合指定条件的数组 自动对数组循环操作
arr.filter(function(item,index){return 要筛选的条件}) item代表的是数组中的每一项数据
var arr = [1, 2, 3, 4, 5, 6]
var narr = arr.filter(function (item) { return item > 3 })
console.log(narr)//输出结果:[4,5,6]
9、every() 判断是否每一项都满足return的条件,返回布尔值 自动对数组循环操作
arr.every(function(item){return 条件})
var arr = [1, 5, false, "hello"]
var narr = arr.every(function (item) { return typeof (item) == "number" })
console.log(narr)//输出结果:false
10、some() 判断数组中是否有满足条件的项,返回布尔值
arr.some(function(item){return 条件})
var arr = [1, 5, false, "hello"]
var narr = arr.some(function (item) { return typeof (item) == "number" })
console.log(narr)//输出结果:true
11、includes(要找的值) 判断数组中是否有指定项,返回布尔值
includes VS indexOf:
includes:只是看看是否有要找的值,并不返回他的位置。
indexOf:返回所查找值的位置,还可以使用第二个参数返回多个位置。
12、forEach(funcion(item,index){console.log(item,index)}) 循环 对数组的每一项执行一件事,不用必须有return
map() VS forEach() VS for()
map:必须有return,必须在特定的场景下:在原数组的基础上做修改。
forEach:不用必须有return,必须在特定的场景下:对数组的每一项都要做这件事。
for:通用。
对于数组对象的循环有:for()、map()、filter()、some()、every()、forEach()
------------------------------以上所有⽅法都不能修改原数组---------------------------
-
1、push(要添加的数据,可以是多个数据) 向数组的结尾追加元素 返回值为新数组的长度
var arr = [1, 2, 3]
var a = arr.push(4, 5, 6)
console.log(a)//输出结果为6
2、unshift( ) 向数组开头追加元素
3、pop() 删除数组最后⼀位元素
4、shift() 删除数组第⼀位元素
5、splice(从哪⼀位开始删除,删⼏个,新值1,新值2…) 在任意位置添加和删除元素 新值的位置为删去的数据的位置 要是不想删除只想要添加则只需把删几个的值改为0即可
返回的是被处理之后的数组
6、reverse() 数组反转
7、sort() 数组排序 不是按照大小来排序的,而是按照编码来排的,先比较第一位,再比较第二位
arr.sort(function(a,b){return a-b}); 若想从大到小,将a-b改为b-a
var arr = [4, 8, 78, 58, 69, 52, 45, 32, 12]
arr.sort(function (a, b) { return a - b })
console.log(arr)//输结果: [4, 8, 12, 32, 45, 52, 58, 69, 78]
//数组的方法
var arr = [1, 2, 3, 4, 5]
// 1 toString() 转换为字符串
var str = arr.toString()
console.log(str)//输出结果:1,2,3,4,5
// 2 slice(start,end) 截取子数组
console.log(arr.slice(1, 4))//输出结果:[2,3,4]
// 3 indexOf(所想查找的关键字)
console.log(arr.indexOf("3"))//输出结果:-1
console.log(arr.indexOf(3))//输出结果:2
// 4 join(连接符) 数组-->字符串
var arr = [1, 2, 5, 8]
console.log(arr.join("号、") + "号同学")//输出结果:1号、2号、5号、8号同学
var arr = ["你", "好", "呀", "小", "姐", '姐']
console.log(arr.join("-"))//输出结果:你-好-呀-小-姐-姐
//不写连接符,会自动加上逗号
console.log(arr.join())//输出结果:你,好,呀,小,姐,姐
console.log(arr.toString())//输出结果:你,好,呀,小,姐,姐
//要是想将数组内的内容连接成一句话,不加任何的符号,可以用空字符""来拼接
console.log(arr.join(""))//输出结果:你好呀小姐姐
//同理,将字符串切割为数组时
var str = 'hello'
var arr = str.split("")
console.log(arr)//输出结果:['h','e','l','l','o']
// 5 concat(要添加进去的数组) 数组合并
var arr = [1, 2, 3]
var arr2 = [4, 5, 6]
var arr3 = [7, 8]
var narr = arr.concat(arr2, arr3)
console.log(narr)//输出结果:[1,2,3,4,5,6,7,8]
// 6 Array.isArray() 判断是否为数组
var arr = [1, 2, 3]
var obj = { name: "lili" }
var a = Array.isArray(arr)
console.log(a)//输出结果:true
var a = Array.isArray(obj)
console.log(a)//输出结果:false
var a = Array.isArray(123)
console.log(a)//输出结果:false
// 7 map(function(item){return 新值}) 基于原数组的每一项进行操作
var arr = [1, 2, 3, 4, 5]
var a = arr.map(function (item) { return "你好" })
console.log(a)//输出结果: ['你好', '你好', '你好', '你好', '你好']
//item代表的就是数组中的每一项,而不是角标
var arr = [1, 2, 3, 4]
var narr = arr.map(function (item) { return "星期" + item })
console.log(narr)//输出结果:['星期1', '星期2', '星期3', '星期4']
// 8 filter(function(item,index){return 要筛选的条件})
var arr = [1, 2, 3, 4, 5, 6]
var narr = arr.filter(function (item) { return item > 3 })
console.log(narr)//输出结果:[4,5,6]
//筛选的是条件 return 1 "hello"代表的是true
var narr = arr.filter(function (item) { return 1 })
console.log(narr)//输出结果:[1,2,3,4,5,6]
// 9 every(function(item){return 条件})
var arr = [1, 5, false, "hello"]
var narr = arr.every(function (item) { return typeof (item) == "number" })
console.log(narr)//输出结果:false
// 10 some(function(item){return 条件})
var arr = [1, 5, false, "hello"]
var narr = arr.some(function (item) { return typeof (item) == "number" })
console.log(narr)//输出结果:true
// 11 includes(要找的值)
var arr = [1, 2, 5, "hello"]
console.log(arr.includes("hello"))//输出结果:true
console.log(arr.includes("hi"))//输出结果:false
// 12 forEach(function(item,index){每一项都做的事情}) 循环
var arr = [1, 8, 9, 5, 7]
arr.forEach(function (item, index) {
console.log(item, index)
})//输出结果:1 0 / 8 1 / 9 2 / 5 3 / 7 4
//-----------------------------以下方法可以修改原数组
// 1 push() 向数组结尾追加数据
var arr = [1, 2, 3]
arr.push(4, 5, 6, 7)
console.log(arr)//输出结果:[1,2,3,4,5,6,7]
// 2 unshift() 向数组开头追加数据
var arr = [1, 2, 3]
arr.unshift(4, 5, 6)
console.log(arr)///输出结果:[4,5,6,1,2,3]
// 3 pop() 删除数组的最后一项
var arr = [1, 2, 35, 4]
arr.pop()
console.log(arr)//输出结果:[1,2,35]
// 4 shift() 删除数组的第一项
var arr = [1, 2, 5, 8, 9]
arr.shift()
console.log(arr)//输出结果:[2,5,8,9]
// 5 splice(从哪一位开始删除,删几个,要新增的数据1,要新增的数据2) 再数组的任意位置删除或添加数据
//从某一位开始删除
var arr = [1, 2, 3, 4]
arr.splice(1, 2)//从第1个位置开始删除,删除两个数据
console.log(arr)//输出结果:[1,4]
//在删除的位置上添加新数据
var arr = [1, 2, 3, 4]
arr.splice(1, 2, 78, 99, 100)//从第1个位置开始删除,删除两个数据,并将78,99,100放在第1位开始的位置
console.log(arr)//输出结果:[1,78,99,100,4]
//不想删除数据,只想要添加数据
var arr = [1, 2, 3, 4]
arr.splice(1, 0, 100)
console.log(arr)//输出结果:[1,100,2,3,4]
// 6 reverse() 数组反转
var arr = [1, 2, 3, 4, 5]
arr.reverse()
console.log(arr)//输出结果:[5,4,3,2,1]
// 7 sort() 数组排序
var arr = [1, 5, 88, 4, 8, 25, 96, 45, 12, 65]
arr.sort()
console.log(arr)//输出结果:[1, 12, 25, 4, 45, 5, 65, 8, 88, 96],只是按照编码排序,并未真正排序
var arr = ["你", "号", "排", "数", "安"]
arr.sort()
console.log(arr)//输出结果: ['你', '号', '安', '排', '数'],按编码排序
//正常数值排序 如果想要从大到小排序,将a-b改为b-a即可
var arr = [1, 5, 88, 4, 8, 25, 96, 45, 12, 65]
arr.sort(function (a, b) { return a - b })
console.log(arr)//输出结果: [1, 4, 5, 8, 12, 25, 45, 65, 88, 96]
var arr = ["你", "号", "排", "数", "安"]
arr.sort(function (a, b) { return a - b })
console.log(arr)//输出结果:['你', '号', '排', '数', '安']
案例:××××将字符串的首字母转为大写后输出:字符串切割转数组+拿到数组的某一项的某一位+转大写toUpperCase()+截取子字符串拼上去+数组join拼接为字符串
var str = "where are you from ? i come from china"
var wordsArr = str.split(" ")//字符串切割转为数组
//对字符数组的每一项进行操作
for (var i = 0; i < wordsArr.length; i++) {
//将每个单词的首字母转为大写,并将单词剩余的部分拼接上去
wordsArr[i] = wordsArr[i][0].toUpperCase() + wordsArr[i].substring(1)
}
//将数组转换为字符串输出
str = wordsArr.join(" ")
console.log(str)
//输出结果:Where Are You From ? I Come From China
4.2 数组去重 面试题常考⭐⭐⭐⭐⭐
注意数组长度会变化的时候,角标也会发生变化,在循环的时候要格外注意角标的变化情况。
从第0项开始,每一项都与第0项比较,如果二者相等,则把后者从数组中使用slice()方法删除,这样就保证了第0项在数组中是唯一的;再从第1项开始,后面的每一项都与第1项比较,如果相等,则把后者从数组中删除,这样就保证了第1项在数组中是唯一的;…,依次进行比较。
但此时,还会存在一些bug,在删除重复的数据之后,数组长度发生变化,它后面数据都会向前移动一位,角标会减1,这时如果再次进行比较的时候应该从被删除数据的角标开始比较,否则会出现跳过一些数据的现象发生。
解决方法一:角标回退
每次在删除数据的时候,下次在拿数据的时候拿的是被删除数据所在角标的数据。
解决方法二:倒序循环
拿最后一项与前面的每一项相比较,如果相等,则删除前面的项,这时即使数组的角标发生变化,变化的是后面的,前面要拿的项的角标并不会发生变化。
解决方法三:indexOf()索引方法,循环遍历原数组,将新数组中在原数组中没有的数据放入新数组中,最后输出新数组。
解决方法四:ES6中的Set()自动去重------最简单的方法
//方法一:角标回退
var arr = [1, 2, 3, 2, 5, 6, 7, 6, 6, 6, "a", true, "a", "a", "b", "c", false, true]
for (var i = 0; i < arr.length; i++) {
for (var j = i + 1; j < arr.length; j++) {
if (arr[i] === arr[j]) {
arr.splice(j, 1)
//如果不j--的话,此时的去重并不彻底,因为在遇到第一个重复项删除之后,j++,下一个要比较的时候拿到的在原来的数组中占的位置不是j++的位置,而是靠后一个的位置,数组的角标不会跳着显示,角标改变会出现有些数据在循环的时候被跳过
j--;
//当有重复项时将该项删除后,下一次开始比较的时候还是从该项的角标开始比较,否则会出现跳过某些项的现象
//在有删除的情况时才进行角标回退
}
}
}
console.log(arr) // [1, 2, 3, 5, 6, 7, 'a', true, 'b', 'c', false] 11项
//方法二:倒序循环,最后一项
var arr = [1, 2, 3, 2, 5, 6, 7, 6, 6, 6, "a", true, "a", "a", "b", "c", false, true]
for (var i = arr.length - 1; i >= 0; i--) {
for (var j = i - 1; j >= 0; j--) {
if (arr[i] === arr[j]) {
arr.splice(j, 1)
i--
//i--是为了取出的标杆是正确的,当删除一个数据之后,数组长度发生变化,标杆的角标也发生了变化,为了之后比较时的标杆不变,将标杆的角标-1,以便于拿到的标杆在一轮循环中始终是同一个
}
}
}
console.log(arr)
//方法三:使用indexOf()索引,循环遍历原数组,如果narr数组中没有该项,则把该项放进新数组narr中,如果narr数组中有了该项,则不放入arr数组中。
var arr = [1, 2, 3, 2, 5, 6, 7, 6, 6, 6, "a", true, "a", "a", "b", "c", false, true]
var narr = []
for (var i = 0; i < arr.length; i++) {
if (narr.indexOf(arr[i]) == -1) {
narr.push(arr[i])
}
}
console.log(narr)
//方法四:ES6的 Set()自动去重
let arr = [1, 2, 3, 2, 5, 6, 7, 6, 6, 6, "a", true, "a", "a", "b", "c", false, true]
let set = new Set(arr)
console.log([...set])//先拆开再合并
//[1, 2, 3, 5, 6, 7, 'a', true, 'b', 'c', false]
4.3 冒泡排序
- function arrSort(arr) {
- for (var j = 0; j < arr.length - 1; j++) {
- for (var i = 0; i < arr.length - 1 - j; i++) {
- if (arr[i] > arr[i + 1]) {
- var box = arr[i]
- arr[i] = arr[i + 1];
- arr[i + 1] = box
- }
- }
- }
- return arr
- };
- var c=[[2,54,6,9,878,123],[12,63,5,778,986,156],[12,6,5,778,76
14
- for(var m=0;m<c.length;m++){
- console.log(arrSort(c[m]))
- }
function sort(arr){
for(var i=0;i<arr.length-1;i++){
for(var j=0;j<arr.length-1-i;j++){
if(arr[j]>arr[j+1]){
var n=arr[j]
arr[j]=arr[j+1]
arr[j+1]=n
}
}
}
return arr
}
5.正则表达式对象RegExp
正则表达式:定义字符串中字符出现的规律,例如登陆注册时的格式规则
1、定义的格式规则:
(1)正则表达式要求写在 /正则表达式/ 中 ;
(2)中括号[]⽤来存放备选字符,⼀个中括号只能代表⼀位字符的匹配规则;(中括号里面不要加符号,否则会被认为是备选字符;)
(3)数量词 {}
{num} 代表前⾯⼀位规则重复⼏次,如果想要多个规则重复,将想重复的加括号括起来就行。例如:var reg=/[1]([3456789][0123456789]){9}/ ,共有19位字符的规则。
{min,} 代表前⾯⼀位规则⾄少重复min次。
{min,max} 代表前⾯⼀位规则⾄少min,最多max。
特殊数量词:
? 代表前面一位规则可有可无 即最少0次最多⼀次 {0,1}
* 代表前面一位规则可有可⽆ 最多不限 {0,}
+ 代表前面一位规则⾄少⼀次 {1,}
(4)正则表达式对于任意连续的区间都可以⽤-连接。
(5)预定义字符集:在正则表达式中⼀些有特殊含义的字符。
\d 代表了任意一位的数字0-9
\w 代表任意一位数字/字⺟/下划线
. 代表任意字符
\s 代表空格
\W 代表的是非数组字母下划线(即是特殊符号)
\D 代表的是所有的非数字
var reg = /^\W+$/ //至少一位特殊字符
var num = "+-*/&&_&&^%$"//格式有误,_不符合\W
var num = "+-*/&&&&^%$777"//格式有误,777不符合\W
var num = "+-*/&&&&^%$"//格式正确
var reg = /^\D+$/ //至少一位非数字
var num = "+-*/&&_&&^%$"//格式正确
var num = "+-*/&&&&^%$777"//格式有误,777不符合\D
var num = "+-*/&&&ASD&^%$"//格式正确
(6)如果备选字符中只有⼀个备选字符或者只有⼀个预定义字符集,那么中括号可省略。
对于在正则表达式中有特殊含义的字符,如果希望以原⽂形式去匹配,需要⽤\转义
2、验证是否符合正则表达式:正则表达式.test(被检验的数据) 返回布尔值
注意:正则表达式是部分匹配。
部分匹配解决方法:在整条正则表达式的开头加^代表以...开头,在整条正则表达式的结尾加$,代 表以...结尾。
在备选字符的中括号开头加^代表除了...都⾏
//发生部分匹配
var num = "dsdsdsd18888888888rer"
var reg = /1[3-9]\d{9}/
console.log(reg.test(num))//输出结果:true
//限制开头和结尾
var num = "q188888888883"
var reg = /^1[3-9]\d{9}$/
console.log(reg.test(num))//输出结果:false
var num = 18888888888
console.log(reg.test(num))//输出结果:true
//在备选字符开头加^,代表除了这些什么都行
var reg = /^[^1abc]$/ //除了1都可以
var num = "1"//格式有误,是1
var num = "c"//格式错误,是c
var num = "s"//格式正确,只要不是1、a、b、c就行
3、例题:邮箱的正则表达式
像邮箱、身份证号、银行卡号等复杂的正则表达式不用自己写,直接从网上找已经被验证是完全正确的直接用即可。
/*邮箱的正则表达式
只有一个预定义字符集的中括号可以省略
3087817739@qq.com xu@sina.com xu@163.com.cn teacherXu@shandong-qd.cn.net
3087817739 @ qq .com
xu @ sina .com
xu @ 163 .com .cn
teacherXu @ shandong -qd .cn .net
teacherXu @ shandong -25qd .cn .net
teacherXu @ shandong -25qd-25qd .cn .net
前面为数字字母下划线都可以,不能是特殊字符,至少一位 \w+
一位@ @
数字字母下划线,至少一位 \w+
特殊符号“-”和后面至少一位的数字字母(不能以-结尾),不是所有的都会出现,可有可无 ([-]\w+)*
. 转义字符 \.
只能是字母和数字,至少一个 [\da-zA-Z]+
上两行的.字母/数字 可以出现多次,至少一次 (\.[\da-zA-Z]+)+
*/
var reg = /^\w+@\w+([-]\w+)*(\.[\da-zA-Z]+)+$/
var num = "teacherXu@shandong-qd.cn.net"
console.log(reg.test(num))
6.Math对象 :封装了一些与数学运算相关的api(方法),必须用Math关键字调用
都是用关键字调用的 ,不是直接用对象调用的,像数组对象的Array.isArray(arr).
1、round() 四舍五⼊取整
2、ceil() 向上取整
3、floor() 向下取整
4、abs() 取绝对值
5、min(参数序列)/max(参数序列) 注意不接受数组当参数,只能接受参数序列
如Math.min(2,8,5,7,58) 要想接收数组当参数,需要es6的知识。
6、random() 取0-1之间的随机数,包含小数
取任意区间内的随机数整数:Math.floor(Math.random()*(max-min+1)+min)
常用场景:抽奖、验证码+取整
如:var a = Math.floor(Math.random() * 6)//0-5之间的随机整数
var a = Math.floor(Math.random() * 6 + 5)//取5-10之间的随机整数
7、pow(x,y) 返回x的y次幂
8、sqrt(x) 返回根号x
//1 round() 四舍五入取整,用于小数
var num = 3.7
console.log(Math.round(num))//输出结果:4
num = 3.2
console.log(Math.round(num))//输出结果:3
//2 ceil() 向上取整
var num = 3.7
console.log(Math.ceil(num))//输出结果:4
num = 3.2
console.log(Math.ceil(num))//输出结果:4
//3 floor() 向下取整
var num = 3.7
console.log(Math.floor(num))//输出结果:3
num = 3.2
console.log(Math.floor(num))//输出结果:3
//4 abs() 取绝对值
var num = 3.7
console.log(Math.abs(num))//输出结果:3.7
num = -3.2
console.log(Math.abs(num))//输出结果:3.2
//5 min(参数序列) max(参数序列)
console.log(Math.min(2, 5, 8, 78, 1, -5))//输出结果:-5
console.log(Math.max(78, 58, -4, 5, 6, 8))//输出结果:78
//6 random() 取0-1之间的随机数
console.log(Math.random())//每次的取值结果都是不一样的
//取任意区间的随机整数 Math.floor(Math.random()*(max-min+1)+min)
var a = Math.floor(Math.random() * 6)//0-5之间的随机数
console.log(a)
var a = Math.floor(Math.random() * 6 + 5)//取5-10之间的随机整数
console.log(a)
//7 pow(x,y) x的y次幂,x的y次方
console.log(Math.pow(5, 2))//输出结果:5的2次方,25
//8 sqrt(x) 根号x
console.log(Math.sqrt(16))//输出结果:根号16,4
7.Date对象 :封装了所有与日期相关的api
日期对象在使用之前需要先创建
日期对象没有键值对,不能进行for in 循环。
1.创建⽇期对象:new Date() 如果不传参数返回的是当前日期对象,传参可以创建一个固定的日期对象 var date=new Date(参数)
可以传参数,如果没有具体的几点,默认的是08:00:00
日期的格式可以是 - / . 都可以,时间的格式为00:00:00
2.⽇期对象可以直接相减(不能做其他运算),得到的是间隔毫秒数,从而再进行/1000/60的各种运算能够得到天数/月数
3.getFullYear() 返回是哪年 number
4.getMonth() 返回的是⽉份 0-11 要+1修正
5.getDate() 返回的是日 1-31
6.getDay() 返回的是周几 0-6 0代表的是周日
7.getHours() 返回时 0-23
8.getMinutes() 返回分 0-59
9.getSeconds() 返回秒0-59
10.getMilliseconds() 返回毫秒0-999
11.getTime()返回的是1970-1-1⾄今的毫秒数 时间戳
12.以上get⽅法全改为set即为更改时间,注意,没有setDay()⽅法
//Date对象
//1 创建日期对象 返回当前日期
var date = new Date()
console.log(date)//输出结果:Fri May 19 2023 17:55:36 GMT+0800 (中国标准时间)
//可以传指定的参数 如果没有具体时间,默认的是08:00:00
var date = new Date("2023-11-11 00:00:00")
console.log(date)//输出结果:Sat Nov 11 2023 00:00:00 GMT+0800 (中国标准时间)
//2 日期之间相减
var date = new Date("2023-11-11 00:00:00")
var now = new Date()
console.log(date - now)//得到二者的毫秒差值
//3 getFullYear() 返回年份
var date = new Date()
console.log(date.getFullYear())//输出结果:2023
//4 getMonth() 返回月份 需要+1修正 0-11
console.log(date.getMonth() + 1)//输出结果:5
//5 getDate() 返回日
console.log(date.getDate())//输出结果:19
//6 getDay() 返回的是周几 0-6 0代表周日
console.log(date.getDay())
//7 getHours() 返回时
console.log(date.getHours())
//8 getMinutes() 返回分
console.log(date.getMinutes())
//9 getSeconds() 返回秒
console.log(date.getSeconds())
//10 getMilliseconds() 返回毫秒 0-999
console.log(date.getMilliseconds())
//11 getTime() 返回从1970-1-1至今的毫秒数
console.log(date.getTime())
//12 setFullYear() 更改年
var date = new Date()
date.setFullYear(2025)//2025年
console.log(date)//输出结果:Mon May 19 2025 18:32:29 GMT+0800 (中国标准时间)
//13 setMOnths() 更改月
date.setMonth(11)//12月
console.log(date)
//14 setDate() 更改日
date.setDate(25)//25日
console.log(date)
//15 setHours() 更改时
date.setHours(23)//23点
console.log(date)
//16 setMinutes()更改分
date.setMinutes(25)//25分
console.log(date)
//17 setSeconds() 更改秒
date.setSeconds(56)//56秒
console.log(date)
8.Error对象
SyntaxError(语法错误) ReferenceError(引⽤错误) TypeError(类型的错误)对象与属性不相匹配
19.DOM (document obje ct model)文档对象模型
1 增删改查 crud
元素对象的属性:所有写在元素开始标签之中的都是元素对象的属性(对于样式只有是行内样式引用的才能读取到style属性,如果是内部样式或外部样式是读取不到的)。(在元素对象中想要访问元素的类名需要的是 元素对象.className,如果直接写 元素对象.class是得不到的,因为在js元素对象中class代表的是类。)
元素对象的属性值也是可以更改的:元素对象.属性名=新值,此时的eleObj仍然是还可以使用的。
我们想要操作哪个元素需先找到它,把它变为对象,才能再js中进行操作,js中操作的都是对象。
1.查
查:查找元素 document也是关键字对象,代表整个html文件
(1)document.getElementById("id名") 返回元素对象 类型为元素对象
(2)document.getElementsByClassName("class名") 返回类数组 用角标拿到相应的元素对象
因为类名是可以重复的,拿到的可能不只是一个,因此返回的是一个类似数组的结果(但并不是数组,只是具有数组的length属性和角标,数组的方法都无法使用)而不是元素对象。要想拿到对应的元素对象要用 数组+角标 的形式。
类数组结构:类似于数组的结构,有length和角标,不具备数组的方法。
(3)document.getElementsByTagName("标签名") 返回数类组
(4)docuemnt.getElementsByName("名字") 对于表单元素input使用的 返回类数组
(5)document.querySelector("css选择器") 返回元素对象 如果有重名的,返回的是第一个
括号内css选择器的内容就是在样式中使用的内容,即使有重名的情况发生,通过这种方式查找到的只有一个元素对象,找到的是第一个。
(6)document.querySelectorAll("css选择器") 返回类数组
上述六种方法不只是只有doucment对象才能有,所有的元素对象都能使用,可以先使用document的其中某个方法找到一个元素对象,再对该元素对象使用方法,从而准确的拿到某个元素内部的内容。
<body>
<div id="app" class="box">
<div class="child">hello js</div>
</div>
<!-- 在下面的通过id名查元素对象的是把id名字改为了hello -->
<div id="title" class="box">hahahahhahahha</div>
<p>123123</p>
<p>456456</p>
<input type="text" name="psw">
<input type="text" name="psw">
<script>
//查
//1 document.getElementById("id名") 返回元素对象
var eleObj=document.getElementById("app")
console.log(eleObj)//输出结果:拿到元素对象<div id="app">hello js</div>
//元素对象的属性 所有写在元素开始标签里的都是该对象的属性
console.log(eleObj.id)//输出结果:app
//在js想要拿到class名需要的是 元素对象.className
console.log(eleObj.className)//输出结果:box
//元素对象的属性值也是可以更改的 但是之前拿到的eleObj仍然是可以使用的
eleObj.id="hello"
//2 document.getElementByClassNaame("class名") 返回一个类似数组的
var eleObj=document.getElementsByClassName("box")
console.log(eleObj)//输出结果:是一个类似数组的 HTMLCollection [div#hello.box, hello: div#hello.box]
//在类数组中拿到元素对象
console.log(eleObj[0])//输出结果:元素对象 <div id="app" class="box">hello js</div>
//3 document.getElementsByTagName("标签名") 返回类数组
var eleObj=document.getElementsByTagName("div")
console.log(eleObj)//输出结果:所有的div
//4 document.getElementsByName("名字") 适用于input表单元素 返回类数组
var eleObj=document.getElementsByName("psw")
console.log(eleObj)
//5 document.querySelector("css选择器") 返回元素对象
var eleObj=document.querySelector("#hello .child")
console.log(eleObj)
//6 document.querySelectorAll("css选择器") 返回类数组
var eleObj=document.querySelectorAll(".box")
console.log(eleObj)
</script>
</body>
<!-- 例:想要拿到下面的4个p的元素对象 -->
<div id="app">
<p>111</p>
<p>222</p>
</div>
<div id="title">
<p>333</p>
<p>444</p>
</div>
<script>
//方法一:使用doucment.querySelectorAll("css选择器")
var app=document.querySelectorAll("#app p")
var title=document.querySelectorAll("#title p")
console.log(app[0],app[1],title[0],title[1])
//方法二:这6个方法是所有的元素对象都可以使用的,可以先用document对象找到外层的元素对象,再对该元素对象使用其中的方法
var app=document.getElementById("app")//得到app元素对象
var eleObj1=app.getElementsByTagName("p")//在app元素对象中使用标签名查找得到类数组
var title=document.getElementById("title")
var eleObj2=title.getElementsByTagName("p")
console.log(eleObj1[0], eleObj1[1], eleObj2[0], eleObj2[1])
</script>
2.改
在js中所有涉及到横线的属性都要改为驼峰式的命名,但如果是带引号的字符串中的内容则不需要驼峰,仍然保持原样即可。
1、改属性
(1)通过对象的⽅式:对象.属性名=新值
如果是只修改样式中的其中某一个属性:样式的优先级变为了行内样式的优先级,一层一层的对象调用拿到要修改的属性。如app.style.width=”500px”。
如果是整体都要修改:
方法一:样式的优先级变为了行内样式的优先级,直接给style修改,内容的格式和css一样。但若此时只改了部分的样式内容,那么没有更改的样式就会消失。如app.style=”width:500px;height:500px;background-color:red”。
方法二:对于内部样式引用,直接修改相对应样式的类名,在css中该类名下有新的样式。但这种方法的比之单独修改某些样式和修改style属性的方法优先级要低,类似于行内样式>内部样式。并且这种方法无法读取到属性,因为没有写在开始标签里面。
(2)setAttribute("属性名","属性值")
这种方法在修改样式时只能全部修改,且原来的样式必须是行内样式引用的,否则拿不到style属性。
getAttribute("属性名")
2、改内容
innerText :可以获取到元素开始标签到结束标签之间的⽂本内容 (读取时忽略结构,只是拿到文本内容。在修改时也会将原来的结构都消除,只剩下修改后的文本内容,即使里面写上标签名也只是当成字符串并不会编译)
innerHTML:可以获取到元素开始标签到结束标签之间的内容(读取时可以读到结构,在修改时可以对元素标签进行编译)修改的时候也可以带着样式,但是出现引号嵌套的情况,里面的需要改为单引号。
class名也可以用变量来表示,需要字符串拼接。
修改的内容出现结构嵌套时,字符串不接受像HTML那样的换行写,也需要用字符串拼接。
如:
<div id="box"></div>
let box=document.getElementById("box")
var cname = "title"
var color = "yellow"
color = "green"
var txt="我是内容"
box.innerHTML = "<div>"+
"<div style='width:200px;height:200px;background-color:"+color+"'>hello js</div>"+
"<div>"+
"<div>"+
"<div>"+txt+"</div>"+
"<p class='"+cname+"'>hello vue</p>"
"</div>"
"</div>"
"</div>"
<!-- 改 -->
<div id="app" class="title">hello js</div>
<div id="world" class="title" style="width: 500px;height: 500px;background-color: pink;">hello world</div>
<div id="box" class="title">
<div>
<div>hello js</div>
<div>
<div>
<div>hello world</div>
<p>hello vue</p>
</div>
</div>
</div>
</div>
<script>
var app = document.getElementById("app")
console.log(app.style)//输出结果:对象类型的样式
// 样式是一个对象,想要拿到其中的某个属性,可以使用.
//在js中所有涉及到横线的属性,都要改为驼峰式的命名
console.log(app.style.backgroundColor)//输出结果:red
//1 改属性 对象名.属性=新值
//只更改其中某些属性 依次找到相应的属性修改
app.style.backgroundColor = "blue"//输出结果:200 200 blue
app.style.width = "500px"//输出结果:500 200 blue
//全部的样式属性都要修改:方法一:更改 对象.style
// app.style="width:500px;height:500px;background-color:orange"//输出结果:500 500 orange
//全部的样式属性都要修改: 方法二:内部样式时适用,直接更改相对应样式的类名,但是这种方法比只单独修改某些属性和直接修改style属性的优先级低
app.className = "wel"//输出结果:500 300 blue 由于前面的行内样式单独修改了背景色和宽度,且将行内样式修改style的内容注释掉了,内部样式的优先级要低,因此只剩下修改了高度
//2 改属性 setAttribute("属性名","属性值")
var world = document.getElementById("world")
world.setAttribute("id", "abc")
world.setAttribute("class", "wel")
//样式只能全部修改且之前的样式必须是行内样式的,否则拿不到style属性
world.setAttribute("style", "width:100px;height:100px;background-color:green")
//1 改内容 innerText
var box = document.getElementById("box")
console.log(box.innerText)//输出结果:标签内的所有文本内容,标签结构都没有
// box.innerText = "我是修改后的文本内容"
//2 改内容 innerHTML
console.log(box.innerHTML)//输出结果:带有标签结构的内容
var cname = "title"
var color = "yellow"
color = "green"
var txt="我是内容"
box.innerHTML = "<div>"+
"<div style='width:200px;height:200px;background-color:"+color+"'>hello js</div>"+
"<div>"+
"<div>"+
"<div>"+txt+"</div>"+
"<p class='"+cname+"'>hello vue</p>"
"</div>"
"</div>"
"</div>"
</script>
3.删
删内容
innerHTML=""
删属性
removeAttribute("属性名")
删单个元素对象:前提是要先获取父元素和子元素的对象
⽗元素对象.removeChild(⼦元素对象)
如果要删除多个元素,需要用循环,依次删除。注意:删除时数组长度发生变化,角标的变化
<body>
<!-- 删 -->
<div id="app" class="title" style="width: 200px;height: 200px;background-color: red;">
<div class="a">111</div>
<div class="a">111</div>
<div class="a">111</div>
<div class="b">111</div>
<div class="b">111</div>
<div class="b">111</div>
</div>
<script>
var app = document.getElementById("app")
//1 删除内容 innerHTML=""
// app.innerHTML = ""
//2 删属性 removeAttribute("属性名")
app.removeAttribute("style")
//3 删元素对象 removeChild
var children=app.getElementsByClassName("b")
for(var i=0;i<children.length;){
//删除时此处需要注意数组角标的变化,采用角标回退的方式解决
app.removeChild(children[i])
}
</script>
</body>
4.增
增加属性
(1)对象.属性=值
(2)setAttribute(“属性名”,”属性值”)
增加内容
innerHTML+=“新的内容“
增加单个元素 多个元素用循环创建
- 创建元素,创建几个就只能增加几个
document.createElement("标签名")
- 添加到对应的位置:加在父元素内部的结尾
⽗元素对象.appendChild(⼦元素对象)
- 添加属性和内容
子元素对象.属性名=值
子元素对象.innerHTML=新内容
<body>
<!-- 例:将星期几循环创建进页面中 -->
<div id="app" class="title">
</div>
<script>
var app=document.getElementById("app")
var week=[1,2,3,4,5,6,7]
for(var i=0;i<week.length;i++){
var child=document.createElement("div")
app.appendChild(child)
child.innerHTML="今天星期"+week[i]
child.style.color="red"
}
</script>
</body>
<body>
<div id="app" class="title">
<div>hello js</div>
</div>
<!-- 增 -->
<script>
var app=document.getElementById("app")
//1 增加属性 对象.属性=新值
app.style="width:500px;height:500px;background-color:red"
//2 增加内容 innerHTML+="新内容"
app.innerHTML+="<div>hello world</div>"
//3 增加元素
// 3.1创建元素 document.creatElement("标签名")
var child=document.createElement("div")
// 3.2将元素对象放入相应的位置 父元素对象.appendChild(子元素对象)
app.appendChild(child)
// 3.3添加属性和内容
child.id="child"
child.className="title"
child.style="width:200px;height:200px;background-color:green"
child.innerHTML="我是新的标签内容"
</script>
5.crud小案例:动态创建表格
<style>
td {
border: 1px solid;
height: 50px;
text-align: center;
}
table {
border: 1px solid;
width: 800px;
/* 表格边框合并 */
border-collapse: collapse;
}
</style>
<body>
<!-- 例:要求动态创建一个表格,先循环创建行,再循环创建单元格
-->
<table id="list">
</table>
<script>
var data = [
{ name: "张三", age: 18, salary: 3500, },
{ name: "李四", age: 19, salary: 23500, },
{ name: "王五", age: 21, salary: 13500, },
{ name: "赵六", age: 25, salary: 31500, },
{ name: "lili", age: 32, salary: 35000, },
{ name: "凯莉", age: 28, salary: 35000, },
{ name: "开心", age: 17, salary: 4500, },
]
var table = document.getElementById("list")
//1 创建表头行
var tr = document.createElement("tr")
// 将表头放入合适位置
table.appendChild(tr)
//2 在表头行中创建表头单元格 内容有多个td,td个数不定
// 拿到对象有几个属性,此时就具有几个td
var td = document.createElement("td")//需求是需要有序号,此时可以在外面单独加一个序号的td
tr.appendChild(td)
td.innerHTML = "序号"
for (var key in data[0]) {
// for in 走几次就创建几个td
var td = document.createElement("td")
tr.appendChild(td)
td.innerHTML = key
}
// //3 追加数据行
for (var i = 0; i < data.length; i++) {
var tr = document.createElement("tr")
table.appendChild(tr)
var td = document.createElement("td")
tr.appendChild(td)
td.innerHTML = i + 1
for (var key in data[i]) {
var td = document.createElement("td")
tr.appendChild(td)
td.innerHTML = data[i][key]
}
}
</script>
</body>
2 事件
⽤户的动作触发的 ,这些事件都是对html元素绑定的,事件本质上就是元素对象的一个属性。
需要先获取元素对象
(1)onclick:点击事件 元素对象.on事件名=函数名
注意:函数名不要加括号,加了括号就变成了主动调用。
如果在事件发生的时候需要传参数,在外层使用匿名函数,在匿名函数内部再调用带参数的函数。
<div id="app">hello</div>
var app = document.getElementById("app")
//当事件发生的时候需要传参数时,使用匿名函数,在匿名函数内部调用函数传参
app.οnclick=function(){
fn(7)
}
function fn(m){
alert(m)
}
(2)onmouseover:鼠标移入事件
(3)onmouseout:鼠标移出事件
(4)onmousemove:鼠标移动事件
应用场景:放大镜的效果
------------------------------------------------以下的事件均只适用于表单元素input
(5)onfocus:获得焦点事件 主要针对于表单元素input
(6)onblur:失去焦点事件 主要针对于表单元素input
应用场景:用户名、密码、确认密码格式的验证;验证填写的信息是否符合要求,进行正则表达式的验证
(7)onchange:值改变事件 主要针对表单元素input
在失去焦点的时候判断一下内容是否有变化,如果是删除了一部分内容,又将该内容重新原样写进去了,此时的值改变事件并没有触发。
(8)oninput:输入事件 主要针对表单元素input
应用场景:密码强度的验证,边输入边验证
--------------------------------------------键盘事件
(9)onkeypress:键盘按下(结果) 此时还无法区分哪个键,等学到了事件对象就可以区分了
onkeydown按下键盘的那一刻触发(过程),
onkeyup松开键盘的那一刻触发
先触发keydown,后触发keypress,最后松手的时候触发keyup
<style>
#app {
width: 200px;
height: 200px;
background-color: red;
}
</style>
<body>
<div id="app">hello</div>
<input type="text" id="user">
<script>
var app = document.getElementById("app")
//1 onclick 当用户点击hello时弹窗
app.onclick = fn//注意fn不要加括号,加了括号就是主动调用
function fn() {
alert(1)
}
//等价于 app.οnclick=function(){alert(1)}
//当事件发生的时候需要传参数时,使用匿名函数,在匿名函数内部调用函数传参
app.onclick = function () { fn(7) }
function fn(m) {
alert(m)
}
//2 onmouseover 鼠标移入事件
app.onmouseover = function () {
console.log("鼠标移入了")
}
//3 onmouseout 鼠标移出事件
app.onmouseout = function () {
console.log("鼠标移出了")
}
//4 onmousemove 鼠标移动事件
app.onmousemove = function () {
console.log("鼠标移动了")
}
//5 onfocus 获得焦点 针对input表单
var user = document.getElementById("user")
user.onfocus = function () {
console.log("获得焦点了")
}
//6 onblur 失去焦点
user.onblur = function () {
console.log("失去焦点了")
}
//7 onchange 值改变事件
user.onchange = function () {
console.log("我的值改变了")
}
//8 oninput 输入事件
user.oninput = function () {
console.log("正在输入..")
}
</script>
</body>
20.DOM实战
1 DOM实战1:oninput输入事件密码强度验证
<!DOCTYPE html>
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
.tips {
color: red;
font-size: 12px;
/* 将显示的隐藏掉 在用户输入之前是不显示的 当用户输入了才会显示相应内容*/
display: none;
}
</style>
</head>
<body>
<!--DOM实战1 :密码强度验证 oninput输入事件 在用户输入的同时密码强度得到更新-->
<input id="app">
<div class="tips">密码强度低</div>
<script>
/* 密码强度判断标准:通过正则表达式
低:纯数字或纯小写字母或纯大写字母
显示密码强度低,且为红色
中:数字字母组合
显示密码强度中,且为黄色
高:包含了特殊符号,(有就行,不用必须开头结尾限定)
显示密码强度高,且为绿色
*/
//定义各类密码强度的正则表达式
var num = /^\d+$/; //纯数字,至少一位数字
var low = /^[a-z]+$/; //纯小写,至少一位小写字母
var upp = /^[A-Z]+$/; //纯大写,至少一位大写字母
// var mix = /^\d+[a-zA-Z]+$/; //中强度
var mix = /^\w+$/; //这里再逻辑上是不符合要求的,如12345也是符合这样写的中强度的要求,但是在下面的if判断中根据执行顺序就已经把这种情况判给了低强度,而中强度的要求是不包含这些的,因此也是合理的
var spe = /\W+/; //高强度包含特殊符号 \W表示除了数字字母下划线,即特殊符号,这时候不需要加限定开头结尾的了,只要内容包含特殊符号即可,不用全部都是特殊符号
//等价于var spe=/[^\w]/; //在备选字符中括号开头加^表示除了这些剩下的内容
var app = document.getElementById("app")
var ele = document.getElementsByClassName("tips")[0]//直接拿到div的元素对象
app.oninput = function () {
//拿到用户输入的内容,通过input的value属性
var val = app.value
//如果将所有的内容都删除会出现显示最后的密码强度,所以需要加上当内容为空时让提示不显示
if (!val) {
ele.style.display = "none"
//需要加上return 让下面的判断不要再进行了,否则下面的判断还会再走一遍,为空的判断就白写了
return
}
//以下的内容都是针对输入框value有值的情况
//低强度 通过num low upp其中一个就是低强度 显示密码强度低且为红色
if (num.test(val) || low.test(val) || upp.test(val)) {
ele.style.display = "block"
// 如果在强度低的时候不更改颜色和内容,使用在ccs中默认的,则在强度变中之后再删除成低强度的,提示内容还是会显示中强度,在变低时没有自己的显示内容
ele.style.color = "red"
ele.innerHTML = "密码强度低"
} else if (mix.test(val)) {
//这里不需要再写显示display:block了,因为中强度为数字字母组合,第一位要么是数字要么是字母,只要用户开头输入了数字或字母就一定会满足低强度的显示,只需要更改颜色即可
ele.style.color = "yellow"
ele.innerHTML = "密码强度中"
} else if (spe.test(val)) {
//这里需要有display:block了,因为如果用户一开头就输入了特殊符号,已经满足了高强度的要求,但是此时没有并显示出来
ele.style.display = "block"
ele.style.color = "green"
ele.innerHTML = "密码强度高"
}
}
</script>
</body>
</html>
2 DOM实战2:注册界面的实现 onblur失去焦点 onclick点击事件
带详细注释版本
<!DOCTYPE html>
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
span {
color: red;
font-size: 12px;
display: none;
}
img {
margin-left: -30px;
}
</style>
</head>
<body>
<!-- DOM实战2:实现注册界面 -->
<div>
用 户 名:<input type="text">
<span>用户名要求是4-8位数字字母组合</span>
</div>
<div>
密 码:<input type="password">
<img src="images/close.png">
<span>密码要求是6位纯数字</span>
</div>
<div>
确认密码:<input type="password">
<img src="images/close.png">
<span>两次密码书写不一致</span>
</div>
<button id="login">注册</button>
<script>
//获取输入框元素对象
var inputs = document.getElementsByTagName("input")
//获取登录按钮元素对象
var login = document.getElementById("login")
//获取span元素对象
var spans = document.getElementsByTagName("span")
//获取img图像元素对象
var eyes = document.getElementsByTagName("img")
//正则表达式
var userReg = /^\w{4,8}$/;//这时的正则如果只是数字或字母也可以通过
var pswReg = /^\d{6}$/
var num1 = 0;//点击密码框眼睛的次数
var num2 = 0;//点击确认密码框眼睛的次数
var flag1 = true;//点击密码框的标记,默认的password为true
var flag2 = true;//点击确认密码框的标记,默认的password为true
//判断用户名的格式 使用onblur失去焦点的事件
inputs[0].onblur = function () {
/* if (userReg.test(inputs[0].value)) {
spans[0].style.display = "none"
} else {
spans[0].style.display = "inline"
}*/
// 代码优化3:判断是否符合正则表达式封装成传递参数的函数
checkValue(userReg, 0)
}
//判断密码
inputs[1].onblur = function () {
/* if (pswReg.test(inputs[1].value)) {
spans[1].style.display = "none"
} else {
spans[1].style.display = "inline"
}*/
// 代码优化3:判断是否符合正则表达式封装成传递参数的函数
checkValue(pswReg, 1)
/* //奇葩用户1:先填写确认密码,后填写密码时,二者不一致时确认密码的提示不显示
//bug2:正着填写,先写密码后写确认密码时,确认密码为空,应该不让确认密码的提示显示
//只要密码或者确认密码其中有一个没填写,都不做确认密码的判断
if (!inputs[2].value || !inputs[1].value) {
spans[2].style.display = "none"
return
}
if (inputs[1].value === inputs[2].value) {
spans[2].style.display = "none"
} else {
spans[2].style.display = "inline"
}*/
// // 代码优化1:以上的代码与判断确认密码中的部分代码有重复,将其封装成函数
checkSame()
}
//判断确认密码
/* inputs[2].onblur = function () {
//奇葩用户1:密码和确认密码反着填,先写确认密码,后写密码,此时密码框为空
//只要密码或者确认密码其中有一个没填写,都不做确认密码的判断
if (!inputs[1].value || !inputs[2].value) {
//bug1:如果先填写了确认密码后写密码,再去更改确认密码,这时再将密码框删除,确认密码的提示还在
spans[2].style.display = "none"
//密码框为空,直接return退出,下面的判断都别做了
return;
}
if (inputs[1].value === inputs[2].value) {
spans[2].style.display = "none"
} else {
spans[2].style.display = "inline"
}
// 代码优化1:以上的代码与判断密码中的部分代码有重复,将其封装成函数
checkSame()
}*/
inputs[2].onblur = checkSame
/*代码优化2:代码优化1之后变成了inputs[2].οnblur=function(){
checkSame()
}
这时可以直接将匿名函数取消,直接写函数名即可:inputs[2].οnblur=checkSame()*/
//注册按钮:当用户名符合正则且密码符合正则且确认密码与密码内容一致时才能注册
login.onclick = function () {
if (userReg.test(inputs[0].value) && pswReg.test(inputs[1].value) && inputs[1].value === inputs[2].value) {
alert("恭喜注册成功")
} else {
alert("请先填写正确的信息!")
}
}
//眼睛的事件 点击眼睛之后密码内容显示出来并且眼睛图片发生更改
eyes[0].onclick = function () {
//通过路径判断是睁眼还是闭眼来改变点击事件行不通,因为在if判断中我们使用的是相对路径,而控制台打印的路径是绝对路径
//思路一:通过input的type是password还是text来转换
/* if (inputs[1].type == "password") {
inputs[1].type = "text"
eyes[0].src = "images/open.png"
} else {
inputs[1].type = "password"
eyes[0].src = "images/close.png"
}*/
// eyesByType(0)
//思路二:点击次数的奇偶 我想到的 var num两个
/* if (num1 % 2 == 0) {
inputs[1].type = "password"
eyes[0].src = "images/close.png"
} else {
inputs[1].type = "text"
eyes[0].src = "images/open.png"
}*/
// num1=eyesByNumMe(num1, 1, 0)
//eyesByNumTeacher(0)
//思路三:添加一个布尔值的标记flag
/*if (flag1) {
inputs[1].type = "text"
eyes[0].src = "images/open.png"
flag1 = false
} else {
inputs[1].type = "password"
eyes[0].src = "images/close.png"
flag1 = true
}*/
// flag1 = eyesByFlagMe(flag1, 1, 0)
eyesByFlagTeacher(0)
}
eyes[1].onclick = function () {
//思路一:通过input的type是password还是text来转换
/* if (inputs[2].type == "password") {
inputs[2].type = "text"
eyes[1].src = "images/open.png"
} else {
inputs[2].type = "password"
eyes[1].src = "images/close.png"
}*/
// eyesByType(1)
//思路二:点击次数的奇偶 我想到的 var num两个
/* if (num2 % 2 == 0) {
inputs[2].type = "password"
eyes[1].src = "images/close.png"
} else {
inputs[2].type = "text"
eyes[1].src = "images/open.png"
}*/
// num2=eyesByNumMe(num2, 2, 1)
//eyesByNumTeacher(1)
//思路三:添加一个布尔值的标记flag
/* if (flag2) {
inputs[2].type = "text"
eyes[1].src = "images/open.png"
flag2 = false
} else {
inputs[2].type = "password"
eyes[1].src = "images/close.png"
flag2 = true
}*/
// flag2 = eyesByFlagMe(flag2, 2, 1)
eyesByFlagTeacher(1)
}
// 代码优化1:将密码和确认密码中判断是否一致的重复的代码封装成函数
function checkSame() {
if (!inputs[2].value || !inputs[1].value) {
spans[2].style.display = "none"
return
}
if (inputs[1].value === inputs[2].value) {
spans[2].style.display = "none"
} else {
spans[2].style.display = "inline"
}
}
// 代码优化3:将用户名和密码的正则表达式的判断封装成函数,传递参数
function checkValue(reg, index) {
//若用户名和密码为空,则不做正则判断,且不显示
if (!inputs[index].value) {
spans[index].style.display = "none"
return
}
if (reg.test(inputs[index].value)) {
spans[index].style.display = "none"
} else {
spans[index].style.display = "inline"
}
}
// 眼睛思路一:通过input的type是password还是text来转换
function eyesByType(index) {
//index代表的是眼睛0 1
if (inputs[index + 1].type == "password") {
inputs[index + 1].type = "text"
eyes[index].src = "images/open.png"
} else {
inputs[index + 1].type = "password"
eyes[index].src = "images/close.png"
}
}
//眼睛思路二:点击次数的奇偶 我想到的 var num两个
//我对num判断的想法
function eyesByNumMe(num, m, n) {
num++
if (num % 2 == 0) {
inputs[m].type = "password"
eyes[n].src = "images/close.png"
} else {
inputs[m].type = "text"
eyes[n].src = "images/open.png"
}
return num
}
//老师对num判断的想法
function eyesByNumTeacher(index) {
//通过传入的index的值判断是对num1还是对num2做操作
//如果index传的是0的话,则num1++;如果index穿的是1的话,则num2++
//由于我们传入的index是0和1,所以可以用三目运算符这么写,如果传入的index是其他的值像1和2,就不能这么写
index ? ++num2 : ++num1
//在对眼睛进行操作的时候也需要判断一下是对num1%2还是对num2%2,当index为1时对num2%2做判断,当index为0时对num1%2做判断
var c = index ? num2 % 2 : num1 % 2
if (!c) {
inputs[index + 1].type = "password"
eyes[index].src = "images/close.png"
} else {
inputs[index + 1].type = "text"
eyes[index].src = "images/open.png"
}
return num
}
//眼睛思路三:添加一个布尔值的标记flag
//我自己对flag判断的想法
function eyesByFlagMe(flag, m, n) {
if (flag) {
inputs[m].type = "text"
eyes[n].src = "images/open.png"
flag = false
} else {
inputs[m].type = "password"
eyes[n].src = "images/close.png"
flag = true
}
return flag
}
//老师对flag判断的想法
function eyesByFlagTeacher(index) {
var c = index ? flag2 : flag1
if (!c) {
inputs[index + 1].type = "password"
eyes[index].src = "images/close.png"
} else {
inputs[index + 1].type = "text"
eyes[index].src = "images/open.png"
}
if (index) {
flag2 = !flag2
} else {
flag1 = !flag1
}
}
</script>
<!--
代码优化1:将确认密码和密码中判断是否一致的重复部分封装成函数
代码优化2:在确认密码中匿名函数内只有调用函数这一件事,且调用的函数没有参数,可以将匿名函数去掉,直接写函数名
代码优化3:在用户名和密码的正则表达式判断时将其封装成一个传递参数的函数。
由于在用户名事件的匿名函数中也只有调用函数这一件事,但是有函数的传递,不能将其直接写为函数名,只能使用匿名函数里面调用带参数的函数
-->
</body>
</html>
简洁版本
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
span {
color: red;
font-size: 12px;
display: none;
}
img {
margin-left: -30px;
}
.margin {
margin-left: 10px;
}
</style>
</head>
<body>
<!-- DOM实战2:登录注册界面 -->
<div>
用 户 名:<input type="text">
<span>用户名要求是4-8位数字字母组合</span>
</div>
<div>
密 码:<input type="password">
<img src="images/close.png">
<span class="margin">密码要求是6位纯数字</span>
</div>
<div>
确认密码:<input type="password">
<img src="images/close.png">
<span class="margin">两次密码书写不一致</span>
</div>
<button id="login">注册</button>
<script>
//正则表达式
var userReg = /^\w{4,8}$/
var pswReg = /^\d{6}$/
//获取对象
var inputs = document.getElementsByTagName("input")
var spans = document.getElementsByTagName("span")
var login = document.getElementById("login")
var eyes = document.getElementsByTagName("img")
//眼睛使用变量
var num1 = 0;//点击密码框的眼睛的次数
var num2 = 0;//点击确认密码框眼睛的次数
var flag1 = true;//点击密码框眼睛的状态,默认是true
var flag2 = true;//点击确认密码框眼睛的状态
//用户名事件
inputs[0].onblur = function () {
checkValue(userReg, 0)
}
//密码事件
inputs[1].onblur = function () {
checkValue(pswReg, 1)
checkSame()
}
//确认密码事件
inputs[2].onblur = checkSame
//注册按钮事件
login.onclick = function () {
if (userReg.test(inputs[0].value) && pswReg.test(inputs[1].value) && inputs[1].value === inputs[2].value) {
alert("恭喜您成功注册!!!")
} else {
alert("请先填写正确的信息")
}
}
//眼睛事件
eyes[0].onclick = function () {
//方法一:使用input的type
//eyesByType(0)
//方法二:使用眼睛的点击次数的奇偶
//num1 = eyesByNumMe(num1, 1, 0)
// eyesByNumTeacher(0)
//方法三:布尔型flag标志
//flag1 = eyesByFlagMe(flag1, 1, 0)
eyesByFlagTeacher(0)
}
eyes[1].onclick = function () {
//方法一:使用input的type
//eyesByType(1)
//方法二:使用眼睛的点击次数的奇偶
// num2 = eyesByNumMe(num2, 2, 1)
//eyesByNumTeacher(1)
//方法三:布尔型flag标志
// flag2 = eyesByFlagMe(flag2, 2, 1)
eyesByFlagTeacher(1)
}
//检查密码和确认密码内容是否一致函数
function checkSame() {
//只要密码或确认密码其中一个为空,就不做一致性判断
if (!inputs[1].value || !inputs[2].value) {
spans[2].style.display = "none"
return
}
//由于用户先填写确认密码后填写密码,可能会导致二者不一致,因此此时还需要再判断一下是否一致
if (inputs[1].value === inputs[2].value) {
spans[2].style.display = "none"
} else {
spans[2].style.display = "inline"
}
}
//检查用户名和密码正则是否匹配函数
function checkValue(reg, index) {
if (!inputs[index].value) {
spans[index].style.display = "none"
return
}
if (reg.test(inputs[index].value)) {
spans[index].style.display = "none"
} else {
spans[index].style.display = "inline"
}
}
//眼睛事件函数
//方法一:使用input的type
function eyesByType(index) {
if (inputs[index + 1].type === "password") {
inputs[index + 1].type = "text"
eyes[index].src = "images/open.png"
} else {
inputs[index + 1].type = "password"
eyes[index].src = "images/close.png"
}
}
//方法二:使用眼睛的点击次数的奇偶
//我自己的Num实现方法
function eyesByNumMe(num, m, n) {
num++
if (num % 2 == 0) {
inputs[m].type = "password"
eyes[n].src = "images/close.png"
} else {
inputs[m].type = "text"
eyes[n].src = "images/open.png"
}
return num
}
//老师的Num实现方法
function eyesByNumTeacher(index) {
//根据index为0/1的值来判断是对num1++还是对num2++
index ? ++num2 : ++num1
var c = index ? num2 % 2 : num1 % 2
if (c) {
inputs[index + 1].type = "text"
eyes[index].src = "images/open.png"
} else {
inputs[index + 1].type = "password"
eyes[index].src = "images/close.png"
}
}
//方法三:布尔型flag标志
//我自己的Flag实现方法
function eyesByFlagMe(flag, m, n) {
if (flag) {
inputs[m].type = "text"
eyes[n].src = "images/open.png"
flag = false
} else {
inputs[m].type = "password"
eyes[n].src = "images/close.png"
flag = true
}
return flag
}
//老师的Flag实现方法
function eyesByFlagTeacher(index) {
var c = index ? flag2 : flag1
if (c) {
inputs[index + 1].type = "text"
eyes[index].src = "images/open.png"
} else {
inputs[index + 1].type = "password"
eyes[index].src = "images/close.png"
}
if (index) {
flag2 = !flag2
} else {
flag1 = !flag1
}
}
</script>
</body>
</html>
闭包实现眼睛
使用闭包实现眼睛,这样就不用声明两个flag变量的。
//使用闭包实现的眼睛,这样就不用再使用了两个flag了
images[0].onclick = eyesSwitch(0)
images[1].onclick = eyesSwitch(1)
function eyesSwitch(index) {
var flag = true
return function () {
if (flag) {
images[index].src = "images/open.png"
inputs[index + 1].type = "text"
} else {
images[index].src = "images/close.png"
inputs[index + 1].type = "password"
}
flag = !flag
}
}