var a = 30
var b = 20
var c = 10
a > b ? alert('a大') : alert("b大")
// 获取a和b中的较大值
var max = a > b ? a : b
// 获取a、b、c中的最大值
max = max > c ? max : c
// 也可以放到一起,但是不推荐使用,不方便阅读
var max = a > b ? (a > c ? a : c) : (b > c ? b :c)
(9) 逗号运算符
使用 , 可以分割多个语句,一般可以在声明多个变量时使用
// 使用逗号运算符同时声明多个变量
var a, b, c
// 可以同时声明多个变量并赋值
var a = 1, b = 2, c = 3
alert(b)
switch(条件表达式){
case 表达式:
语句……
break;
case 表达式:
语句……
break;
default:
语句……
break;
}
switch...case..语句
在执行时会值次将 case 后的表达式的值和 switch 后的条件表达式的值进行全等比较。
如果比较结果为 true,则从当前 case 处开始执行代码。当前 case 后的所有的代码都会执行,我们可以在 case 的语句后加上一个 break 关键字,这样可以确保只会执行当前 case 后的语句,而不会执行其他的 case。
如果比较结果为 false,则继续向下比较。
如果所有的比较结果都为 false,则只执行 default 后的语句。
switch 语句和 if 语句的功能实际上有重复的,使用 switch 可以实现 if 的功能,同样使用 if 也可以实现 switch 的功能, 所以我们使用时,可以根据自己的习惯选择。
/*
switch(parseInt(score/10)){
case 10:
case 9:
case 8:
console.log("优秀");
break;
case 7:
case 6:
console.log("合格");
break;
default:
console.log("不合格");
break;
}
*/
switch(true){
case score >= 60:
console.log("合格");
break;
default:
console.log("不合格");
break;
}
(3) 循环语句
通过循环语句可以反复地执行一段代码多次
while 循环
语法:
while(条件表达式){
语句……
}
while 语句在执行时,先对条件表达式进行求值判断,如果值为 true,则执行循环体,循环体执行完毕以后,继续对表达式进行判断,如果为 true,则继续执行循环体,以此类推,如果值为 false 则终止循环
var c = 10
var d = 10
console.log(c == d)
var obj3 = new Object()
var obj4 = new Object()
obj3.name = "张三"
obj4.name = "张三"
console.log(obj3, obj4, obj3==obj4)
对象字面量
/* 创建一个对象 */
// var obj = new Object()
/* 使用对象字面量来创建一个对象 */
var obj = {}
console.log(typeof obj)
obj.name = "张三"
console.log(obj.name)
在函数作用域中也有声明提前的特性,使用 var 关键字声明的变量,会在函数中所有的代码执行之前声明。函数声明也会在函数中所有的代码执行之前声明
在函数中,不使用 var 声明的变量都会成为全局变量
定义形参就相当于在函数作用域中声明了变量
14、声明提前
变量的声明提前
使用 var 关键字声明的变量,会在所有的代码执行之前被声明(即使放在使用的之后)但提前声明并不会同时赋值
// 没有var a时
console.log(a) // 报错Uncaught ReferenceError: a is not defined
--------------------------------------------------------------
// 提前声明,相当于在这里 var a
console.log(a) // undefined
var a = 1 // 这里a=1
console.log(a) // 1
但是如果声明变量时不使用 var 关键字,则变量不会被声明提前
函数的声明提前
使用函数声明形式创建的函数 function 函数(){},它会在所有的代码执行之前就被创建
fun() // 声明提前,输出fun()
function fun(){
console.log("fun()")
}
function createPerson(name, age, gender){
var obj = new Object()
obj.name = name
obj.age = age
obj.gender = gender
obj.sayName = function(){
alert(this.name)
}
return obj
}
var zbj = createPerson("猪八戒",1030,"男")
var lcg = createPerson("李长庚",11030,"男")
var ce = createPerson("嫦娥",18,"女")
ce.sayName()
构造函数和普通函数的区别就是调用方法的不同,普通函数时直接调用,而构造函数需要使用 new 关键字调用
function Person(){}
var per = new Person()
console.log(per)
构造函数的执行流程:
立刻创建一个新的对象
将新建的对象设置为函数中的 this,在构造函数中可以使用 this 来引用新建的对象
逐行执行函数中的代码
将新建的对象作为返回值返回
function Person(name, age, gender){
this.name = name
this.age = age
this.gender = gender
this.sayName = function(){
alert(this.name)
}
}
var zbj = new Person("猪八戒",1030,"男")
var lcg = new Person("李长庚",11030,"男")
var ce = new Person("嫦娥",18,"女")
console.log(zbj)
console.log(lcg)
console.log(ce)
function Person(name, age, gender){
this.name = name
this.age = age
this.gender = gender
// 向对象中添加一个方法
this.sayName = fun
}
// 将sayName()方法在全局作用域中定义
function fun(){
alert(this.name)
}
var per = new Person("张三", 21, "男")
var per2 = new Person("李四", 18, "男")
function MyClass(){
}
MyClass.prototype.a = 123
var mc = new MyClass()
var mc2 = new MyClass()
var mc3 = new MyClass()
mc.a = "我是mc中的a"
console.log(mc.a) // 由于mc中自己有a,因此输出自己的 我是mc中的a
console.log(mc2.a)
console.log(mc3.a) // 这两个自己没有a,因此会到原型中去找,找到了则输出 123
function Person(name, age, gender){
this.name = name
this.age = age
this.gender = gender
}
var per = new Person("张三", 21, "男")
var result = per.toString()
console.log("result="+result) // result=[object Object]
console.log(per.__proto__.__proto__.hasOwnProperty("toString")) // true
/*
函数参数可选,可以利用arguments来判断
arr:数组
length:长度,可选参数
callback:回调函数
*/
function(){
var arr = arguments[0]
if(arguments.length==2){
var fun = arguments[1]
fun()
}
if(arguments.length==3){
var length = arguments[1]
var fun = arguments[2]
fun()
}
}
25、Date() 对象
在 js 中使用 Date 对象来表示一个时间
// 创建一个Date对象
var d = new Date()
console.log(d) // Mon Apr 13 2020 09:09:04 GMT+0800 (中国标准时间)
JS 原生 Date 并不好用,因此在工作中一般会使用第三方库如 moment.js、day.js 来处理时间
如果直接使用构造函数创建一个 Date 对象,则会封装为当前代码执行的时间
创建一个指定的时间对象,需要在构造函数中传递一个表示时间的字符串作为参数
日期的格式: 月份/日/年 时:分:秒
var d2 = new Date("4/16/2020 09:09:04")
console.log(d2) // Thu Apr 16 2020 09:09:04 GMT+0800 (中国标准时间)
getElementsByClassName() 可以根据元素的 class 属性值查询一组元素节点对象,但是该方法不支持 IE 8 及以下的浏览器
var btn = document.querySelector("#btn")
var body = document.body
var html = document.documentElement
var all = document.all
var box = document.getElementsByClassName("box")[0]
3、事件
事件,就是文档或浏览器窗口中发生的一些特定的交互瞬间/交互行为。
JavaScript 与 HTML 之间的交互是通过事件实现的。
对于 Web 应用来说,有下面这些代表性的事件:点击某个元素、将鼠标移动至某个元素上方、按下键盘上某个键、关闭窗口等等。
for 循环会在页面加载完成之后立即执行,而响应函数会在超链接被点击时才执行,等它执行,循环已经结束了
var allA = document.getElementsByTagName("a")
for(var i=0; i<allA.length; i++){
allA[i].onclick = function(){
alert(i) // 一直是3
return false
}
}
可以用 this 来解决,添加之后删除,由于绑定删除是之前的,因此需要单独绑定
删除和添加员工
<script>
/* 删除员工 */
var allA = document.getElementsByTagName("a")
for(var i=0; i<allA.length; i++){
allA[i].onclick = function(){
var tr = this.parentNode.parentNode
// var name = tr.getElementsByTagName("td")[0].innerText
var name = tr.children[0].innerHTML
// alert("确认删除吗?")
/* window对象中的方法,找到confirm,这是用于弹出一个带有确认和取消按钮的提示框,字符串(提示文字)作为参数,点击确认返回true,点击取消返回false */
var flag = confirm("确认删除" +name+ "吗?") // firstChild会找第一个节点,空格也是
if(flag){
tr.parentNode.removeChild(tr)
}
// 取消默认行为
return false
}
}
/* 添加员工 */
addEmpButton.onclick = function(){
var name = document.getElementById("empName").value
var email = document.getElementById("email").value
var salary = document.getElementById("salary").value
// console.log(name,email,salary)
/*
<tr>
<td>Bob</td>
<td>bob@tom.com</td>
<td>10000</td>
<td><a href="deleteEmp?id=003">Delete</a></td>
</tr>
*/
var tr = document.createElement("tr")
var nameTd = document.createElement("td")
var emailTd = document.createElement("td")
var salaryTd = document.createElement("td")
var aTd = document.createElement("td")
var a = document.createElement("a")
// 文本节点
var nameText = document.createTextNode(name)
var emailText = document.createTextNode(email)
var salaryText = document.createTextNode(salary)
var delText = document.createTextNode("Delete")
// 将文本插入到td中
nameTd.appendChild(nameText)
emailTd.appendChild(emailText)
salaryTd.appendChild(salaryText)
a.appendChild(delText)
a.href = "javascript:;"
a.onclick = function(){
var tr = this.parentNode.parentNode
var name = tr.children[0].innerHTML
var flag = confirm("确认删除" +name+ "吗?")
if(flag){
tr.parentNode.removeChild(tr)
}
return false
}
aTd.appendChild(a)
// 将td添加到tr中
tr.appendChild(nameTd)
tr.appendChild(emailTd)
tr.appendChild(salaryTd)
tr.appendChild(aTd)
// 插入到table
// employeeTable.appendChild(tr) // 事实上tr在tbody中
employeeTable.getElementsByTagName("tbody")[0].appendChild(tr)
}
</script>
由于删除的有相同代码,可以提出来
function delA(){
var tr = this.parentNode.parentNode
// var name = tr.getElementsByTagName("td")[0].innerText
var name = tr.children[0].innerHTML
// alert("确认删除吗?")
/* window对象中的方法,找到confirm,这是用于弹出一个带有确认和取消按钮的提示框,字符串(提示文字)作为参数,点击确认返回true,点击取消返回false */
var flag = confirm("确认删除" +name+ "吗?") // firstChild会找第一个节点,空格也是
if(flag){
tr.parentNode.removeChild(tr)
}
// 取消默认行为
return false
}
删除员工中
allA[i].onclick = delA
添加员工中
a.onclick = delA
增加的使用 appendChild 和 innerHTML 配合更简单一点
/* 添加员工 */
addEmpButton.onclick = function(){
var name = document.getElementById("empName").value
var email = document.getElementById("email").value
var salary = document.getElementById("salary").value
var tr = document.createElement("tr")
tr.innerHTML = "<td>"+name+"</td>"+
"<td>"+email+"</td>"+
"<td>"+salary+"</td>"+
"<td><a href='javascript:;'>Delete</a></td>"
var a = tr.getElementsByTagName("a")[0]
a.onclick = delA
var tbody = employeeTable.getElementsByTagName("tbody")[0]
tbody.appendChild(tr)
// tbody.innerHTML += tr // 这样就不太合适了,会影响前面已有的
}
<style type="text/css">
#info{
width: 300px;
height: 500px;
background-color: #bfa;
overflow: auto;
}
</style>
<h3>欢迎亲爱的用户注册</h3>
<p id="info">
Lorem ipsum, dolor sit amet consectetur adipisicing elit. Amet, doloremque. Ea tempora consequuntur mollitia corrupti. Commodi iusto ducimus deleniti, ratione quam, harum fugit autem omnis nihil dolorem fuga, sequi eligendi excepturi expedita tenetur accusamus! In eaque voluptate inventore commodi a? Unde provident tempore, dolorem deserunt numquam reiciendis eum vero. Aut ipsum, dolorem doloribus nemo molestiae exercitationem deserunt amet quod voluptatibus expedita ex architecto, cum culpa fuga dolore. Ratione perspiciatis soluta, facilis temporibus, error laudantium nostrum facere doloremque natus sint cum esse incidunt officiis eum officia velit ab illo perferendis distinctio enim voluptas tempore? Reiciendis, itaque cupiditate? Totam mollitia tenetur labore neque possimus vero porro modi iure atque reiciendis fugit iste, omnis, magnam rem animi adipisci tempore repellendus iusto fugiat voluptatum consequuntur excepturi. Similique vel praesentium quo quam at. Veniam, neque nostrum, minima ex assumenda perferendis aliquam cum, molestiae culpa repellat explicabo? Sapiente, placeat eligendi voluptas velit beatae accusantium minus culpa reprehenderit similique, corporis eum neque tempore expedita iure, adipisci molestias. Quidem, sapiente temporibus deserunt nobis architecto incidunt ipsam. Provident distinctio accusamus quaerat inventore ex, omnis excepturi temporibus quod alias possimus maxime nesciunt odio aperiam error quia? Neque rem eos a perferendis repellat repudiandae reprehenderit reiciendis molestiae ullam! Nihil, illum odio!
</p>
<!-- 如果为表单项添加disabled="disabled" 则表单项将变成不可用的状态 -->
<input type="checkbox" disabled="disabled" />我已仔细阅读协议,一定遵守
<input type="submit" value="注册" disabled="disabled" />
<script type="text/javascript">
window.onload = function(){
/*
* 当垂直滚动条滚动到底时使表单项可用
*/
//获取id为info的p元素
var info = document.getElementById("info")
//获取两个表单项
var inputs = document.getElementsByTagName("input")
//为info绑定一个滚动条滚动的事件
info.onscroll = function(){
//检查垂直滚动条是否滚动到底
if(info.scrollHeight - info.scrollTop == info.clientHeight){
//滚动条滚动到底,使表单项可用
/*
* disabled属性可以设置一个元素是否禁用,
* 如果设置为true,则元素禁用
* 如果设置为false,则元素可用
*/
inputs[0].disabled = false
inputs[0].onclick = function(){ // 只有到底了才能能点复选框,点了复选框才能点按钮
if(inputs[0].checked){
inputs[1].disabled = false
}
}
}
}
}
</script>
//创建一个对象
var arr = '[1,2,3,"hello",true,null]'
var obj2 = '{"arr":[1,2,3]}'
var arr2 ='[{"name":"孙悟空","age":18,"gender":"男"},{"name":"孙悟空","age":18,"gender":"男"}]'
将 JSON 字符串转换为 JS 中的对象
在 JS 中,为我们提供了一个工具类,就叫 JSON
这个对象可以帮助我们将一个 JSON 转换为 JS 对象,也可以将一个 JS 对象转换为 JSON
JSON ---> JS对象
JSON.parse()
可以将以 JSON 字符串转换为 js 对象
它需要一个 JSON 字符串作为参数,会将该字符串转换为 JS 对象并返回
var json = '{"name":"孙悟空","age":18,"gender":"男"}'
var o = JSON.parse(json)
var o2 = JSON.parse(arr)
console.log(o.gender)
console.log(o2[1])
JS对象 ---> JSON
JSON.stringify()
可以将一个 JS 对象转换为 JSON 字符串
需要一个 js 对象作为参数,会返回一个 JSON 字符串
var obj3 = {name:"猪八戒" , age:28 , gender:"男"}
var str = JSON.stringify(obj3)
console.log(str)
title: 打牢 JS 基础 date: 2020-04-05 12:33 updated: 2020-04-05 12:33 cover: //cdn.wallleap.cn/img/pic/cover/202302GKk2ms.jpg category: 技术杂谈 tags:
前端 description: 打牢 JS 基础
JS 是前端三剑客中的“行为”
一、JavaScript 简介
1、简介
什么是语言
JavaScript起源
JavaScript简史
时间表
实现
学习内容
JS 的特点
2、写法
(1) JS 代码需要写到 script 标签中
例如:
自上而下顺序执行
(2) JS 代码编写位置
写到标签属性中
写到 script 标签中
现在默认 script 标签就是 js,因此可以不用写 type 属性
写到 js 文件中,再引入
可以将 js 代码编写到外部 js 文件中,然后通过 script 标签引入,写到外部文件中可以在不同的页面中同时引用,也可以利用到浏览器的缓存机制 —— 推荐使用的方式
二、ECMAScript
是 JS 的核心部分
1、注释
要养成良好的编写注释的习惯,也可以通过注释来对代码进行一些简单的调试
2、说明
js 代码中严格区分大小写
js 中每一条语句以分号(
;
)结尾对于是否需要加分号,引用下尤雨溪大佬讲的:
3、字面量和变量
字面量/常量,都是一些不可改变的值,比如:1、2、3、4、5
变量
在 js 中使用
var
关键字来声明一个变量,为变量赋值声明和赋值同时进行
也可以通过变量名对字面量进行描述
在 JS 中声明变量除了使用
var
关键字外,还可以使用let
和const
,例如:4、标识符
在 js 中所有的可以由我们自主命名的都可以称为标识符
如:变量名、函数名、属性名
命名一个标识符时需要遵守如下的规则:
标识符中可以含有字母、数字、
_
、$
标识符不能以数字开头(有这么一些行业公认的:
$
开头的一般都是框架或者库、_
开头的一般都是私有的、大写字母开头的一般都是类/构造函数)标识符不能是 ES 中的关键字或保留字
其他不建议使用的标识符
标识符一般都采用驼峰命名法 helloWorld
js 底层保存标识符时,实际上是采用 Unicode 编码,所以理论上讲,所有的 utf-8 中含有的内容都可以作为标识符
5、数据类型
数据类型指的就是字面量的类型
在 js 中一共有八种数据类型
String
字符串Number
数值Boolean
布尔值Null
空值Undefined
未定义Bigint
大整数Symbol
Object
对象前七种属于基本数据类型,
Object
属于引用数据类型(1) String
var str = ”hello”
\
作为转义字符,当表示一些特殊符号时,可以使用\
进行转义\”
\’
\n
\t
\\
(2) Number
在 js 中所有的数值都是 Number 类型
包括整数和浮点数(小数)
可以使用运算符
typeof
来检查一个变量的类型Number.MAX_VALUE
数字的最大值,超过了这个值回返回Infinity
,表示正无穷,-Infinity
表示负无穷NAN
,表示 Not A Number,是一个特殊的数字Number.MIN_VALUE
大于 0 的最小值在 js 中整数的运算基本可以保证精确
浮点数计算,可能得到一个不精确的值,不要进行对精确度要求高的计算(可以先用整数计算,然后再除 10 的整数倍)
(3) Boolean
布尔值只有两个,主要用来做逻辑判断
true 真
false 假
(4) Null
null
专门用来表示一个为空的对象(5) undefined
声明了一个变量但是没有赋值时,它的值就是
undefined
6、强制类型转换
强制类型转换:将一个数据类型转换成其他的数据类型
String Number Boolean
(1) 调用被转换数据类型的
toString()
方法该方法不会影响到原变量,它会将转换的结果返回,所以可以直接用该变量接收
但是注意:
null
和undefined
这两个值没有toString()
方法,如果调用它们的方法,会报错(2) 调用
String()
函数,并将被转换的数值作为参数传递给函数Number
和Boolean
实际上就是调用toString()
方法null
和undefined
,就不会调用toString()
方法,它会将null
直接转换成"null"
(3) 使用
Number()
函数NaN
0
true
转成1
false
转成0
Null
--->数字0
undefined
--->数字NaN
(4) 对字符串,
parseInt()
把一个字符串转换为一个整数,可取整可以将字符串中的有效的整数内容取出来,然后转换为
Number
(5)
parseFloat()
把一个字符串转换为小数16进制
0x10
8进制070
2进制0b10
(6) 使用
Boolean()
函数将其他数据类型转换为 Boolean0
和NaN
,其他的都是true
true
null
和undefined
都会转换为false
7、运算符
运算符(操作符)通过运算符可以对一个或多个值进行运算
比如:
typeof
就是一个运算符,可以用来获得一个值的类型,它会将该值的类型以字符串的形式返回(1) 算术运算符:
NaN
做运算都得NaN
+
可以对两个值进行加法运算,并将结果返回+””
使其转换为字符串(隐式转换)-
可以对两个值进行减法运算,并将结果返回*
可以对两个值进行乘法运算/
可以对两个值进行除法运算%
取模运算(取余数)(2) 一元运算符 只需要一个操作数
+
正号 正号不会对数字产生任何影响-
负号 负号可以对数字进行负号的取反对于非 Number 类型的值,它会先转换为 Number,然后再运算,可以对一个其它的数据类型使用
+
,将其转换为 Number,它的原理和Number()
函数一样(3) 自增和自减
自增
++
可以使变量在自身的基础上增加1,原变量的值改变后++(
a++
)前++(++a
)都会立即使原变量的值自增1,但是两个整体值不同,后++ 为原值,前++ 为自增后的值,都改变了 a 的值,但是自身的看情况。自减--
类似,只是变为了减一。(4) 逻辑运算符 逻辑判断
!
非 对一个值进行非运算,对布尔值进行取反操作取反
true
变false
、false
变true
如果对一个值进行两次取反,它不会变化
如果对非布尔值进行运算,则会将其转换为布尔值,然后再取反,所以我们可以利用这个特点,来将一个其他的数据类型转换为布尔值(可以为一个任意数据类型取两次反,来将其转换为布尔值),原理和
Boolean()
函数一样&&
与 对符号两侧的值进行与运算并返回结果两个值只要有一个为
false
就返回false
,只有两个值都为true
时才会返回true
js 中的与属于短路的与,如果第一个值为
false
,就不会再看第二个值了||
或 可以对符号两侧的值进行或运算并返回结果两个值中只要有一个
true
就返回true
,如果两个值都为false
,才返回false
js 中的或属于短路的或,如果第一个值为
true
,就不会看第二个值&&
、||
的非布尔值情况:对于非布尔值进行与或运算时,会先将其转换为布尔值,再运算,并且返回原值
与运算:如果第一个值为
true
,则必然返回第二个值。 如果第一个值为false
,则直接返回第一个值或运算:
如果第一个值为
true
,则直接返回回一个值如果第一个值为
false
,则返回第二个值在实际工作中,一般会用与或代替简单的分支判断,例如
(5) 赋值运算符
=
可以将符号右侧的值赋值给符号左侧的变量
复合运算
+=
、-=
、*=
、/=
、%=
(6) 关系运算符
可以比较两个值之间的大小关系
如果关系成立它会返回
true
,如果关系不成立则返回false
>
大于号true
,如果关系不成立则返回false
>=
大于等于 是否大于或等于<
小于号<=
小于等于非数值的情况
(7) 相等运算符
使用
==
来做相等运算相等运算符用来比较两个值是否相等,如果相等会返回
true
,否则返回false
如果两个进行比较的值类型不同,则会自动进行类型转换,将其转换为相同的类型,然后再比较
isNaN()
函数就是用来判断一个值是否是NaN
的使用
!=
来做不相等运算不相等运算符用来判断两个值是否不相等,如果不相等会返回
true
,否则返回false
不相等运算符也会对变量进行自动类型转换,如果转换后相等它也会返回 false
使用
===
来做全等运算使用
!==
来做不全等运算(8) 条件运算符,也叫三元运算符
条件表达式?语句1:语句2
执行的流程:
首先对条件表达式进行求值,如果该值为
true
,则执行语句1,并返回执行结果;如果该值为false
,则执行语句2,并返回执行结果。非布尔值会先转换为布尔值
(9) 逗号运算符
使用
,
可以分割多个语句,一般可以在声明多个变量时使用和数学中一样,在 js 中运算符也有优先级,例如先乘除后加减
在 JS 中有一个运算符优先的表,在表中越靠上优先级越高,优先级越高越优先运算,如果优先级一样,则从左往右计算,可以利用
()
改变优先级8、编码
在字符串中使用转义字符输入 Unicode 编码:
\u四位编码
在网页中使用 Unicode 编码:
&#编码;
这里的编码需要的是十进制9、语句
;
结尾{}
来为语句进行分组,同一个{}
中的语句我们称为是一组语句,它们要么都执行,要么都不执行,一个{}
中的语句我们也称为一个代码块,在代码块的后边就不用再编写;
了流程控制语句
(1) 条件判断语句
使用条件判断语句可以在执行某个语句之前进行判断,如果条件成立才会执行语句,条件不成立则语句不执行。
if 语句
语法一:
if 语句在执行时,会先对条件表达式进行求值判断,如果条件表达式的值为
true
,则执行 if 后的语句,如果条件表达式的值为false
,则不会执行 if 后的语句。if 语句只能控制紧随其后的那个语句,如果希望 if 语句可以控制多条语句,可以将这些语句统一放到代码块中。
语法二:
if...else...语句
当该语句执行时,会先对 if 后的条件表达式进行求值判断如果该值为
true
,则执行 if 后的语句,如果该值为false
,则执行 else 后的语句。语法三:
if...else if...else...
当该语句执行时,会从上到下依次对条件表达式进行求值判断,如果值为
true
,则执行当前语句,如果值为false
,则继续向下判断。补充一个知识点:
prompt()
可以弹出一个提示框。该提示框中会带有一个文本框,用户可以在文本恒中输入一段内容,该函数需要一个字符串作为参数,该字符串将会作为提示框的提示文字。用户输入的内容将会作为函数的返回值返回,可以定义一个变量来按收该内容。(2) 条件分支语句
switch...case..语句
在执行时会值次将
case
后的表达式的值和 switch 后的条件表达式的值进行全等比较。 如果比较结果为true
,则从当前case
处开始执行代码。当前case
后的所有的代码都会执行,我们可以在case
的语句后加上一个break
关键字,这样可以确保只会执行当前case
后的语句,而不会执行其他的case
。如果比较结果为
false
,则继续向下比较。如果所有的比较结果都为
false
,则只执行default
后的语句。switch 语句和 if 语句的功能实际上有重复的,使用 switch 可以实现 if 的功能,同样使用 if 也可以实现 switch 的功能, 所以我们使用时,可以根据自己的习惯选择。
(3) 循环语句
通过循环语句可以反复地执行一段代码多次
while 循环
true
,则执行循环体,循环体执行完毕以后,继续对表达式进行判断,如果为true
,则继续执行循环体,以此类推,如果值为false
则终止循环do...while 循环
do...while 语句在执行时,会先执行循环体,循环体执行完毕以后,再对 while 后的条件表达式进行判断,如果结果为
true
,则连续执行循环体,执行完毕后继续判断以此类推,如果结果为false
则终止循环实际上 while 和 do...while 这两个语句功能相似,不同的是 while 是先判断后执行,而 do...while 可以保证循环体至少执行一次,而 while 不能
for 循环
for 语句,也是一个循环语句,也称为 for 循环
在 for 循环中,提供了专门的位置用来放三个表达式:
① 执行初始化表达式,初始化变量(初始化表达式只会执行一次)
② 执行条件表达式,判断是否执行循环。
如果为 true,则执行循环 ③
如果为 false,终止循环
④ 执行更新表达式,更新表达式执行完毕继续重复 ③
补充:
break
和continue
break
关键字可以用来退出switch
或循环语句,不能在 if 语句中使用break
和continue
,break
关键字会立即终止离他最近的那个循环语句可以为循环语句创建一个 label,用来标识当前的循环
label: 循环语句
。使用 break 时,可以在 break 后跟着一个 label,这样 break 将会结束指定的循环,而不是最近的。测试某段代码的性能:
可以通过
Math.sqrt()
对一个数进行开方:10、对象
五种基本数据类型:
String
字符串、Number
数值、Boolean
布尔值、Null
空值、Undefined
未定义我们以后看到的值只要不是这五种,全都是对象(
Object
)基本数据类型都是单一的值 "hello"、123、true,值和值之间没有任何的联系
在 js 中表示一个人的信息(name gender age):
如果使用基本数据类型的数据,我们所创建的变量都是独立的,不能成为一个整体
对象属于一种复合的数据类型,在对象中可以保存多个不同数据类型的属性。
对象的分类:
创建对象:
使用
new
关键字调用的函数,是构造函数 constructor,构造函数是专门用来创建对象的函数。使用typeof
检查一个对象时,会返回 object。添加属性:
在对象中保存的值称为属性
向对象添加属性,语法:
对象.属性名=属性值
或对象["属性名"]=属性值
读取属性:
读取对象中的属性,语法:
对象.属性名
或对象["属性名"]
如果读取对象中没有的属性,不会报错,而是会返回
undefined
修改属性值:
修改对象的属性值,语法:
对象.属性名=新值
删除属性:
删除对象的属性,语法:
delete 对象.属性名
属性名:
.
的方式来操作,需要使用另一种方式,语法:对象["属性名"]=属性值
,读取时也需要采用这种方式对象["属性名"]
。使用[]
这种形式去操作属性,更加地灵活,在[]
中可以直接传递一个变量,这样变量值是多少就会读取那个属性(变量的时候也只能采用这种方式)。属性值:
in
运算符:"属性名" in 对象
基本数据类型和引用数据类型:
基本数据类型:
String
、Number
、Boolean
、Null
、Undefined
引用数据类型:
Object
基本数据类型的值直接在栈内存中存储,值与值之间是独立存在,修改一个变量不会影响其他的变量。
new
会在堆内存中开辟空间obj2=null
,这样 obj2 就没有指向0x123
这个地址了当比较两个基本数据类型的值时,就是比较值。
而比较两个引用数据类型时,它是比较的对象的内存地址,如果两个对象是一模一样的,但是地址不同,它也会返回 false
对象字面量
使用对象字面量,可以在创建对象时,直接指定对象中的属性,语法:
{属性名:属性值,属性名:属性值……}
对象字面量的属性名可以加引号也可以不加,建议不加,如果要使用一些特殊的名字,则必须加引号。
属性名和属性值是一组一组的名值对结构,名和值之间使用
:
连接,多个名值对之间使用,
隔开。11、函数
(1) 函数 function
typeof
检查一个函数对象时,会返回function
(2) 创建函数和调用函数
函数对象()
我们在实际开发中很少使用构造函数来创建一个函数对象,而是使用其他方式,例如以下两种(事实上学完 ES 6 后这两种方式也很少使用了)
使用函数声明来创建一个函数
语法:
其中
[]
代表可选使用函数表达式来创建一个函数
语法:
例如:
ES 6 中新增了箭头函数,可以直接使用:
(3) 函数的参数
可以在定义函数的时候,在函数的
()
中指定一个或多个形参(形式参数),多个形参之间使用,
隔开,声明形参就相当于在函数内部声明了对应的变量,但是并没有赋值。在调用函数的时候,可以在
()
中指定实参(实际参数),实参将会赋值给函数中对应的形参。undefined
(4) 返回值
可以使用 return 来设置函数的返回值
语法:
return 值
return 后的值将会作为函数的执行结果返回,可以定义一个变量来接收该结果
在函数中 return 后的语句都不会执行
如果 return 语句后不跟任何值就相当于返回一个
undefined
,如果函数中不写 return,也是返回undefined
return 后可以跟任意类型的值(返回值可以是任意的类型),可以是一个对象,可以是一个函数……
在函数内部可以再返回声明一个函数,可以这样调用——
fun()()
总结:使用
break
可以退出当前循环,使用continue
跳过当次循环,使用 return 可以结束整个函数。(5) 立即执行函数(匿名函数)——只想调用一次
函数定义完,立即被调用。
如果不喜欢写分号的,记得上面说过的规则,开头是
()
、[]
需要加上分号:(6) 函数与方法
函数也可以成为对象的属性,如果一个函数作为一个对象的属性保存,那么我们称这个函数时这个对象的方法(method),调用这个函数就说调用对象的方法。
但是它只是名称上的区别,没有其他的区别。
调用方法:
obj.sayName()
调用函数:
fun()
12、for...in
使用 for...in 语句可以枚举对象中的属性
语法:
for...in 语句,对象中有几个属性,循环体就会执行几次,每次执行时,会将对象中的恶一个属性的名字赋值给变量
13、作用域 scope
作用域指一个变量的作用的范围
在 js 中一共有两种作用域:全局作用域和函数作用域(ES 6 多了块级作用域)
全局作用域
全局作用域中的变量都是全局变量,在页面的任意的部分都是可以访问到的。
函数作用域
14、声明提前
变量的声明提前
函数的声明提前
function 函数(){}
,它会在所有的代码执行之前就被创建15、this
解析器在调用函数时每次都会向函数内部传递一个隐含的参数
这个隐含的参数就是 this,this 指向的是一个对象,这个对象我们称为函数执行的上下文对象,根据函数的调用方式的不同,this 会指向不同的对象。
在后面的学习中将慢慢补全 this 是什么
16、使用工厂方法创建对象
通过该方法可以大批量的创建对象
使用工厂方法创建的对象,使用的构造函数都是 Object,所以创建的对象都是 Object 这个类型,这就导致我们无法区分出多种不同类型的对象
17、构造函数
构造函数就是一个普通的函数,创建方式和普通函数没有区别,不同的是构造函数习惯上首字母大写。
构造函数和普通函数的区别就是调用方法的不同,普通函数时直接调用,而构造函数需要使用 new 关键字调用
构造函数的执行流程:
立刻创建一个新的对象
将新建的对象设置为函数中的 this,在构造函数中可以使用 this 来引用新建的对象
逐行执行函数中的代码
将新建的对象作为返回值返回
使用同一个构造函数创建的对象,我们称为一类对象,也将一个构造函数称为一个类。我们将通过一个构造函数创建的对象,称为是该类的实例
18、instanceof
使用 instanceof 可以检查一个对象是否是一个类的实例
语法:
对象 instanceof 构造函数
如果是,则返回 true,否则返回 false
注意:
所有的对象都是 Object 的后代,所以任何对象和 Object 做 instanceof 检查时都会返回 true
缺陷
创建一个 Person 构造函数,在 Person 构造函数中, 为每一个对象都得加了一个 sayName 方法。
目前我们的方法是在构造固数内部创建的,也就是构造函数每执行一次就会创建一个新的 sayName 方法,也就是说实例的 sayName 都是唯一的。
这样就导致了构造函数执行一次就会创建一个新的方法,执行10000次就会创建10000个新的方法,而10000个方法都是一模一样的,这是完全没有必要,完全可以使所有的对象共享同一个方法。
将函数定义在全局作用域中,污染了全局作用域的命名空间,而且也不安全
19、原型 prototype
我们所创建的每一个函数,解析器都会向函数中添加一个属性 prototype,这个属性对应着一个对象,这个对象就是我们所谓的原型对象
如果函数作为普通函数调用,prototype 没有任何作用
当函数以构造函数的形式调用时,它所创建的对象中都会有一个隐含的属性,指向该构造函数的原型对象,我们可以通过
__proto__
来访问该属性原型对象就相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象,我们可以将对象中共有的内容,统一设置到原型对象中
当我们访问对象的一个属性或方法时,它会先在对象自身中寻找,如果有则直接使用,如果没有则会去原型对象中寻找,如果找到则直接使用
mc、mc2、mc3 是通过 MyClass 创建的对象,完整代码如下
建议:以后我们创建构造函数时,可以将这些对象共有的属性和方法。 统一添加加到构造函教的原型对象中,这样不用分别为每一个对像添加,也不会影响到到全局作用城,就可以使每个对象都具有这些属性和方法了
使用 in 检查对象中是否含有某个属性是,如果对象中没有,但是原型中有,也会返回 true
可以使用对象的
hasOwnProperty()
来检查对象自身中是否含有该属性,该方法只有当对象自身中含有属性时,才会返回 true原型对象也是对象,所以它也有原型,当我们使用一个对象的属性或方法时,会先在自身中寻找,自身中如果有,则直接使用;如果没有则去原型对象中寻找,如果原型对象中有,则使用;如果没有则去原型的原型中寻找,直到找到 Object 对象的原型,Object 对象的原型没有原型,如果在 Object 原型中仍然没有找到,则返回 undefined(原型链)。
当我们直接在页面中打印一个对象时,实际上输出的是对象的
toString()
方法的返回值如果我么希望在输出对象时不输出
[object Object]
,可以为对象添加一个toString
方法20、垃圾回收(GC)
21、数组
使用字面量来创建数组
22、数组的方法
push()
pop()
unshift()
shift()
数组的遍历
for 循环
forEach
一般我们都是使用 for 循环去遍历数组,js 中还为我们提供了一个方法,用来遍历数组forEach()
这个方法只支持IE8以上的浏览器,IE8及以下的浏览器均不支持该方法,还是使用for
forEach( ) 方法需要一个函数作为参数
像这种函数,由我们创建但是不由我们调用但最后执行了的,我们称为回调函数
数组中有几个元素函数就会执行几次,每次执行时,浏览器会将遍历到的元素 以实参的形式传递进来, 我们可以来定义形参,来读取这些内容
浏览器会在回调函数中传递三个参数:
slice()
splice()
去除数组中重复的数字
concat()
join()
reverse()
sort()
23、函数的方法
call() 和 apply()
这里 this 又多了一种情况:
24、arguments
在调用函数时,浏览器每次都会传递进两个隐含的参数:
函数的上下文对象 this
封装实参的对象 arguments
arguments 是一个类数组对象,它可以通过索引来操作数据,也可以获取长度
在调用函数时,我们所传递的实参都会在 arguments 中保存
arguments.length 可以用来获取实参的长度
我们即使不定义形参,也可以通过 arguments 来使用实参,只不过比较麻烦
它里边有一个属性叫做 callee,这个属性对应一个函数对象,就是当前正在指向的函数的对象
由于是个伪数组(类数组),因此不支持数组的方法,比如 forEach,但是可以通过 Array.from(arguments) 转换成真数组
25、Date() 对象
如果直接使用构造函数创建一个 Date 对象,则会封装为当前代码执行的时间
创建一个指定的时间对象,需要在构造函数中传递一个表示时间的字符串作为参数
日期的格式:
月份/日/年 时:分:秒
getTime()
26、Math 对象
Math 对象用于执行数学任务。
Math 对象并不像 Date 和 String 那样是对象的类,因此没有构造函数 Math(),像 Math.sin() 这样的函数只是函数,不是某个对象的方法。它属于一个工具类,无需创建它,通过把 Math 作为对象使用就可以调用其所有属性和方法。
Math 对象属性
Math 对象方法
Math.random()
console.log(Math.random())
Math.random()*10
--> 整数Math.round(Math.random()*10)
Math.round(Math.random()*x)
Math.round(Math.random()*(y-x)+x)
Math.max() 可以获取多个数中的最大值
Math.min() 可以获取多个数中的最小值
Math.pow(x,y) 返回x的y次幂
Math.sqrt(x) 返回x的平方根
27、包装类
基本数据类型:
String
、Number
、Boolean
、Null
、Undefined
引用数据类型:
Object
在 js 中为我们提供了三个包装类,通过这三个包装类可以将基本数据类型的数据转换为对象
但是注意,我们在实际应用中不会使用基本数据类型的对象,如果使用基本数据类型的对象,在做一些比较时可能会带来一些不可预期的结果
方法和属性只能添加给对象,不能添加给基本数据类型
当我们对一些基本数据类型的值去调用属性和方法时,浏览器会临时使用包装类将其转换为对象,然后在调用对象的属性和方法,调用完以后,再将其转换为基本数据类型
28、字符串相关
创建一个字符串
在底层字符串是以字符数组的形式保存的
['H',"e","l","l","o"." ","J","a"]
length 属性
charAt()
charCodeAt()
String.formCharCode()
concat()
+
一样indexof()
lastIndexOf()
slice()
substring()
substr()
split()
toUpperCase()
toLowerCase()
字符串和正则相关方法(正则表达式看下一节)
splite()
search()
match()
replace()
29、正则表达式
GitHub上有个很好的学习教程 learn-regex,翻译版
正则表达式用于定义一些字符串的规则,计算机可以根据正则表达式,来检查一个字符串是否符合规则,将字符串中符合规则的内容提取出来
创建正则表达式的对象
var 变量 = new RegExp("正则表达式","匹配模式")
使用 typeof 检查正则对象,会返回 object
正则表达式的方法 test()
使用这个方法可以检查一个字符串是否符合正则表达式的规则,如果符合则返回 true,否则返回 false
在构造函数中可以传递一个匹配模式作为第二个参数,可以是:
使用字面量来创建正则表达式,语法:
var 变量 = /正则表达式/匹配模式
使用字面量的方式创建更加简单,使用构造函数创建更加灵活
|
表示或者的意思[]
里的内容也是或的关系[ab]==a|b
[a-z]
任意小写字母[A-Z]
任意大写字母[A-z]
任意字母[0-9]
任意数字[^ ]
除了{n}
正好出现 n 次{n,m}
出现 m~n 次{n,}
出现 n 次以上+
至少一个,相当于{1,}
*
0 个或多个,相当于{0,}
?
0 个或 1 个,相当于{0,1}
^
表示开头$
表示结尾^
、$
则要求字符串必须完全符合正则表达式.
表示任意字符\w
任意字母、数字、下划线(_
)[A-z0-9_]
\W
除了字母、数字、下划线(_
)[^A-z0-9_]
\d
任意的数字\D
除了数字\s
空格\S
除了空格\b
单词边界\B
除了单词边界三、DOM
1、什么是 DOM
全称 Document Object Model 文档对象模型
JS 中通过 DOM 来对 HTML 文档进行操作。只要了解了 DOM 就可以随心所欲地操作 WEB 页面。
文档:表示的就是整个 HTML 网页文档
对象:表示将网页中的每一个部分都转换为了一个对象
模型:使用模型来表示对象之间的关系,这样方便我们获取对象
文档对象模型
2、节点
3、节点分类和 DOM 查询
(1) 节点分类
文档节点(document)
document
,代表的是整个 HTML 文档,网页中的所有节点都是它的子节点。window
对象的属性存在的,我们不用获取可以直接使用。元素节点(Element)
document.getElementById)
根据 id 属性值获取-个元素节点对象。文本节点(Text)
元素节点.firstChild
获取元素节点的第一个子节点,一般为文本节点属性节点(Attr)
元素节点.getAttributeNode("属性名")
(2) 获取元素节点
通过 document 对象调用
getElementById()
通过 id 属性获取一个元素节点对象getElementsByTagName()
通过标签名获取一组元素节点对象getElementsByName()
通过name
属性获取一组元素节点对象(3) 获取元素节点的子节点
通过具体的元素节点调用
getElementsByTagName()
方法,返回当前节点的指定标签名后代节点childNodes
属性,表示当前节点的所有子节点childNodes 属性会获取包括文本节点在内的所有节点,包括 DOM 标签与标签间空白也会当成文本节点
children
属性可以获取当前元素的所有子元素firstChild
属性,表示当前节点的第一个子节点(包括空白文本节点)firstElementChild
获取当前元素的第一个子元素,但是不支持 IE 8 及以下的浏览器lastChild
属性,表示当前节点的最后一个子节点(4) 获取父节点和兄弟节点
通过具体的节点调用
parentNode
属性,表示当前节点的父节点previousSibling
属性,表示当前节点的前一个兄弟节点nextSibling
属性,表示当前节点的后一个兄弟节点(5) DOM 查询的其他方法
querySelector()
该方法需要一个选择器作为参数,可以根据一个 CSS 选择器来查询一个元素节点对象,IE 8 中也可以使用,总是会返回唯一的一个元素,如果满足条件的元素有多个,那么它只会返回第一个querySelectorAll()
该方法和querySelector()
用法类似,不同的是它会将符合条件的元素封装到一个数组中返回,即使符合条件的元素之后一个,它也会返回数组document.getElementsByTagName("body")[0]
,其实在document
中有一个属性,它保存的就是 body 的引用document.body
document.documentElement
保存的是 html 根标签document.all
代表页面中所有元素,document.getElementsByTagName("*")
getElementsByClassName()
可以根据元素的 class 属性值查询一组元素节点对象,但是该方法不支持 IE 8 及以下的浏览器3、事件
这种写法结构和行为耦合,不方便维护,不推荐使用
4、onclick
可以为按钮的对应事件绑定处理函数的形式来响应事件,这样当事件被触发时,其对应的函数将会被调用
像这种单击事件绑定的函数,我们称为单击响应函数
4、文档加载 onload
浏览器在加载一个页面时,是按照自上向下的顺序加载的,读取到一行就运行一行,如果将 script 标签写到页面的上边,在代码执行时,页面还没有加载,页面没有加载 DOM 对象也没有加载,会导致无法获取到 DOM 对象
将 js 代码编写到页面的下方就是为了可以在页面加载完毕以后再执行 js 代码
但是,一定要放在上面呢,js 也提供了一个事件
onload 事件会在整个页面加载完成之后才触发
为 window 绑定一个 onload 事件,该事件对应的响应函数将会在页面加载完成之后执行,这样可以确保我们的代码执行时,所有的 DOM 对象已经加载完毕了
在这里来做几个练习呗
1、城市选择
要求完成右边按钮的功能
它们的功能相似,可以封装为一个函数(只是提醒一下,这里不一定更方便)
2、轮播图
3、全选
反选可以修改下代码,减少一个循环
上面又用到了 this:
在事件的响应函数中,响应函数是给谁绑定的 this 就是谁
5、DOM 对象的其他属性、方法
下面的属性和方法可用于所有 HTML 元素上:
DOM 查询学完了,接着就可以操作对象了(增删改)
增:
appendChild()
向父节点添加一个新的子节点,父元素.appendChild(子节点)
insertBefore()
在指定的子节点前插入新的子节点,父节点.insertBefore("要插入的子节点","指定的子节点")
createElement()
创建元素节点,需要一个标签名作为参数,将会根据该标签名创建元素节点对象,并将创建好的对象作为返回值返回createTextNode()
创建文本节点,需要一个文本内容作为参数,将会根据该内容创建文本节点,并将新的节点返回createAttribute()
创建属性节点删:
removeChild()
删除子节点,父节点.removeChild(子节点)
--->子节点.parentNode.removeChild(子节点)
改:
replaceChild()
使用指定的子节点替换已有子节点,父节点.replaceChild(新节点,旧节点)
setAttribute()
把指定属性设置或修改为指定的值innerHTML
用于获取元素内部的 HTML 代码,对于自结束标签,这个属性没有意义如果要读取元素节点属性,可以直接使用
元素.属性名
,例如元素.id
、元素.name
、元素.value
,注意 class 属性不能采用这种方式,读取 class 属性时需要使用元素.className
innerText
这个属性可以获取到元素内部的文本内容,和 innerHTML 类似,不同的是它会自动将 html 去除可以使用
innerHTML
完成 DOM 的增删改操作练习:
1、城市节点修改
2、员工记录
HTML 和 CSS 部分
取消 a 的默认行为
其他取消默认行为的方法
for 循环会在页面加载完成之后立即执行,而响应函数会在超链接被点击时才执行,等它执行,循环已经结束了
可以用 this 来解决,添加之后删除,由于绑定删除是之前的,因此需要单独绑定
删除和添加员工
由于删除的有相同代码,可以提出来
增加的使用 appendChild 和 innerHTML 配合更简单一点
6、DOM 操作 CSS
通过 js 修改元素的样式
语法:
元素.style.样式名=样式值
注意:如果 CSS 的样式名中含有
-
,这种名称在 js 中是不合法的,需要将这种样式名修改为驼峰命名,去掉-
,然后将-
后的字母大写!important
,则此时样式会有最高的优先级,即使通过 js 也不能覆盖该样式,此时将会导致 js 修改样式失败,所以在写 CSS 样式的时候尽量不要加!important
js 读取样式
元素.style.样式名
js 获取当前显示的样式
元素.currentStyle.样式
在其他浏览器中可以使用
getComputedStyle()
这个方法来获取元素当前的样式,这个方法是 window 的方法,可以直接使用需要两个参数
第一个:要获取样式的元素
第二个:可以传递一个伪元素,一般都传 null
这个方法会返回一个对象,对象中封装了当前元素对应的样式
可以通过
对象.样式名
来读取样式,如果获取的样式没有设置,则会获取到真实的值,而不是默认值。比如:没有设置 width,它不会获取到 auto,而是一个长度这个方法不支持IE8及以下的浏览器
通过 currentStyle 和 getComputedStyle() 读取到的样式都是只读的,不能修改,如果要修改必须通过 style 属性
clientWidth、clientHeight
这两个属性可以获取元素的可见宽度和高度
这些属性都是不带px的,返回都是一个数字,可以直接进行计算
会获取元素宽度和高度,包括内容区和内边距
这些属性都是只读的,不能修改
offsetWidth、offsetHeight
获取元素的整个的宽度和高度,包括内容区、内边距和边框
offsetParent
可以用来获取当前元素的定位父元素
会获取到离当前元素最近的开启了定位的祖先元素,如果所有的祖先元素都没开启定位,则返回body
offsetLeft
当前元素相对于其定位父元素的水平偏移量
offsetTop
当前元素相对于其定位父元素的垂直偏移量
设置了
overflow:auto;
,高度和长度都太大,会出现滚动条scrollWidth、scrollHeight
可以获取元素整个滚动区域的宽、高度
scrollLeft
可以获取水平滚动条滚动的距离
scrollTop
可以获取垂直滚动条滚动的距离
7、其他事件
onscroll
该事件会在元素的滚动条滚动时触发
阅读协议:
onmousemove
该事件会在鼠标在元素中移动时被触发
事件对象:当事件的响应函数被触发时,浏览器每次都会将一个事件对象作为实参传递进响应函数,在事件对象中封装了当前事件相关的一切信息。比如,鼠标坐标、键盘哪个按键被按下、鼠标滚轮滚动的方向……
在IE8中,响应函数被触发时,浏览器不会传递事件对象,在IE8及以下的浏览器中,是将事件对象作为window对象的属性保存的
上面也涉及到了跟随鼠标的,下面来详细说一下
ontouchstart
该事件会在手指触摸到屏幕时被触发
ontouchmove
该事件会在手指在屏幕上移动时被触发
ontouchend
该事件会在手指离开屏幕时被触发
8、事件的冒泡(Bubble)
所谓的冒泡指的就是事件的向上传导,当后代元素上的事件被触发时,其祖先元素的相同事件也会被触发
点一下 span,span、div、body 的单击响应函数都会被触发
在开发中大部分情况冒泡都是有用的,如果不希望发生事件冒泡可以通过事件对象来取消冒泡
9、事件的委派
事件的委派
指将事件统一绑定给元素的共同的祖先元素,这样当后代元素上的事件触发时,会一直冒泡到祖先元素,从而通过祖先元素的响应函数来处理事件。
事件委派是利用了冒泡,通过委派可以减少事件绑定的次数,提高程序的性能
10、事件的绑定
使用
对象.事件 = 函数
的形式绑定响应函数,它只能同时为一个元素的一个事件绑定一个响应函数,能绑定多个,如果绑定了多个,则后边会覆盖掉前边的addEventListener()
通过这个方法也可以为元素绑定响应函数
参数:
事件的字符串,不要 on
回调函数,当事件触发时该函数会被调用
是否在捕获阶段触发事件,需要一个布尔值,一般都传 false
使用 addEventListener() 可以同时为一个元素的相同事件同时绑定多个响应函数,这样当事件被触发时,响应函数将会按照函数的绑定顺序执行
这个方法不支持 IE 8 及以下的浏览器
attachEvent()
在 IE 8 中可以使用 attachEvent() 来绑定事件
参数:
这个方法也可以同时为一个事件绑定多个处理函数,不同的是它是后绑定先执行,执行顺序和 addEventListener() 相反(顺序实在有要求可以反着写)
定义一个函数,用来为指定元素绑定响应函数
addEventListener() 中的 this,是绑定事件的对象
attachEvent() 中的 this,是 window
需要统一两个方法 this
11、事件的传播
关于事件的传播网景公司和微软公司有不同的理解
W3C综合了两个公司的方案,将事件传播分为了三个阶段:
如果希望在捕获阶段就触发事件,可以在 addEventListener() 的第三个参数设置为 true,一般情况下我们不会希望在捕获阶段触发事件,所以这个参数一般都是 false
IE 8 及以下的浏览器中没有捕获阶段
12、鼠标事件
onmousedown、onmousemove、onmouseup
拖拽
还记得 H5 新添加的那个拖拽 API 嘛,那个非常好用的对吧,可是在 H5 还没出来的时候咋实现的呢
onmouseup 使用过了直接就不需要了,可以直接取消,这样 onmouseup 就变成一次性事件了。
点击 box 光标会变到鼠标左上角,需要求出 box 的偏移量,在按下时求出,移动时减去这个偏移量就是鼠标所处的位置了(如果有滚动条还要进行处理)
封装
鼠标滚轮事件
onmousewheel(火狐用 DOMMouseScroll)
13、键盘事件
onkeydown
按键被按下
对于 onkeydown 来说如果一直按着某个按键不松手,则事件会一直触发
当 onkeydown 连续触发时,第一次和第二次之间会间隔稍微长一点,其他的会非常的快,这种设计是为了防止误操作的发生。
onkeyup
按键被松开
键盘事件一般都会绑定给一些可以获取到焦点的对象或者是 document
可以通过 keyCode 来获取按键的编码
通过它可以判断哪个按键被按下
除了keyCode,事件对象中还提供了几个属性
altKey
ctrlKey
shiftKey
,这个三个用来判断 alt ctrl 和 shift 是否被按下,如果按下则返回 true,否则返回 false通过按键移动盒子
还存在问题:会有卡顿
总结:
JS 中事件可以分为以下几种
涉及概念
四、BOM
BOM (浏览器对象模型)可以使我们通过 js 来操作浏览器
在 BOM 中为我们提供了一组对象,用来完成对浏览器的操作
BOM 对象:
这些 BOM 对象在浏览器中都是作为 window 对象的属性保存的,可以通过 window 对象来使用,也可以直接使用
1、Navigator
一般我们只会使用 userAgent 来判断浏览器的信息,userAgent 是一个字符串,这个字符串中包含有用来描述浏览器信息的内容,不同的浏览器会有不同的 userAgent
根据 UA 来判断
如果通过 userAgent 不能判断,还可以通过一些浏览器中特有的对象,来判断浏览器的信息
比如:
ActiveXObject
2、History
History 对象可以用来操作浏览器向前或向后翻页
3、Location
如果直接打印 location,则可以获取到地址栏中的信息(当前页面的完整路径)
如果直接将 location 属性修改为一个完整的路径或相对路径,则我们的页面会自动跳转到该路径,并且会生成响应的历史记录
4、Screen
5、Window
定时器:
循环定时器
js 的程序执行速度是非常快的,如果洗完过一段程序,可以每隔一段事件执行一次,可以使用定时调用
setInterval()
定时调用可以将一个函数,每隔一段事件执行一次
参数有两个:
第一个是回调函数,该函数会每隔一段时间调用一次
第二个是每次调用间隔的时间,单位是毫秒
返回值:
返回一个 Number 类型的数据,这个数字用来作为定时器的唯一标识
clearInterval()
可以用来关闭一个定时器,方法中需要一个定时器的标识作为参数,这样将关闭标识对应的定时器延时定时器
setTimeout()
延时调用,延时调用一个函数不马上执行,而是隔一段时间以后在执行,而且只会执行一次延时调用和定时调用的区别,定时调用会执行多次,而延时调用只会执行一次
延时调用和定时调用实际上是可以互相代替的,在开发中可以根据自己需要去选择
1、count 自动增加
2、自动切换图片
3、解决按键移动 box 卡顿问题
延时调用
44、盒子移动
5、封装一个移动函数
封装 move.js
调用
6、轮播图
js
类的操作实现样式修改
我们可以通过修改元素的 class 属性来间接地修改样式,这样一来,我们只需要修改一次,即可同时修改多个样式,浏览器只需要重新渲染页面一次,性能比较好,并且这种方式,可以使表现和行为进一步地分离
定义函数,用来对一个元素中 class 进行操作
二级菜单
使这个菜单在点击时能够把二级菜单展示出来,点击另一个 span,关掉该项打开点击的项
新的 class 操作:
五、JSON
JSON
JS 中的对象只有 JS 自己认识,其他的语言都不认识
JSON 就是一个特殊格式的字符串,这个字符串可以被任意的语言所识别,并且可以转换为任意语言中的对象,JSON 在开发中主要用来数据的交互
JavaScript Object Notation JS 对象表示法
JSON 借鉴了部分 JS 的语法,实现了 number、boolean、string、array、object、null 的表示
JSON 和 JS 对象的格式一样,只不过 JSON 字符串中的属性名必须加双引号,其他的和 JS 语法一致
JSON 分类:
{}
[]
JSON中允许的值:
将 JSON 字符串转换为 JS 中的对象
JSON ---> JS对象
JSON.parse()
JS对象 ---> JSON
JSON.stringify()
JSON 这个对象在 IE 7 及以下的浏览器中不支持,所以在这些浏览器中调用时会报错
如果需要兼容 IE 7 及以下的 JSON 操作,则可以通过引入一个外部的 js 文件来处理
eval()