初识JavaScript
Js组成
- ECMAScript:JavaScript语法
- DOM:页面文档对象模型
标准编程接口.通过 DOM 提供的接口可以对页面上的各种元素进行操作(大小、位置、颜色等)。
- BOM:浏览器对象模型
通过BOM可以操作浏览器窗口,比如弹出框、控制浏览器跳转、获取分辨率等
Js三种书写位置
- 行内式
- 内嵌
- 外部
Js基础
输入输出
变量
使用
var myname = prompt(‘请输入您的名字:’);
可以将输入内容存入变量myname
- 若只声明未赋值:为undefined.
命名规范
数据类型
数据类型由 JS引擎 根据 = 右边变量值的数据类型来判断 的
JavaScript 拥有动态类型,意味着相同的变量可用作不同的类型
JS 把数据类型分为两类:
- 简单数据类型 (Number,String,Boolean,Undefined,Null)
- 复杂数据类型 (object)
简单数据类型
数字型number
- 数字型进制
二进制\八进制\十进制\十六进制
八进制前加0,十六进制前加0x
- 数字型范围
最大值和最小值:
alert(Number.MAX_VALUE); // 1.7976931348623157e+308
alert(Number.MIN_VALUE); // 5e-324
- 三个特殊值
- isNaN()
用来判断一个变量是否为非数字的类型
字符串型String
使用""或’’
引号可以嵌套:外单内双或内单外双
- 转义符
- 字符串长度length
- 字符串拼接"+"
拼接方式为 字符串 + 任何类型 = 拼接之后的新字符串
布尔型Boolean
true=1
false=0
undefine和Null
一个声明后没有被赋值的变量会有一个默认值 undefined
一个声明变量给 null 值,里面存的值为空
获取变量的数据类型
typeof 可用来获取检测变量的数据类型
数据类型转换
转换为字符串
更常用第三种
转换为数字型(重点)
转换为布尔型
运算符
算数运算符
浮点数精度
浮点数值的最高精度是 17 位小数,但在进行算术计算时其精确度远远不如整数
不要直接判断两个浮点数是否相等
递增和递减运算符
用**递增(++)和递减( – )**运算符
++num 前置递增,先自加,后返回值
num++ 后置递增,先返回原值,后自加
比较运算符
比较运算后,会返回一个布尔值 (true / false)作为比较运算的结果
"="小结
逻辑运算符
返回值也是布尔值
短路运算(逻辑中断)
当有多个表达式(值)时,左边的表达式值可以确定结果时,就不再继续运算右边的表达式的值
- 逻辑与
- 逻辑或
赋值运算符
运算符优先级
- 一元运算符里" ! "优先级很高
- " && "比 " || "优先级高
流程控制–分支
顺序结构、分支结构和循环结构
分支结构
if语句
三元表达式
表达式1 ? 表达式2 : 表达式3;
如果表达式1为 true ,则返回表达式2的值,如果表达式1为 false,则返回表达式3的值
switch语句
流程控制–循环
for循环
for 循环主要用于把某些代码循环若干次,通常跟计数有关系
断点调试
while循环
while 循环和 for 循环的不同之处在于 while 循环可以做较为复杂的条件判断,比如判断用户名和密码
do while循环
注意:先再执行循环体,再判断, do…while 循环语句至少会执行一次循环体代码
continue和break
continue 关键字用于立即跳出本次循环,继续下一次循环
break 关键字用于立即跳出整个循环(循环结束)
数组
创建数组
- 用new创建(对象):var arr = new Array();
- 利用数组字面量:var 数组名 = [1,2,‘你好’,true ];
- (数组里数据可以是任意类型,一定用逗号分隔.
获取数组元素
数组名[索引号]
数组长度
数组名.length
数组新增元素
修改length长度
添加长度后,没有初始值的索引元素为undefined
修改索引
不可以直接给数组名赋值,否则会覆盖掉以前的数据
函数
function 函数名( ) {
}
调用函数: 函数名( );
function 函数名(形参1,形参2… ) {
}(这里的形参变量不需要声明)
调用函数: 函数名(实参1,实参2… );
形参和实参匹配
- 形参个数<实参个数:形参匹配前几个实参,取到实参的个数;
- 形参个数>实参个数:多的形参看作未定义undefined,参加运算计算结果为NaN
函数返回值return
function 函数名( ) {
return 需要返回的结果;
}
调用函数: 函数名( );
实际应用,经常用一个变量接受返回结果。
函数没有return则返回undefined。
arguments使用
当不确定有多少参数传递时,用arguments获取。
arguments实际上是当前函数的一个内置对象,arguments对象中存储了传递的所有实参。
// arguments 的使用 只有函数才有 arguments对象 而且是每个函数都内置好了这个arguments
function fn() {
// console.log(arguments); // 里面存储了所有传递过来的实参 arguments = [1,2,3]
// console.log(arguments.length);
// console.log(arguments[2]);
// 我们可以按照数组的方式遍历arguments
for (var i = 0; i < arguments.length; i++) {
console.log(arguments[i]);
}
}
fn(1, 2, 3);
fn(1, 2, 3, 4, 5);
// 伪数组 并不是真正意义上的数组
// 1. 具有数组的 length 属性
// 2. 按照索引的方式进行存储的
// 3. 它没有真正数组的一些方法 pop() push() 等
函数两种声明方式
- 命名函数:上面说过的声明
- 匿名函数——函数表达式:var 变量名 = function(){ };
var fun = function() { };
调用:fun();
作用域
- 全局变量
- 全局变量: 在全局作用域下的变量 在全局下都可以使用
// 注意 如果在函数内部 没有声明直接赋值的变量也属于全局变量
- 局部变量
- 局部变量 在局部作用域下的变量 后者在函数内部的变量就是 局部变量
// 注意: 函数的形参也可以看做是局部变量
- 比较
- 从执行效率来看全局变量和局部变量
// (1) 全局变量只有浏览器关闭的时候才会销毁,比较占内存资源
// (2) 局部变量 当我们程序执行完毕就会销毁, 比较节约内存资源
- js没有块级作用域(在es6时新增块级作用域)
- 作用域链:内层函数就近访问外层函数的变量.
预解析
将所有变量声明和函数声明提到其作用域的最前面,但是不赋值.
对象
对象是一组无序的相关属性和方法的集合
由属性和方法组成
- 属性:事物的特征
- 方法:事物的行为
创建对象
字面量创建对象
var obj = {
uname**😗* ‘张三’,
age**😗* 18**,**
sex: ‘男’,
sayHi: function() {
console.log(‘hi’);
}
** }**
- 属性或方法采用键:值对的形式
- 多个属性或方法用逗号隔开
- 方法冒号后是一个匿名函数
- 使用对象:对象名.属性名 .如obj.uname;或对象名[‘属性名’].如obj[‘age’]
- 使用方法:对象名.方法名( ) . (不要忘记小括号)
变量\属性\函数\方法总结
new Object创建对象
var obj = new Object();
obj.uname = ‘张三’;
obj.age = 18;
obj.sex = ‘男’;
obj.sayHi = function() {
}
调用同上.
构造函数创建对象
以上两种方法一次只能创建一个对象
使用构造函数可以一次创建多个对象
构造函数就是把对象里一些相同的属性和方法抽象出来封装到函数里
function 构造函数名( ) {
**this.**属性 = 值;
this.方法 = function() { }
}
var 对象名 = new 构造函数名( );
- 构造函数名首字母要大写
- 构造函数必须使用new
遍历对象for…in
for(变量 in 对象){
}
for(var k in obj){
console.log(k); //变量–输出的是遍历属性名
console.log(obj[k]); //obj[k]–输出的是遍历属性值(一定要用[ ]的形式)
}
内置对象
查文档MDN
https://developer.mozilla.org/zh-CN/
Math对象
对于内置对象不用new,直接使用里面的属性和方法即可.
注意:Math.round()四舍五入–其他数字都是四舍五入,只有**.5是往大了取;Math.round(1.5)=2;Math.round(-1.5)=-1;
随机数方法Math.random()
random() 方法可以随机返回一个小数**,其取值范围是 [0,1),左闭右开 0 <= x < 1
得到一个两数之间的随机整数,包括两个数在内
function getRandom(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
日期对象
是一个构造函数,必须使用new来创建日期对象
var date = new Date();
console.log(date);
- 如果Date()不写参数,就返回当前时间
- 如果Date()里面写参数,就返回括号里面输入的时间(常见写法,数字型 2019,10,1或字符串型’2019-10-1 8:8:8’
- 格式化日期
vardate = newDate();
console.log(date.getFullYear()); // 返回当前日期的年 2019
console.log(date.getMonth() + 1); // 月份 返回的月份小1个月 记得月份+1 呦
console.log(date.getDate()); // 返回的是 几号
console.log(date.getDay()); // 3 周一返回的是 1 周六返回的是 6 但是 周日返回的是 0
var arr = [‘星期日’, ‘星期一’, ‘星期二’, ‘星期三’, ‘星期四’, ‘星期五’, ‘星期六’];
var day = date.getDay();
console.log(‘今天是:’ + year + ‘年’ + month + ‘月’ + dates + '日 ’ + arr[day]);
console.log(date.getHours()); // 时
console.log(date.getMinutes()); // 分
console.log(date.getSeconds()); // 秒
// 要求封装一个函数返回当前的时分秒 格式 08:08:08
function getTimer() {
var time = newDate();
var h = time.getHours();
h = h < 10 ? ‘0’ + h : h;
var m = time.getMinutes();
m = m < 10 ? ‘0’ + m : m;
var s = time.getSeconds();
s = s < 10 ? ‘0’ + s : s;
return h + ‘:’ + m + ‘:’ + s;
}
console.log(getTimer());
获取日期的总毫秒数
// 获得Date总的毫秒数(时间戳) 不是当前时间的毫秒数 而是距离1970年1月1号过了多少毫秒数
// 1. 通过 valueOf() getTime()
var date = newDate();
console.log(date.valueOf()); // 就是 我们现在时间 距离1970.1.1 总的毫秒数
console.log(date.getTime());
// 2. 简单的写法 (最常用的写法)
var date1 = +newDate(); // **+new Date() **返回的就是总的毫秒数
console.log(date1);
// 3. H5 新增的 获得总的毫秒数
console.log(Date.now());
倒计时
function countDown(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(countDown('2022-1-31 8:00:00'));
数组对象
- 创建数组
- 利用数组字面量
var arr = [1,2,3];
console.log(arr[0]);
- 利用new Array( )
var arr1 = new Array(2); (表示数组长度为2)
var arr1 = new Array(2,3); (表示里面有两个数组元素:2,3)
- 检测是否为数组
- instanceof 运算符,可以判断一个对象是否属于某种类型
- Array.isArray()用于判断一个对象是否为数组,isArray() 是 HTML5 中提供的方法
- 添加或删除元素
// 添加删除数组元素方法
// 1. push() 在我们数组的末尾 添加一个或者多个数组元素 push 推
var arr = [1, 2, 3];
// arr.push(4, ‘pink’);
console.log(arr.push(4, ‘pink’));
console.log(arr);
// (1) push 是可以给数组追加新的元素
// (2) push() 参数直接写 数组元素就可以了
// (3) push完毕之后,返回的结果是 新数组的长度
// (4) 原数组也会发生变化
// 2. unshift 在我们数组的开头 添加一个或者多个数组元素
console.log(arr.unshift(‘red’, ‘purple’));
console.log(arr);
// (1) unshift是可以给数组前面追加新的元素
// (2) unshift() 参数直接写 数组元素就可以了
// (3) unshift完毕之后,返回的结果是 新数组的长度
// (4) 原数组也会发生变化
// 3. pop() 它可以删除数组的最后一个元素
console.log(arr.pop());
console.log(arr);
// (1) pop是可以删除数组的最后一个元素 记住一次只能删除一个元素
// (2) pop() 没有参数
// (3) pop完毕之后,返回的结果是 删除的那个元素
// (4) 原数组也会发生变化
// 4. shift() 它可以删除数组的第一个元素
console.log(arr.shift());
console.log(arr);
// (1) shift是可以删除数组的第一个元素 记住一次只能删除一个元素
// (2) shift() 没有参数
// (3) shift完毕之后,返回的结果是 删除的那个元素
// (4) 原数组也会发生变化
- 数组排序
var arr = [1, 64, 9, 6];
arr.sort(function(a, b) {
return b - a; // 降序
// return a - b; // 升序
});
console.log(arr);
- 数组索引方法
var arr = [‘red’, ‘green’, ‘pink’];
console.log(arr.indexOf(‘blue’));
indexOf()只返回满足条件的第一个索引号
lastIndexOf()只返回满足条件的最后一个索引号
- 数组转换为字符串
// 数组转换为字符串
// 1. toString() 将我们的数组转换为字符串
var arr = [1, 2, 3];
console.log(arr.toString()); // 1,2,3
// 2. join(分隔符)
var arr1 = [‘green’, ‘blue’, ‘pink’];
console.log(arr1.join()); // green,blue,pink
console.log(arr1.join(’-’)); // green-blue-pink
console.log(arr1.join(’&’)); // green&blue&pink
字符串对象
- 基本包装类型
基本包装类型就是把简单数据类型包装成为复杂数据类型,这样基本数据类型就有了属性和方法
因为字符串不可变,所以不要大量拼接字符串
- 根据字符返回位置
字符串所有的方法,都不会修改字符串本身(字符串是不可变的),操作完成会返回一个新的字符串。
- 根据位置返回字符(重点)
- 拼接和截取字符串
// 1. concat(‘字符串1’,‘字符串2’…)
var str = ‘andy’;
console.log(str.concat(‘red’));
// 2. substr(‘截取的起始位置’, ‘截取几个字符’);
var str1 = ‘改革春风吹满地’;
console.log**(str1.substr(**2, 2)); // 第一个2 是索引号的2 从第几个开始 第二个2 是取几个字符
- 替换replace
replace() 方法用于在字符串中用一些字符替换另一些字符。
- split()方法
split(‘分隔符’)方法用于切分字符串,它可以将字符串切分为数组。在切分完毕之后,返回的是一个新数组。
var str2 = ‘red, pink, blue’;
console.log(str2.split(’,’));
var str3 = ‘red&pink&blue’;
console.log(str3.split(’&’));
简单类型与复杂类型
简单类型又叫做基本数据类型或者值类型,复杂类型又叫做引用类型。
简单数据类型
在存储时变量中存储的是值本身,因此叫做值类型
string ,number,boolean,undefined,null
栈(操作系统):由操作系统自动分配释放存放函数的参数值、局部变量的值等。其操作方式类似于数据结构中的栈;
简单数据类型存放到栈里面,直接开辟一个空间,存放的是值
传参
函数的形参也可以看做是一个变量,当把一个值类型变量作为参数传给函数的形参时,其实是把变量在栈 空间里的值复制了一份给形参,那么在方法内部对形参做任何修改,都不会影响到外部变量。
复杂数据类型
在存储时变量中存储的仅仅是地址(引用),因此叫做引用数据类型
通过 new 关键字创建的对象(系统对象、自定义对象),如 Object、Array、Date等
堆(操作系统):存储复杂类型(对象),一般由程序员分配释放,若程序员不释放,由垃圾回收机制回收。
复杂数据类型存放到堆里面(首先在栈里面存放地址 十六进制表示 然后这个地址指向堆里面的数据)
传参
函数的形参也可以看做是一个变量,当我们把引用类型变量传给形参时,其实是把变量在栈空间里保存的堆地
址复制给了形参,形参和实参其实保存的是同一个堆地址,所以操作的是同一个对象。
function Person(name) {
this.name = name;
}
function f1(x) { // x = p
console.log(x.name); // 2. 这个输出刘德华
x.name = “张学友”;
console.log(x.name); // 3. 这个输出张学友
}
var p = new Person(“刘德华”);
console.log(p.name); // 1. 这个输出刘德华
f1§;
console.log(p.name); // 4. 这个输出张学友
Web APIs
DOM
文档对象模型(Document Object Model,简称 DOM),是 W3C 组织推荐的处理可扩展标记语言(HTML 或者XML)的标准编程接口。
W3C 已经定义了一系列的 DOM 接口,通过这些 DOM 接口可以改变网页的内容、结构和样式
获取元素
根据ID获取
** document.getElementById(‘id’);**获取带有 ID 的元素对象。
//一定是document,括号里面是字符串,要加‘’
通过HTML5新增方法获取
- document.getElementsByClassName(‘类名’);// 根据类名返回元素对象集合
- document.querySelector(‘选择器’); // 根据指定选择器返回第一个元素对象
- document.querySelectorAll(‘选择器’); // 根据指定选择器返回
querySelector 和 querySelectorAll里面的选择器需要加符号,比如:document.querySelector(’#nav’);,类加.,.box;id加#,#nav
总结
自定义属性值
获取属性值: element.属性获取内置属性值(元素本身自带的属性)
element.getAttribute(‘属性’); 主要获得自定义的属性 (标准) 我们程序员自定义的属性
设置属性值: element.属性设置内置属性值
element.setAttribute(‘属性’); 主要设置自定义的属性 (标准)
移除属性:element.removeAttribute(‘属性’);
H5规定自定义属性**data-**开头做为属性名并且赋值
** 获取H5自定义属性 **
- 兼容性获取 element.getAttribute(‘data-index’);
- H5新增 element.dataset.index 或者 element.dataset[‘index’] ie 11才开始支持
节点操作
节点层级
- 父级节点
node.parentNode
得到的是离它最近的父节点
如果指定的节点没有父节点则返回 null
// 1. 父节点 parentNode
var erweima = document.querySelector(’.erweima’);
// var box = document.querySelector(’.box’);
// 得到的是离元素最近的父级节点(亲爸爸) 如果找不到父节点就返回为 null
console.log(erweima.parentNode);
- 子节点
parentNode.childNodes(标准)//不常用
parentNode.children(非标准)
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);
3. parentNode.firstChild
firstChild 返回第一个子节点,找不到则返回null。同样,也是包含所有的节点。
-
parentNode.**lastChild **
lastChild 返回最后一个子节点,找不到则返回null。同样,也是包含所有的节点(文本节点、元素节点)。 -
parentNode.**firstElementChild **
firstElementChild 返回第一个子元素节点,找不到则返回null。 -
parentNode.**lastElementChild **
lastElementChild 返回最后一个子元素节点,找不到则返回null。
注意:这两个方法有兼容性问题,IE9 以上才支持。
实际开发中,firstChild 和 lastChild 包含其他节点,操作不方便,而 firstElementChild 和
lastElementChild 又有兼容性问题,那么我们如何获取第一个子元素节点或最后一个子元素节点呢?
**解决方案: **
-
如果想要第一个子元素节点,可以使用 parentNode.chilren[0]
-
如果想要最后一个子元素节点,可以使用 parentNode.chilren[parentNode.chilren.length - 1]
-
兄弟节点
-
node.**nextSibling **
nextSibling 返回当前元素的下一个兄弟元素节点,找不到则返回null。同样,也是包含所有的节点。 -
node.**previousSibling **
previousSibling 返回当前元素上一个兄弟元素节点,找不到则返回null。同样,也是包含所有的节点。 -
node.nextElementSibling
nextElementSibling 返回当前元素下一个兄弟元素节点,找不到则返回null。 -
node.previousElementSibling
previousElementSibling 返回当前元素上一个兄弟节点,找不到则返回null。
注意:这两个方法有兼容性问题, IE9 以上才支持
创建节点
document.createElement(‘tagName’)
想要页面添加一个新的元素:1.创建元素2.添加元素
// 1. 创建节点元素节点
var li = document.createElement(‘li’);
// 2. 添加节点 node.appendChild(child) node 父级 child 是子级 后面追加元素 类似于数组中的push
var ul = document.querySelector(‘ul’);
ul.appendChild(li);
// 3. 添加节点 node.insertBefore(child, 指定元素);
varlili = document.createElement(‘li’);
ul.insertBefore(lili, ul.children[0]);
// 4. 我们想要页面添加一个新的元素 : 1. 创建元素 2. 添加元素
删除节点
node.removeChild(child)
node.removeChild() 方法从 DOM 中删除一个子节点,返回删除的节点。
阻止链接跳转需要添加 javascript:void(0); 或者 javascript:;
// (1) 创建元素
varli = document.createElement(‘li’);
// 先有li 才能赋值
li.innerHTML = text.value + “删除”;
复制节点
node.cloneNode() 方法返回调用该方法的节点的一个副本。 也称为克隆节点/拷贝节点
**注意: **
- 如果括号参数为空或者为 false ,则是浅拷贝,即只克隆复制节点本身,不克隆里面的子节点。
- 如果括号参数为 true ,则是深度拷贝,会复制节点本身以及里面所有的子节点。
三种创建元素的区别
document.write()
element.innerHTML
document.createElement()
**区别 **
- document.write 是直接将内容写入页面的内容流,但是文档流执行完毕,则它会导致页面全部重绘
- innerHTML 是将内容写入某个 DOM 节点,不会导致页面全部重绘
- innerHTML 创建多个元素效率更高(不要拼接字符串,采取数组形式拼接),结构稍微复杂
- createElement() 创建多个元素效率稍低一点点,但是结构更清晰
总结:不同浏览器下,innerHTML 效率要比 creatElement 高
DOM核心重点
创建
- document.write
- innerHTML
- createElement
增
- appendChild
- insertBefore
删
- removeChild
改
主要修改dom的元素属性,dom元素的内容、属性, 表单的值等
- 修改元素属性: src、href、title等
- 修改普通元素内容: innerHTML 、innerText
- 修改表单元素: value、type、disabled等
- 修改元素样式: style、className
查
主要获取查询dom的元素
- DOM提供的API 方法: getElementById、getElementsByTagName 古老用法 不太推荐
- H5提供的新方法: querySelector、querySelectorAll 提倡
- 利用节点操作获取元素: 父(parentNode)、子(children)、兄(previousElementSibling、
nextElementSibling) 提倡
属性操作
主要针对于自定义属性。
- setAttribute:设置dom的属性值
- getAttribute:得到dom的属性值
- removeAttribute移除属性
事件操作
给元素注册事件, 采取 事件源.事件类型 = 事件处理程序
事件高级
注册事件
传统监听方式:注册事件的唯一性
事件监听方式
addEventListener 事件监听方式
eventTarget.addEventListener(type, listener[, useCapture])
eventTarget.addEventListener()方法将指定的监听器注册到 eventTarget(目标对象)上,当该对
象触发指定的事件时,就会执行事件处理函数。
该方法接收三个参数:
type:事件类型字符串,比如 click 、mouseover ,注意这里不要带 on
listener:事件处理函数,事件发生时,会调用该监听函数
useCapture:可选参数,是一个布尔值,默认是 false。学完 DOM 事件流后,我们再进一步学习
** attachEvent 事件监听方式 **
eventTarget.attachEvent(eventNameWithOn, callback)
eventTarget.attachEvent()方法将指定的监听器注册到 eventTarget(目标对象) 上,当该对象触
发指定的事件时,指定的回调函数就会被执行。
该方法接收两个参数:
eventNameWithOn:事件类型字符串,比如 onclick 、onmouseover ,这里要带 on
callback: 事件处理函数,当目标触发事件时回调函数被调用
**注意:**IE8 及早期版本支持
var btns = document.querySelectorAll(‘button’);
// 1. 传统方式注册事件
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);
})
// 3. attachEvent ie9以前的版本支持
btns[2].attachEvent(‘onclick’, function() {
alert(11);
})
删除事件
传统注册方式
eventTarget.onclick = null;
方法监听注册方式
① eventTarget.removeEventListener(type, listener[, useCapture]);
② eventTarget.detachEvent(eventNameWithOn, callback);
var divs = document.querySelectorAll(‘div’);
divs[0].onclick = function() {
alert(11);
// 1. 传统方式删除事件
divs[0].onclick = null;
}
// 2. removeEventListener 删除事件
divs[1].addEventListener(‘click’, fn) // 里面的fn 不需要调用加小括号
functionfn() {
alert(22);
divs[1].removeEventListener(‘click’, fn);
}
// 3. detachEvent
divs[2].attachEvent(‘onclick’, fn1);
functionfn1() {
alert(33);
divs[2].detachEvent(‘onclick’, fn1);
}
DOM事件流
事件流描述的是从页面中接收事件的顺序。
事件发生时会在元素节点之间按照特定的顺序传播,这个传播过程即 DOM 事件流。
DOM 事件流分为3个阶段:
- 捕获阶段
- 当前目标阶段
- 冒泡阶段
事件冒泡: IE 最早提出,事件开始时由最具体的元素接收,然后逐级向上传播到到 DOM 最顶层节点的过程。
事件捕获: 网景最早提出,由 DOM 最顶层节点开始,然后逐级向下传播到到最具体的元素接收的过程。
**注意 ** - JS 代码中只能执行捕获或者冒泡其中的一个阶段。
- onclick 和 attachEvent 只能得到冒泡阶段。
- addEventListener(type, listener[, useCapture])第三个参数如果是 true,表示在事件捕获阶段调用事件处理程序;如果是 false(不写默认就是false),表示在事件冒泡阶段调用事件处理程序。
- 实际开发中我们很少使用事件捕获,我们更关注事件冒泡。
- 有些事件是没有冒泡的,比如 onblur、onfocus、onmouseenter、onmouseleave
事件对象
event就是一个事件对象,写到侦听函数的小括号里,当形参来看
eventTarget.onclick = function(event) {}
eventTarget.addEventListener(‘click’, function(event) {})
// 这个 event 就是事件对象,我们还喜欢的写成 e 或者 evt
官方解释:event 对象代表事件的状态,比如键盘按键的状态、鼠标的位置、鼠标按钮的状态。
简单理解:事件发生后,跟事件相关的一系列信息数据的集合都放到这个对象里面,这个对象就是事件对象event,它有很多属性和方法。
比如:
- 谁绑定了这个事件。
- 鼠标触发事件的话,会得到鼠标的相关信息,如鼠标位置。
- 键盘触发事件的话,会得到键盘的相关信息,如按了哪个键。
这个 event 是个形参,系统帮我们设定为事件对象,不需要传递实参过去。
当我们注册事件时, event 对象就会被系统自动创建,并依次传递给事件监听器(事件处理函数)。
事件对象常见的属性和方法
e.target 和 this 的区别:
this 是事件绑定的元素, 这个函数的调用者(绑定这个事件的元素)
e.target 是事件触发的元素。
区别 : e.target 点击了那个元素,就返回那个元素 this 那个元素绑定了这个点击事件,那么就返回谁
// 常见事件对象的属性和方法
// 1. 返回事件类型
var div = document.querySelector('div');
div.addEventListener('click', fn);
div.addEventListener('mouseover', fn);
div.addEventListener('mouseout', fn);
function fn(e) {
console.log(e.type);
}
// 2. 阻止默认行为(事件) 让链接不跳转 或者让提交按钮不提交
var a = document.querySelector('a');
a.addEventListener('click', function(e) {
e.preventDefault(); // dom 标准写法
})
// 3. 传统的注册方式
a.onclick = function(e) {
// 普通浏览器 e.preventDefault(); 方法
// e.preventDefault();
// 低版本浏览器 ie678 returnValue 属性
// e.returnValue;
// 我们可以利用return false 也能阻止默认行为 没有兼容性问题 特点: return 后面的代码不执行了, 而且只限于传统的注册方式
returnfalse;
alert(11);
}
阻止事件冒泡
标准写法:利用事件对象里面的 stopPropagation()方法
e.stopPropagation()
非标准写法:IE 6-8 利用事件对象 cancelBubble 属性
e.cancelBubble = true;
**阻止事件冒泡的兼容性解决方案 **
if(e && e.stopPropagation){
e.stopPropagation();
}else{
window.event.cancelBubble = true;
}
事件委托
事件委托也称为事件代理, 在 jQuery 里面称为事件委派。
**事件委托的原理 **
不是每个子节点单独设置事件监听器,而是事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点。
以上案例:给 ul 注册点击事件,然后利用事件对象的 target 来找到当前点击的 li,因为点击 li,事件会冒泡到 ul 上,ul 有注册事件,就会触发事件监听器。
**事件委托的作用 **
我们只操作了一次 DOM ,提高了程序的性能
常用的鼠标事件
1.禁止鼠标右键菜单
contextmenu主要控制应该何时显示上下文菜单,主要用于程序员取消默认的上下文菜单
document.addEventListener(‘contextmenu’, function(e) {
e.preventDefault();
})
2.禁止鼠标选中(selectstart 开始选中)
document.addEventListener(‘selectstart’, function(e) {
e.preventDefault();
})
鼠标事件对象
event对象代表事件的状态,跟事件相关的一系列信息的集合。现阶段我们主要是用鼠标事件对象
MouseEvent 和键盘事件对象 KeyboardEvent。
常用的键盘事件
**注意: **
**1. 如果使用addEventListener 不需要加 on **
2. onkeypress 和前面2个的区别是,它不识别功能键,比如左右箭头,shift 等。
3. 三个事件的执行顺序是: keydown – keypress — keyup
**注意:**onkeydown 和 onkeyup 不区分字母大小写,onkeypress 区分字母大小写。
在我们实际开发中,我们更多的使用keydown和keyup, 它能识别所有的键(包括功能键)
Keypress 不识别功能键,但是keyCode属性能区分大小写,返回不同的ASCII值
// 核心思路: 检测用户是否按下了s 键,如果按下s 键,就把光标定位到搜索框里面
// 使用键盘事件对象里面的keyCode 判断用户按下的是否是s键
// 搜索框获得焦点: 使用 js 里面的 focus() 方法
var search = document.querySelector(‘input’);
document.addEventListener(‘keyup’, function(e) {
// console.log(e.keyCode);
if (e.keyCode === 83) {
search.focus();
}
})
④ 注意: keydown 和 keypress 在文本框里面的特点: 他们两个事件触发的时候,文字还
没有落入文本框中。
⑤ keyup事件触发的时候, 文字已经落入文本框里面了
BOM
BOM(Browser Object Model)即浏览器对象模型,它提供了独立于内容而与浏览器窗口进行交互的对象,其核心对象是 window。
BOM 由一系列相关的对象构成,并且每个对象都提供了很多方法与属性。
BOM 缺乏标准,JavaScript 语法的标准化组织是 ECMA,DOM 的标准化组织是 W3C,BOM 最初是Netscape 浏览器标准的一部分。
BOM 比 DOM 更大,它包含 DOM。
**window 对象是浏览器的顶级对象,**它具有双重角色。
- 它是 JS 访问浏览器窗口的一个接口。
- 它是一个全局对象。定义在全局作用域中的变量、函数都会变成 window 对象的属性和方法。
在调用的时候可以省略 window,前面学习的对话框都属于 window 对象方法,如 alert()、prompt() 等。
**注意:**window下的一个特殊属性 window.name
windows对象的常见事件
窗口加载事件
- window.onload = function(){}
或者
- window.addEventListener(‘load’,function(){});
当文档内容完全加载完成会触发该事件(包括图像、脚本文件、CSS文件等), 就调用的处理函数。
**注意: **
- 有了 window.onload 就可以把 JS 代码写到页面元素的上方,因为 onload 是等页面内容全部加载完毕,再去执行处理函数。
- window.onload 传统注册事件方式只能写一次,如果有多个,会以最后一个 window.onload 为准。
- 如果使用 addEventListener 则没有限制
- document.addEventListener(‘DOMContentLoaded’,function(){})
DOMContentLoaded 事件触发时,仅当DOM加载完成,不包括样式表,图片,flash等等。
Ie9以上才支持
如果页面的图片很多的话, 从用户访问到onload触发可能需要较长的时间, 交互效果就不能实现,必然影响用户的体验,此时用 DOMContentLoaded 事件比较合适。
调整窗口大小事件
window.onresize = function(){}
window.addEventListener(“resize”,function(){});
**注意: **
- 只要窗口大小发生像素变化,就会触发这个事件。
- 我们经常利用这个事件完成响应式布局。 window.innerWidth 当前屏幕的宽度
定时器
setTimeout()定时器
window.setTimeout(调用函数, [延迟的毫秒数]);(window可以省略)
**注意: **
- window 可以省略。
- 这个调用函数可以直接写函数,或者写函数名或者采取字符串‘函数名()'三种形式。第三种不推荐
- 延迟的毫秒数省略默认是 0,如果写,必须是毫秒。
- 因为定时器可能有很多,所以我们经常给定时器赋值一个标识符
function callback() {
console.log(‘爆炸了’);
}
var timer1 = setTimeout(callback, 3000);
var timer2 = setTimeout(callback, 5000);
停止setTimeout()定时器
window.clearTimeout(timeoutID);(window可以省略)
里面的参数就是定时器的标识符 。
setInterval()定时器
window.setInterval(回调函数, [间隔的毫秒数]);
setInterval() 方法重复调用一个函数,每隔这个时间,就去调用一次回调函数。
**注意: **
- window 可以省略。
- 这个调用函数可以直接写函数,或者写函数名或者采取字符串 ‘函数名()’ 三种形式。
- 间隔的毫秒数省略默认是 0,如果写,必须是毫秒,表示每隔多少毫秒就自动调用这个函数。
4.因为定时器可能有很多,所以我们经常给定时器赋值一个标识符。 - 第一次执行也是间隔毫秒数之后执行,之后每隔毫秒数就执行一次。
停止setInerval()定时器
window.clearInterval(intervalID);
this
this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,一般情况下this的最终指向的是那个调用它的对象
现阶段,我们先了解一下几个this指向
- 全局作用域或者普通函数中this指向全局对象window(注意定时器里面的this指向window)
- 方法调用中谁调用this指向谁
3.构造函数中this指向构造函数的实例
JS执行机制
JS是单线程
同步和异步
同步任务 **
同步任务都在主线程上执行,形成一个执行栈。 **
异步任务 **
JS 的异步是通过回调函数实现的。
一般而言,异步任务有以下三种类型:
1、普通事件,如 click、resize 等
2、资源加载,如 load、error 等
3、定时器,包括 setInterval、setTimeout 等
异步任务相关回调函数添加到任务队列**中(任务队列也称为消息队列)。
- 先执行执行栈中的同步任务。
- 异步任务(回调函数)放入任务队列中。
- 一旦执行栈中的所有同步任务执行完毕,系统就会按次序读取任务队列中的异步任务,于是被读取的异步任务结束等待状态,进入执行栈,开始执行。
location对象
location 属性用于获取或设置窗体的 URL,并且可以用于解析 URL 。 因为
这个属性返回的是一个对象,所以我们将这个属性也称为 location 对象。
URL
统一资源定位符 (Uniform Resource Locator, URL) 是互联网上标准资源的地址。互联网上的每个文件都有
一个唯一的 URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它。
URL 的一般语法格式为:
protocol://host[:port]/path/[?query]#fragment
http://www.itcast.cn/index.html?name=andy&age=18#link
location对象的属性
获取URL参数数据(练习数据在不同页面中的传递)
login.html