JavaScript学习
JavaScript基础
📚 Web 学习目录
🚀 HTML学习 - 📝 CSS学习 - 🚗 Flex 与 Grid 学习 - 🔦 JavaScript学习 - 🎉 JavaScript 高级
本教程里的资料来源于网友的资料,自己整理以供学习。视频学习:黑马程序员
JS概论
HTML/CSS -
标记语言JS脚本语言 -
编程类语言
浏览器分成两部分,
渲染引擎和JS引擎
- 渲染引擎:用来解析 HTML 与 CSS,俗称内核,比如 Chrome 的 blink
 
JS引擎: JS解释器,用来读取网页中的 JavaScript 代码,对其处理后运行,比如 chrome 浏览器的 V8
浏览器本身并不会执行 JS 代码,而是通过内置 JavaScript 引擎来执行 JS 代码, JS 引擎执行代码时逐行解释每一句源码(转换为机器语言二进制),然后由计算机去执行
解释性语言: 进行时立即解释执行的语言 如 Js编译性语言: 必须通过编译生成中间代码后才执行的语言 如 Java、C
JS组成: ECMAscript(js语法)、DOM(页面文档对象模型)、BOM(浏览器对象模型)后两者即合称 API
- ECMAscript: 规定了JS的编程语法和基础核心知识,是所有浏览器厂商共同遵守的一套 JS 语法工业标准
 
JavaScript程序的执行
- 出现在
<script>和</script>标记对之间的 javascript 语句按照它们在脚本中出现的顺序来执行。当一个文件有多个脚本的时候,脚本按照它们出现的顺序来执行(除非脚本带有 defer 属性)。<script>标记中的 JS 代码作为文档载入和解析过程的一部分来执行 
JS词法结构
JS注释
单行注释
1
// 这一行都是注释内容
多行注释
1
2
3/*
这里面的内容为注释
*/快捷键
1
2
3单行注释 ctrl+/
多行注释 ctrl+shift+/
JS相关
标识符、关键字、保留字、直接量
标识符: 开发人员为变量、属性、函数、参数取的名字(标识符不能是关键字或保留字)关键字: js 本身已经使用了的字保留字: 为后面预留的关键字 如booleanbytecharint等字面量(直接量):程序中直接显示出来的数据值数字字面量: 8、9、10字符串字面量: “大前端”布尔字面量: true false
JS命名规则
标识符命名规则
必须要有意义
变量一般用名词
函数一般用动词
不能与其他关键字同名
操作符规范
操作符左右两侧各保留个空格
单行注释//后加一个空格再写注释
末尾大括号要对齐其父元素
JS嵌入HTML
行内式
放置在 HTML 事件处理程序中
1  | <input type="button" value="点我" onclick="alert('Hello World!')">  | 
注意:
可以将单行或少量JS代码写在HTML标签的事件属性中(以 on 开头的属性),如: onclick
注意单双引号的使用: 在 HTML 中我们推荐使用双引号,JS 中使用单引号
可读性差
引号易错,易混淆
特殊情况下使用
内联式
直接写在 html 文件中,一般写在 body 标签中所有元素后面
1  | <script>  | 
外联式
放置在由标签的 src 属性指定的外部 js 文件中
1  | <script type="text/javascript" src="my.js">此处不可写代码</script>  | 
注意:
- 引用外部 js 文件的 script 标签中间不可以写代码
 - 执行顺序就是他们在文档中出现的顺序
 
指定脚本语言
1  | <meta http-equiv="Content-Script-Type" content="text/javascript">  | 
一般浏览器会假设 js 为默认脚本化语言,如果没有指定默认语言,或者想覆盖默认语言,可以使用type属性
1  | <script type="text/javascript">  | 
script标记的属性
defer、async
脚本的执行在默认情况下是同步和阻塞的。但是如果有了属性 defer 或者 async,情况会发生变化。
defer作用: 浏览器解析遇到带有 defer 属性的 script 标记时,延迟该脚本的执行。文档的载入和解析完成再继续执行async作用: 浏览器可以尽快执行脚本,不用在下载脚本时阻塞文档解析。即一边下载 js 一边解析文档,js如果两者同时都有,那么会遵从 async 而忽略 defer
JS输入输出语句
alert(msg): 浏览器弹出警示框console.log(msg): 浏览器控制台打印输出信息prompt(info): 浏览器弹出输入框,用户可以输入,输入的是字符串confirm(msg): 浏览器弹出确认框,点击确认返回 true,否则返回 false
1  | // 这是一个输入框  | 
注意: confirm、prompt、alert 都会产生阻塞,但他们弹出时,代码会停止运行。
JS变量
声明和初始化
声明变量
1  | //声明变量(var=variable)  | 
赋值
1  | // = 表示把右边的值赋予左边的值  | 
变量的初始化
1  | var age=10;  | 
变量语法扩展
1  | var myname='卓越科技-';  | 
变量值只取就近一个
声明多个变量
1  | var age=18, address='火影村', gz=2000;  | 
声明变量的特殊情况
1  | // 1.只声明不赋值 结果为undefined  | 
变量命名规范
由字母数字下划线美元符号构成,不能有横杠!!!
区分大小写
不能数字开头
不能是关键字、保留字
变量名必须有意义
遵守驼峰命名法
对于内部使用的函数变量可以用下划线开头结尾的格式命名
作用域
变量起作用的范围,可以提高程序的可靠性,减少命名冲突
作用域类型
全局作用域: 整个 script 标签内 或是一个单独的 js 文件
局部作用域: 在函数内部,代码名字只在函数内部起效果和作用
全局变量和局部变量
根据作用域的不同,变量可分为: 1.全局变量 2.局部变量
全局变量: 在全局起作用的变量
局部变量: 在局部作用域下的变量(函数内部的变量)函数形参亦可以看做局部变量
从执行效率看
全局变量只有浏览器关闭时才会销毁,比较占内存资源
局部变量在程序执行完毕时即销毁
现阶段 js 没有块级作用域(即花括号包含之内): 函数中声明的所有变量,无论是在那里声明在整个函数中都是有定义的,因为变量提升的原因
全局对象和调用对象
全局对象: 当 js 解释器开始运行时,它首先要做的是在执行任何 js 代码前创建一个全局对象,而全局变量就是这个全局对象的属性。在客户端 JS(嵌入网页的JS)中,这个全局对象就是 Window 对象调用对象: 每调用一次函数时,会在该函数作用域链前加一个调用对象。函数的参数和局部变量是作为调用对象的属性而存储的。用一个完全独立的对象来存储局部变量使 JS 可以防止局部变量覆盖同名的全局变量的值
作用域链
为一个对象列表或对象链。在一个
非嵌套函数中,作用域链由这个函数的调用对象和全局对象组成
内部函数访问外部函数的变量,采取的是链式查找的方式根据就近原则来决定取那个值
1
2
3
4
5
6
7
8
9var num = 10;
function fn(){
var num = 20;
function fun(){
console.log(num);
}
fun();
}
fn(); // 结果是20
垃圾回收
JavaScript 每次创建字符串数组或对象时,解释器都必须f分配内存储存实体
与C、C++不同,js 有垃圾收集的机制,解释器可以检测何时程序不再使用一个对象,当确定了对象是无用的时候,会自动释放其占用的内存
数据类型(占用内存大小不同)
js 是一种弱类型或者说动态语言,不用提前声明变量的类型,在程序运行过程中,类型会自动被确定,js 的变量数据类型只有被赋值后才被确定
相同的变量可用于不同的数据类型
简单数据类型
三种基本数据类型: 数字型、字符串型和布尔型
两种小数据类型: null、undefined
还有ES6新增: symbol
| 简单数据类型 | 说明 | 默认值 | 
|---|---|---|
| number | 数字型,包含整型值和浮点型值,如 21,0.21 | 0 | 
| boolean | 布尔型,如true、false | false | 
| string | 字符串类型,如”张三” | “” | 
| undefined | var a; 声明但没赋值 此时a = undefined | undefined | 
| null | var a = null; 声明了变量a为空值 | null | 
复杂数据类型
对象(object)、数组(array)、函数(function)、日期(Date)、正则表达式(RegExp).本质上都是对象
数字型Number
1  | var num = 10;  | 
isNaN();: 用来判断非数字 数字返回 false 非数字返回 true1
2console.log(isNaN(12)); //结果为false
console.log(isNaN('dada')); //结果为true变量.toFixed(n);: 将变量保留 n 位小数1
2var num =2.312313;
console.log(num.toFixed(3)); // 2.312
字符串型(不是对象)
语法:双引号或单引号(推荐)
嵌套: 外双内单或者外单内双
转义符(以\开头)
| 转义符 | 解释说明 | 
|---|---|
\n | 换行符,n 是 newline 的意思 | 
\\ | 斜杠 \ | 
\' | ‘ 单引号 | 
\* | “ 双引号 | 
\t | tab 缩进 | 
\b | 空格,b 是 blank 的意思 | 
字符串的length属性
用于检测字符串长度
1  | // 检测获取字符串的长度  | 
字符串拼接
多个字符串之间可以用+拼接,拼接方式为字符串+任何类型=拼接之后的新字符串
数值型和字符型之间也可以相加
口诀: 数值相加,字符相连
1  | console.log('hello' + 'world'); //结果是helloworld  | 
布尔型
布尔型有两个值: true 和 false,其中 true 表示真,false 表示假
布尔型和数字型相加时, true 为1, false 为0
undefined
如果使用了一个
并未声明的变量时,或者使用了已经声明但还没有赋值的变量时,又或者使用了一个并不存在的对象属性时,返回的就是 undefined
定义方式
1  | var str;  | 
布尔环境中,它会转为 false 。数字环境中,会被转为 NaN 。字符串环境中,转为 “undefined”
null
即不是有效的对象、数组、数字、字符串和布尔值
定义方式
1  | var b = null;  | 
布尔环境中,它会转为 false 。数字环境中,会被转为0。字符串环境中,转为 “null”
数据类型转换
转为字符型
| 方式 | 说明 | 案例 | 
|---|---|---|
toString() | 转换为字符串 | var num = 1; alert(num,toString()); | 
String()强制转换 | 转换成字符串 | var num = 1; alert(String(num)); | 
加号拼接字符串 | 和字符串拼接的结果都是字符串 | var num = 1; alert(num + “我是字符串”); | 
用法
1  | //变量.toString()  | 
toString()可加参数,用来指定转换的基数,如为2,则转为二进制,如为8,则转为八进制,默认为10
1
2
3var num = 190;
num = num.toString(2);
console.log(num); //1011110
前两种了解即可。推荐使用第三种,亦称为隐式转换
转为数字型(重点)
| 方式 | 说明 | 案例 | 
|---|---|---|
parseInt(string)函数 | 将string类型转换成整数数值型 | parselnt(‘78’); | 
parseFloat(string)函数 | 将string类型转换成浮点数数值 | parseFloat(‘78.21’); | 
Number()强制转换函数 | 将string类型转换成数值型 | Number(‘12’); | 
js 隐式转换( - * / ) | 利用算数运算隐式转换为数值型 | ‘12’ - 0 | 
重点掌握
parseInt()、parseFloat()会从字符串开始处转换和返回任何的数字,自动忽略舍去非数字部分(前提是数字开头)1
2console.log(parseInt("88 woshi"));// 88
console.log(parseInt("aa 88 woshi"));//NaNparseInt可以解析”0x”或”0X”开头的数字,也可以接受另一个参数指定要解析的数字的基数(不能解析0开头的数字,除非显性地指定所使用的基数)1
console.log(parseInt("ff",16));// 255
1
2
3
4
5
6
7
8
9
10
11
12//parseInt(变量) 只能转为整数型
var age = prompt('请输入年龄');
console.log(parseInt(age));
console.log(parseInt('3.14')); //3 取整
console.log(parseInt('120px')); //会取消px单位
// parseFloat 可以把字符型的转化为数字型 得到是小数 浮点数
console.log(parseFloat('3.14'));
// Number()
var str = '123';
console.log(Number(str));
// 隐式转换 可以利用- * / 三种符号
console.log('12' - 0);注: Number() 只对10十进制数字有效
转化为布尔型
| 方式 | 说明 | 案例 | 
|---|---|---|
Boolean()函数 | 其他类型转成布尔值 | Boolean(“true”); | 
代表空、否定的值都转化为 false,如 ‘’, 0 , null , NaN , undefined 。其他都转化为 true
1  | console.log(Boolean('')); // false  | 
运算符
浮点数运算精确度远不如整数,不能直接拿浮点数比较是否相等
表达式: 由
数字、运算符、变量组成的式子返回值: 表达式返回的值
递增递减运算符
递增运算符(++)递减运算符(–)
放在变量前面为
前置递增后面为后置递增前置递增: 先运算再取值
后置递增: 先取值再运算
单独使用时两者结果相同
比较运算符
概念: 比较运算符(关系运算符)是
两个数据进行比较时所使用的运算符,比较运算后,会返回一个布尔值true/false作为比较运算的结果。
| 运算符名称 | 说明 | 案例 | 结果 | 
|---|---|---|---|
< | 小于号 | 1 < 2 | true | 
> | 大于号 | 1 > 2 | false | 
>= | 大于等于号(大于或者等于) | 2 >= 2 | true | 
<= | 小于等于号(小于或者等于) | 3 <= 2 | false | 
== | 判等号(会转型) | 37 == 37 | true | 
!= | 不等号 | 37 != 37 | false | 
=== !=== | 全等 要求值和 数据类型都要一直 | 37 === ‘37’ | false | 
= 赋值
== 判断(会转型)
===全等(不转型,即判断数据类型和值是否全部相等,对于对象数组函数来说则是判断是否引用同一个地址的对象数组函数)
instanceof运算符
instanceof 运算符(判断对象类型)
instance: 实例
用于判断是否是某种特殊对象(数组、对象、日期)的实例
要求左边是对象,右边是一个类的名字
1  | var d = new Date();  | 
注: instanceof是通过原型对象来判断一个实例属不属于某个构造函数创建的,而不是通过构造函数的名字
利用typeof获取变量数据类型
typeof 获取变量数据类型(判断基本类型)
- 语法: typeof 变量
 
返回的是字符类型的小写的数据类型名称
undefinedstringnumberfunctionboolean,对于包装对象和 DOM 获得的元素返回的都是object对象, null 和 数组返回的是 object
1  | var num = 10;  | 
逻辑运算符
| 运算符 | 含义 | 
|---|---|
| && | 与 | 
| || | 或 | 
| ! | 非 | 
如果是布尔值参与逻辑运算,则结果为布尔值
如果是
具体数值或表达式参与运算,则发生逻辑中断,其中具体数值代表真,0 '' null undefined NaN代表假短路运算原理: 当有多个表达式时,左边的表达式可以确定结果时,就不再运算右边的表达式的值
表达式1 && 表达式2
如果第一个为真,不足以确定结果,那么就返回表达式2
如果第一个为假,足以确定结果,那么就返回表达式1
1
2console.log(0 && 456); //结果为0
console.log(123 && 456); //结果为456
表达式1 || 表达式2
如果第一个为真,足以确定结果,那么就返回表达式1
如果第一个为假,不足以确定结果,那么就返回表达式2
1
2
3
4
5console.log( 123 || null ); //结果为123
console.log( undefined || 456); //结果为456
var num = 0;
console.log( 123 || 456); //结果123
console.log(num); //结果为0
赋值运算符
= 赋值 后面赋值给前面
+= x 每次加x num += 5; num = num + 5
-= x 每年减x num -= 5 ; num = num - 5
*= x 每次乘x
/= x 每次除x
%= x 每次除x取余
运算符优先级
小括号
一元运算符
++--!算术运算符 先 * / % 再 + -
关系运算符
相等运算符
逻辑运算符 先 && 后 ||
赋值运算符 =
逗号运算符 ,
语句
三种结构
顺序结构
按照代码先后顺序,依次执行
分支结构
根据不同的条件,执行不同的路径代码 (if while)
if分支语句
语法:
1
2
3if(条件表达式){
执行语句;
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15if(){
}
else {
}
if(){
} else if {
} else if {
} else{
} //先判断第一个 不符合则判断下一个如果条件表达式结果为真,则执行大括号里面的执行语句
如果条件表达式为假,则跳过if执行后面的代码
三元表达式(由三元运算符
? :组成的表达式)
语法结构
1
条件表达式 ? 表达式1:表达式2
如果条件表达式结果为真,则返回表达式1的值,如果为假则返回表达式2
switch语句
1  | switch(表达式){  | 
匹配 case 的值,如果匹配,则运行该 case 里的值,如果都不匹配,则执行 default 里的值
表达式里的值和 case 里的值相等是用全等 === 判定的,即必须是值和数据类型完全一致才可以
必须要有 break,否则会执行下一个 case
if else if 和switch的区别
前者一般用判断范围 后者一般用于确定值
前者需要判断多次,后者进行判断后直接执行到程序的条件语句,效率较高
分支较少时前者效率高
分支多时后者效率高且结构更清晰
循环结构
可重复执行一些代码
for循环结构
1  | for(初始化变量;条件表达式;操作表达式){ 循环体;}  | 
while循环结构
1  | while(){}  | 
- 记得加入计数器,防止死循环
 
do{} while()循环
1  | do{} while()  | 
先执行一次语句,再判断,若正确,则继续执行,否则退出
即循环体至少执行一次
总结: 一般若与数字相关,常用 for、while 和 dowhile 可以执行更加复杂的循环。while 先判断再执行,dowhile 先执行再判断
跳转语句 continue
1  | continue;  | 
遇到continue就停止本次循环,直接跳到i++,不再执行循环体内continue后面语句
1
2
3
4
5
6
7
8
9
10
11
12
13for (var i =1;i<=5;i++){
if (i==3){
continue;
}
console.log('我正在吃第'+i+'个包子');
}
/*
结果:
我正在吃第1个包子
我正在吃第2个包子
我正在吃第4个包子
我正在吃第5个包子
*/
结束语句 break
1  | break;  | 
遇到 break 直接跳出此循环所属的 for 语句的所有循环
1
2
3
4
5
6
7
8
9
10
11for(var i=1;i<=5;i++){
if(i==3){
break;
}
console.log('我正在吃第'+i+'个包子')
}
/*
结果:
我正在吃第1个包子
我正在吃第2个包子
*/
throw
用于抛出异常,用信号通知发生了错误或者异常状况
异常: 发生了某种异常情况或错误时产生的一个信号。
语法格式:
1
throw expression;
expression 可以使任意类型,一般为 Error 对象
1
2
3
4
5function twoArg(o,t){
if(arguments.length !== 2)
throw new Error('必须是两个参数');
}
twoArg(1);注意:当抛出异常时,JS 解释器会停止当前正在执行的逻辑,跳转到最近的异常处理程序(即后面 try/catch/finally 中 catch 语句编写的程序)
常见的几个错误异常
- SyntaxError:语法错误
 - Uncaught RefenetceError:引用错误 
引用一个不存在的变量时发生的错误。将一个值分配给无法分配的对象,比如对函数的运行结果或者函数赋值。 - RangeError:范围错误 
RangeError是当一个只超出有效范围时发生的错误。主要的有几种情况,第一是数组长度为负数,第二是Number对象的方法参数超出范围,以及函数堆栈超过最大值。 - TypeError类型错误 
变量或参数不是预期类型时发生的错误。比如使用new字符串、布尔值等原始类型和调用对象不存在的方法就会抛出这种错误,因为new命令的参数应该是一个构造函数。 - URIError,URL错误 
URI相关参数不正确时抛出的错误,主要涉及encodeURI、decodeURI()、encodeURIComponent()、decodeURIComponent()、escape()和unescape()六个函数try/catch/finally
 
try用于检查抛出异常catch用于抓住异常,其参数便是 try 抛出的值finally内的代码无论如何总会执行1
2
3
4
5
6
7
8
9
10try {
var n = prompt('enter a number');
// var t = prompt('enter a number');
if(n == 1){
throw 'wocao';
}
}
catch(e){
alert(e);//wocao
}
注意:
try 后面至少要跟随一个 catch 或者 finally
catch 的参数有局部作用域,只在 catch 语句中有效
如果没有 catch 从句,执行 finally 后会向上传播异常,直到找到能处理这个异常的 catch 从句
小知识: 断点调试
浏览器中按F12 --> sources --> 找到需要要调试的文件 --> 在程序的某一行设置断点Wath: 监视,通过watch可以监视变量的值的变化 ,非常的常用。F11: 程序单步执行,让程序行一行的执行,这个时候,观赛watch中变量的值的变化。- 代码调试的能力非常重要,只有学会了代码调试,才能学会自己解决bug的能力。初学者不要觉得调试代码麻烦就不去调试,知识点花点功夫肯定学的会,但是代码调试这个东西,自己不去练,永远都学不会。
 - 代码调试非常的简单,只要记住代码调试的这几个按钮的作用即可,后面还会学到很多的代的调试技巧。
 
数组
一组数据的集合
创建方式
利用 new 关键字创建数组
1
var arr = new Array();
利用数组字面量创建数组
1
2
3var arr = ['a','b','c','d','e'];
var arr = [1,2,'dada',true];
var arr=[];注意
数组里面可以放任何数据类型
数组里面的数据称为数组元素
数组的索引
索引: 用来访问数组元素的序号(
从0开始,最大为2^32 - 1)数组的长度是元素个数,不要跟索引号混淆
数组的遍历
遍历: 就是把数组中的所有元素从头到尾访问一次;
数组名.length: 动态监测数组元素的个数,一般循环遍历时长度都用这个来表示1
2
3for(i = 0;i < date.length;i++){
alert(date[i]);
}
数组元素增加
通过修改 length 新增数组元素
先修改数组长度,再对新增元素赋值
若修改后的长度 < 原先的长度,则原数组会被截取。若修改后的长度 > 原先的长度,则原数组会添加多余个数的 undefined
1
2
3arr.length = 5;
arr[3] = 4;
arr[4] = 5;通过修改数组索引的方式增加数组元素
直接对未赋值的数组元素赋值,若赋值的索引号已被占用,则会被替换为新的元素值
1
2var arr = [1, 2, 3];
arr[3] = 4;注意: 不要对数组名直接赋值,否则会清除所有数组元素
函数
封装了一段可被重复调用执行的代码块,通过函数可以实现大量代码的重复使用
函数使用步骤
声明函数
声明方式1:
1
2
3function 函数名(参数1,参数2,...){
函数体;
}注意 :
function 为声明函数的关键字,全部小写
函数名一般为动词,代表此函数要做什么
函数声明后被调用才能执行,不调用不执行
函数声明一般出现在 js 代码的顶层,也可以嵌套在其他函数中,但是只能嵌套在那些函数顶层中,不能出现在 if , while 或其他语句中
使用可选参数设计函数时,应该确保把可选的参数放参数列表的末尾
1
2
3function sayHi(){
alert('hi');
}声明方式 2 :
var 变量名 = function(参数1,参数2,...){}; (匿名函数)1
2
3var fun = function(){
console.log('Hello World!');
}函数调用
函数名();1
sayHi();
或者
变量名(); 针对第二种声明方式1
fun();
注意:
- 调用函数时一定记得写
小括号 
- 调用函数时一定记得写
 
函数的参数
| 参数 | 说明 | 
|---|---|
形参 | 形式上的参数 函数定义的适合 传递的参数 当前并不知道是什么 | 
实参 | 实际上的参数 函数调用的时候传递的参数 实参是传递给形参的 | 
多个参数之间逗号隔开
如果实参个数多于形参个数,会取到形参的个数
如果实参个数小于形参的个数,没有赋值的形参则为 undefined ,结果为 NaN
调用数组时直接写数组名字或者整个数组元素即可
函数返回值
函数只是实现某种功能,最终结果需要 return 返回数值, return 只能返回一个值
函数如果没有 return,返回的是 undefined
return 也有终止函数的功能
可以利用数组实现返回多个值
1
2
3
4
5function getResult(num1,num2){
return [num1 + num2, num1 - num2,num1 * num2, num1 / num2];
}
var re = getResult(1,2);
console.log(re);
arguments的使用
存储函数传递的所有实参
arguments 是 Arguments对象的实例,是当前函数的一个内置对象,所有函数都内置了一个 arguments 对象, arguments 只能在函数中调用,可以按照数目获取函数的实参的参数值(调用函数时写的参数而不是定义函数时写的形参),当不确定有多少个参数传递的时候,可以用 arguments 来获取。
1  | function fn(){  | 
arguments 是一个伪数组,可以进行遍历,特点如下:
具有 length 属性
按索引方式储存数据
不具有数组的
push、pop等方法
arguments的属性
arguments.callee: 返回 arguments 所在的函数
1  | function whoIsCalling(){  | 
该属性可用来实现回调
小知识
在 JS 中,代码可以对函数进行操作。JS 中的函数是真正的数据,可以被存储在变量中、数组和对象中,可以作为参数传递给其他函数
函数的属性方法
函数.length: 返回函数定义时形参的个数
1  | function f(x,y){  | 
JS的预解析(小难点,看案例)
js引擎运行分两步
预解析:
js 引擎会把 js 里面所有的 var 和 function 提升到当前作用域最前面代码执行: 按书写顺序依次执行代码
预解析分为
变量预解析(变量提升): 把 var 提升到当前作用域的最前面,但不赋值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23function fun(){
console.log(num);
}
fun();
var num = 10;
等价于
var num;
function fun(){
console.log(num);
}
fun();
num = 10;
fn();
var fn=function(){
console.log(11);
}
等价于
var fn;
fn();
fn = function(){
console.log(11);
}函数预解析(函数提升): 把所有函数声明提升到当前作用域最前面,但不调用函数
1
2
3
4
5
6
7
8
9con();
function con(){
console.log(11);
}
等价于
function con(){
console.log(11);
}
con();注意:
var a = b = c = 9;预解析后等于var a;a = 9;b = 9;c = 9;b和c变成全局变量
JS的对象
对象
一组无序的相关属性和方法的集合,所有的事物 都是对象,除了字符串、数字、true、false、null 和 undefined 其他都是对象(事实上字符串数字布尔值可以被包装为包装对象)
对象由属性和方法构成
属性: 事物的特征,在对象中用属性来表示(常用名词),属性值可以是任意的js表达式,等同于变量。
属性两种类型:
自有属性: 直接在对象中定义的属性
继承属性: 通过原型对象继承的属性
属性的三个特性:
值(value): 属性的值可写(writable): 表明是否可以设置该属性的值可枚举(enumerable): 表示是否可以通过 for/in 循环返回该属性可配置(configurable): 表明是否可以删除或者修改该属性方法: 事物的行为,在对象中用方法来表示(常用动词),即存储在对象中的函数
对象有三种
自定义对象
内置对象
宿主对象 (前两者属于 ECMAscript ,后者属于客户端 JavaScript)
创建对象
用字面量创建对象
var 对象名 = { 属性名: '属性值', 属性名: '属性值', 。。。}1
2
3
4
5
6
7
8var obj = {
uname: 'zykj',
age: 18,
sex: '男',
sayHi: function(){
console.log('Hi');
}
}调用对象
对象名.属性名对象名['属性名'](即作为关联数组的对象,允许动态地将任意数值和任意字符串关联在一起)1
2
3console.log(obj.uname);
//第二种方法 对象名['属性名']
console.log(obj['age']);
变量、属性、函数、方法的区别
变量和属性都是用来存储数据,但变量需要声明属性不需要,变量可以直接写变量名调用,属性必须
对象名.属性名调用,变量和属性基本等同函数和方法都是实现某种功能。函数是单独声明且调用时是写
函数名()。方法在对象里声明且调用为对象.方法(),对象中的函数即为方法
用 new Object 创建对象
利用等号对属性进行赋值
1
2
3
4
5
6
7var obj = new Object();
obj.uname = 'zykj';
obj.age = 18;
obj.sex = '男';
obj.sayHi = function(){
console.log('Hi');
}调用对象
1
2
3console.log(obj.uname);
console.log(obj.sex);
obj.sayHi();利用构造函数构造多个对象
构造函数: 就是把对象里面一些相同的属性和方法抽出封装起来的函数,即构造对象的函数1
2
3
4function 构造函数名(形参){
this.属性 = 值;
this.方法 = function(){}
}var 对象名 = new 构造函数名(实参);1
2
3
4
5
6function Star(uname,age,sex){
this.name = uname;
this.age = age;
this.sex = sex;
}
var zykj = new Star('zykj',18,'male');注意点以及构造函数执行过程:
构造函数名字首字母一般大写
构造函数不需要 return
调用构造函数 必须使用 new 构造函数在内存中创建了一个空的对象
必须使用 this , this 指向 new 创建的空对象
执行构造函数的代码后,就会给这个空对象添加属性和方法
new 会返回创建后的对象
遍历对象
语法: for(变量 in 对象){} 该方法会
枚举所有可枚举的属性,包括自有属性和继承属性(除非利用 Object.defineProperty() 人为设定
1  | for(var k in obj){  | 
注意:
k 可以改为任意变量名,一般用 k
k 为数组
也可以用于数组!!!
该方法会枚举所有可枚举的属性,包括自有属性和继承属性(除非利用 Object.defineProperty() 人为设定为不可枚举)
许多预定义内部属性和方法,包括所有的内部方法都是不可枚举的
删除属性
语法: delete 属性
删除运算数指定的对象的属性、数组元素或变量(严格模式不可删除)。返回布尔值
内部核心属性、客户端属性、用 var 语句声明的用户定义变量都不能删除
1  | var obj = {  | 
注意:
delete: 只是断开属性和宿主对象的联系,而不会去操作属性中的属性
检查属性的存在性
检测对象或数组中是否有某个属性,返回布尔值
语法: 属性名 in 对象或数组
1
2
3
4
5var obj = {
num: 10,
age: 20
}
console.log("num" in obj); //true注意: 该方法可以检测所有的属性方法,包括自定义类内置的和原型链上的以及原始类的属性方法
只能检测对象的自有属性
语法:
对象.hasOwnProperty(属性名)返回布尔值1
2
3
4
5
6
7
8function Star(){
this.name = 1
}
Star.prototype.age = 12;
Object.prototype.male = 'man';
var zykj = new Star();
console.log(zykj.hasOwnProperty('name'));//true
console.log(zykj.hasOwnProperty('male'));//false
确定对象类型
typeof: 用于区分 number、string、boolean、undefined、function、symbol 这些基本类型instanceof: 一旦确定了一个值不是基本类型或函数,就可以用 instanceof 来确定是哪种内建对象的实例,对于基本类型包装对象无效Object.toString(): 返回的是[object class], class 是对象的内部类型,通常与该对象的构造函数名字对应。只能返回 Array、Function、Date、String、Number、Boolean、Symbol,其他一律返回 Objectconstructor:返回原型对象所属的类,返回的是整个构造函数
序列化对象
将对象的状态转为字符串或将字符串还原为对象
利用JSON.stringify()和JSON.parse()来序列化和还原对象
JSON(JavaScript Object Notation): JavaScript 对象表示法
内置对象
常用 Math Date Array String 等
数学对象
不是构造函数,无需用 new 调用。而是可以直接调用其类属性及类方法
调用属性 如 输出pi值:
Math.PI1
console.log(Math.PI); // 3.14....
调用方法 如 取最大值:
Math.max1
console.log(Math.max(1,2,3)); // 3
如果有一个或一个以上的值为非整数型,则返回 NaN
如果没有赋值,则返回 Infinity
求开根号
Math.sqrt(x)返回 x 的开根号值1
2var x = Math.sqrt(81);
console.log(x);求绝对值
Math.abs1
2
3
4console.log(Math.abs(1)); //1
console.log(Math.abs(-1)); // 1
console.log(Math.abs('-1')); // 1 有隐式转换 可以直接字符串转为数字型
console.log(Math.abs('哈哈')); // NaN三个取整方法
Math.floor(): 向下取整,往最小了取值,不会四舍五入1
2console.log(Math.floor(1.1)); // 1
console.log(Math.floor(1.9)); // 1Math.ceil(): 往上取整,往最大了取,不会四舍五入1
console.log(Math.ceil(1.9)); // 2 console.log(Math.ceil(1.1)); // 2
Math.round(): 四舍五入取整(其他都是四舍五入,只有5是往大了取)1
2
3console.log(Math.round(1.1)); // 1
console.log(Math.round(1.9)); // 2
console.log(Math.round(-1.5)); // -1
随机数
Math.random(): 返回一个随机的0到1之间的小数(不包含0和1)且不跟参数得到两个整数之间的随机整数:
1
2
3function getRandom(min,max){
console.log(Math.floor(Math.random()*(max-min+1)+min));
}
日期对象
Date() 日期对象 是一个构造函数 必须使用 new 来调用创建自己的日期对象
使用方法
1
2var date = new Date();
console.log(date);参数写法
无参数则返回当前系统时间
数字型: 2019,10,01
字符型: ‘2019-10-1 08:08:08’1
2
3var date1 = new Date(2019,10,1);
or
var date2 = new Date('2019-10-1 08:08:08');具体方法
返回当前年份1
对象名.getFullYear()
返回当前月份1
对象名.getMonth()+1
注意:
是从0开始到11 所以应该+1 否则得到的月份少一个月返回当前号数1
对象名.getDate()
返回周几1
对象名.getDay()
注意:
是从0(即星期日)开始到6(星期六)返回小时1
对象名.getHours();
返回分钟1
对象名.getMinutes()
返回秒钟1
对象名.getSeconds()
返回自1970年来的总毫秒数对象名.getvalueOf()或者对象名.getTime()var 对象名 = new Date();
console.log(Date.now());//低版本浏览器不支持
获取时间1
2
3
4
5
6
7
8
9
10
11
12
13
14
15function countDown(time) {
var nowTime = +new Date(); // 返回的是当前时间总的毫秒数
var inputTime = +new Date(time); //返回的是用户输入时间的总毫秒数
var times = (inputTime - nowTime) / 1000; // times是剩余时间总的毫秒数
var d = parseInt(times / 60 / 60 / 24); // 天
d = d < 10 ? '0' + d : d;
var h = parseInt(times / 60 / 60 % 24); // 时
h = h < 10 ? '0' + h : h;
var m = parseInt(times / 60 % 60); // 分
m = m < 10 ? '0' + m : m;
var s = parseInt(times % 60); // 当前的秒
s = s < 10 ? '0' + s : s;
return d + '天' + h + '时' + m + '分' + s + '秒';
}
console.log(countDown('2020-5-13 17:29:00'))
数组对象
创建方式
利用字面量
1
2var arr = [1,2,3];
console.log(arr[0]);利用
new Array()1
2
3var arr1 = new Array(); // 空数组
var arr2 = new Array(2); // 长度为2的空数组
var arr3 = new Array(2,3);// 内容为2和3的数组
检测变量是否为数组的方法
利用
instanceof变量名 instanceof Array
返回的是布尔值
1
2
3
4var arr = [];
var obj = {};
console.log(arr instanceof Array); // 返回true
console.log(arr instanceof Array); // 返回false注: 亦可用来判断是否为对象类型 : 变量名 instanceof Object
利用Array内置对象的行为
Array.isArray(变量)返回的也是布尔值
1
2Array.isArray([1,2,3]); // TRUE
Array.isArray(1,2,3); // FALSE
给数组添加元素的方法
末尾添加
数组名.push(元素1,元素2,...);1
2var arr = [1,2,3];
arr.push(1,'dada'); // 返回结果是数组长度头部添加
数组名.unshift(元素1,元素2,...);1
2var arr = [1,2,3];
arr.unshift('red','purple'); // 返回结果是数组长度尾部删除
数组名.pop()1
arr.pop(); //pop没有参数 返回删除的元素 一次只能删除一个元素
头部删除
数组名.shift()1
arr.shift()//没有参数 返回删除的元素 一次只能删除一个
总结
方法名 说明 返回值 push(参数1...)末尾添加一个或多个元素,注意修改原数组返回新的长度 pop()删除数组最后一个元素,把数组长度减1 无参数、修改原数组返回它删除元素的值 unshift(参数1...)向数组的开头添加一个或更多元素,注意修改原数组返回新的长度 shift()删除数组的第一个元素,数组长度减1 无参数。修改数组返回第一个元素 数组排序的方法
数组翻转
数组名.reverse();1
2
3var arr = [1,2,3];
arr.reverse();
console.log(arr);数组排序
数组名.sort();: 只对一位数起效,多位数会出错数组名.sort(function(a,b){ a - b}): 升序排序数组名.sort(function(a,b){ b - a}): 降序排序1
2
3
4
5var arr1 = [3,4,8,12];
arr1.sort(function(a,b){
// return a - b; 升序排列
return b - a;
});
获取数组元素索引方式
变量名.indexOf(元素值);1
2var arr = ['red','green','pink','blue'];
console.log(arr.indexOf('blue'));注: 返回第一个满足条件的索引号
如果该数组里找不到元素,则返回-1
变量名.lastIndexOf(元素值);注: 从末尾开始找 返回正序的索引号
1
console.log(arr.lastIndexOf('blue'))
注: 只能用于数组,不能用于节点
数组转为字符串
变量名.toString();1
2var arr = [1,2,3];
console.log(arr.toString());变量名.join();把数组所有元素转换成字符串,再把它们连接起来。可以指定一个可选的字符串来分隔结果字符串中的元素。默认为逗号分隔
1
2
3var arr1 = ['green','blue','pink'];
console.log(arr1.join()); //green,blue,pink
console.log(arr1.join('')); //greenbluepink
数组的截取删除连接
数组链接
数组名1.concat(数组名2);数组名1.concat(元素值,元素值,...);1
2
3
4var num1 = [1,2,3];
var num2 = ['a','b','c'];
console.log(num1.concat(num2));
console.log(num1.concat(num2,1,[2,3]));数组删除插入(改变原数组,返回被删除的值)
数组名.splice(起始位置,删除个数,添加元素)1
2
3
4
5
6var num3 = ['ha','xi','hei','he'];
var num4 = num3.splice(1,0,'en'); // 在第1位后插入'en'
var num5 = num3.splice(1,1); //第1位开始删除一位
console.log(num5); // 'xi'
var num6 = num3.splice(2,1,'en','o');
console.log(num3); // 'ha' 'xi' 'en' 'o' 'he'数组截取(不会改变原数组,只是截取出来作为新数组)
数组名.slice(开始位置(包含),结束位置(不包含));1
2
3
4var num7 = [1,2,3,4,5,6];
console.log(num7.slice(2)); // 3,4,5,6
console.log(num7.slice(1,3));// 2,3
// num7依旧为1,2,3,4,5,6
字符串对象
基本包装类型: js 不仅支持数字字符串和布尔值这些数据类型,还支持 Number、String、Boolean 类,这些类是其对应基本数据类型的包装。不仅具有和基本类型一样的值,还定义了用来运算数据的属性和方法
过程:
字符串值内部创建一个String包装对象
1
var temp = new String(字符串值)
代替原始的字符串值
1
变量名 = temp;
销毁temp
1
temp = null;
字符串不可变性: 字符串赋值后重新赋值需要重新创建内存空间,原先的内存及其值不变。所以不要大量拼接字符串,即字符串的值无法修改
字符串所有方法,都不会修改字符串本身内容,而是创建新的字符串
实例方法
根据字符串返回索引值
字符串名.indexOf(具体某个字符串,开始位置(默认无));1
2
3var str ='改革春风吹满地,春天来了';
console.log(str.indexOf('春')); // 返回2
console.log(str.indexOf('春',3)); // 返回8根据索引值返回字符串
字符串变量名.charAt(索引值)1
2
3var str='1234';
var a = str.charAt(1);
console.log(a); // 2字符串变量名.charCodeAt(索引值): 返回对应位置字符的ASCII码 用于判断用户按键1
console.log(str.charCodeAt(0));
变量名[索引值]1
console.log(str[1]);
字符串连接
字符串1.concat(字符串2);字符串1.concat(字符,字符,...);一般用加号
字符串截取
字符串.substr(截取起始位置,截取的字符数): 不改变原字符串1
2var str = '改革春风吹满地';
console.log(str.substr(2,2));字符串替换
字符串.replace('被替换的字符','替换为的字符')返回的是新修改后的字符串,原字符不变
1
2
3
4
5
6var str = 'andy';
console.log(str.replace('y','d')); // 有一个字符串'abcoefoxyozzopp' 要求把所有o替换为*
var str1 = 'abcoefoxyozzopp';
for(i = 0;i < str1.length;i++){
str1 = str1.replace('o','*');
}字符串转为数组
字符串.split('分隔符')原字符串用什么分割,就用什么做分隔符 不改变原字符串
1
2
3
4var str1 = 'red,pink,blue';
console.log(str1.split(','));
var str3 = 'red&pink&blue';
console.log(str3.split('&'));字符串大小写转换
字符串.toUpperCase(): 将字符串转为大写字符串.toLowerCase(): 将字符串转为大写注: 字符串大小比较是按对应字母一个一个比
去除字符串左右的空格
字符串.trim()可用来去除表单只填入空格时造成的 bug
类方法
根据 ASCII码 返回字符串
String.fromCharCode(num1, ..., numN)1
console.log(String.fromCharCode(78)); //N
返回在指定的位置的字符的 Unicode 编码。
String.charCodeAt(index)index表示字符串中某个位置的数字,即字符在字符串中的下标1
2var str = "Hello world!"
console.loge(str.charCodeAt(1)) // 101
简单和复杂数据类型
简单数据类型
简单数据类型(基本数据类型或值类型),存储时变量中存放的是值本身,因此叫值类型,如 number、boolean、undefined、null。都具有固定的内存大小
其中 null 的返回类型是 Object ,因此一般可先用来定义对象
1  | var timer = null;  | 
如果有个变量打算存储为对象但没想好放什么属性和行为,那么就可以先设置为 null 类型
复杂数据类型
复杂数据类型(引用类型): 变量中存储的仅仅是地址,如对象及其特殊类型数组和函数
其中字符串不能很好地适合基本类型和引用类型的二分法。因为字符串不是对象,被当做基本类型,而字符串又有任意的长度,所以也可以被认为是引用类型。字符串是通过传值来比较
堆和栈
栈: 存放简单数据类型,由操作系统自动分配释放存放函数的参数值、局部变量的值等。简单数据类型直接查找存放在栈中的变量的值(简单数据 > 栈 > 变量 > 值)
堆: 存放复杂数据类型,一般由程序员分配释放。复杂数据类型通过存放在栈中的变量中的地址找到存放在堆中的值(复杂数据>栈>变量>地址>堆>值)
简单数据类型的传参(传值)
函数的形参可以看做一个变量,当把一个变量传给函数形参就等于把变量的值复制一份给形参。所以对函数内变量的修改不会影响外部变量
复杂数据类型的传参(传址)
函数的形参可以看做一个变量,当把一个变量传给函数形参就等于把变量存放的堆地址复制一份给形参,即形参和实参保存的是同个堆地址,所以操作的是同一个对象。
Web APIs
本教程里的资料来源于网友的资料,自己整理以供学习。视频学习: 黑马程序员
DOM:文档对象模型(document object model)
BOM: 浏览器对象模型
API(application programming interafce,应用程序编程接口): 是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节Web API: 浏览器提供的一套操作浏览器功能和页面元素的 API
可以将 Web 浏览器当做简单操作系统,就可以 web 应用定义为 JavaScript 访问更多浏览器提供的高级服务的Web页面
文档中的 JavaScript 的角色定位: 增强用户浏览体验,使信息的获取和传递更容易。而不是降低网页的可访问性。
DOM
文档对象模型(document object model),处理 HTML 或者 XML 的标准编程接口,通过DOM可以改变网页的内容、结构和样式
文档: 一个
页面就是一个文档,DOM中用document表示元素:
页面中所有标签都是元素,DOM用element表示节点: 网页中所有内容都是节点(标签属性文本注释等),DOM中用
node表示
DOM把以上内容都看作是对象
获取页面元素
根据ID获取
根据标签名获取
根据h5新增属性获取
特殊元素获取
根据 window 属性获取(不推荐)
利用 HTMLCollection (HTML集合)快捷获取
根据ID获取
document.getElementById(ID名)1
2
3
4
5
6
7
8
9<body>
<div id="time">2019-9-9</div>
<script type="text/javascript">
var timer = document.getElementById('time');
console.log(timer); // <div id="time">2019-9-9</div>
console.log(typeof timer); // object
console.dir(timer);
</script>
</body>注意点
因为文档页面从上往下加载,所以先得有标签, script 写到标签下面
参数 id 是大小写敏感的字符串 一定要加引号
返回的是一个文档对象 object (即有众多属性和方法)
console.dir打印对象所有的属性和方法
根据标签名获取
document.getElementsByTagName(标签名)父元素.getElementsByTagName(标签名)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37<body>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
<ol>
<li>4</li>
<li>5</li>
<li>6</li>
</ol>
<ol id="ol">
<li>7</li>
<li>8</li>
<li>9</li>
</ol>
<script>
var lis = document.getElementsByTagName("li");
console.log(lis); // HTMLCollection {0: HTMLLIElement, 1: HTMLLIElement, 2: HTMLLIElement, 3: HTMLLIElement, 4: HTMLLIElement…}
console.log(lis[2]); // <li>3</li>
for(i = 0;i<lis.length;i++){
console.log(lis[i]);
}
var ol = document.getElementsByTagName("ol");
console.log(ol); // HTMLCollection {0: HTMLOListElement, 1: HTMLOListElement, constructor:
console.log(ol[0].getElementsByTagName("li")); // HTMLCollection {0: HTMLLIElement, 1: HTMLLIElement, 2: HTMLLIElement, constructor: Object}
var ol = document.getElementById('ol');
console.log(ol.getElementsByTagName('li')); // HTMLCollection {0: HTMLLIElement, 1: HTMLLIElement, 2: HTMLLIElement, constructor: Object}
</script>
</body>注意:
返回的值是伪数组,即所有相应标签的集合,即以伪数组的形式存储(无论有多少个,即使是0个),单个元素仍为对象,得到的元素是动态的
可用遍历方式打印里面具体的元素对象
通过父元素获取标签时,父元素必须是具体的单个对象,如果父元素是通过标签名获取,则获取其子元素时应加上索引号。也可以直接通过 ID 获取不加索引号
H5新增,返回的是 NodeList 对象
document.getElementsByClassName(标签名)1
2var box = document.getElementsByClassName("box");
console.log(box); // HTMLCollection {0: HTMLDivElement, constructor: Object}注意
- 返回的依旧是伪数组形式
 
document.querySelector(选择器)如(#id,.类名,标签名)返回指定选择器的
第一个元素1
2
3
4
5
6var firstbox = document.querySelector('.box');
console.log(firstbox);
var nav = document.querySelector('#nav');
console.log(nav);
var one = document.querySelector('li');
console.log(one);注意:
永远只会返回一个元素对象document.querySelectorAll(选择器)返回选定选择器的所有元素集合
1
2
3
4var allbox = document.querySelectorAll('.box');
console.log(allbox);
var lis = document.querySelectorAll('li');
console.log(lis[1]);注意: 返回的是伪数组形式(无论对象元素数量多少)
获取特殊元素
- 获取 body 元素
 
document.body1
2var bodyEle = document.body;
console.log(bodyEle);- 获取 html 元素
 
document.documenElement1
2var htmlEle = document.documentElement;
console.log(htmlEle);- 获取 head 元素
 
document.head1
console.log(document.head);
根据 window 属性获取赋予 id 、name 属性的 html 标签(不推荐)
如果HTML文档中用 id 属性为元素命名,并且 Window 对象没有该名字的属性,那么 Window 对象会创建一个同名属性,该属性指向以该名字命名 id 属性的 html 元素
1
2
3
4
5
6<body>
<div id="one"></div>
<script type="text/javascript">
console.log(window.one); // <div id="one"></div>
</script>
</body>对于 a、iframe、img、form 等标签来说,如果有 name 属性,那么也会有与上面同样的表现。如果有多个相同 name 属性,则具有该名称的隐式全局变量会引用一个伪数组对象
1
2
3
4
5<img src="" alt="" name="ii">
<img src="" alt="" name="ii">
<script type="text/javascript">
console.log(window.ii);// HTMLCollection(2) [img, img, ii: img]
</script>利用 HTMLCollection (HTML集合)快捷获取,返回的是 HTMLCollection 对象
HTMLDocument中定义了一些属性,如images、forms、links可以快速获取img、form、a等标签
1
2
3
4
5<img src="" alt="">
<img src="" alt="">
<script type="text/javascript">
console.log(document.images);//HTMLCollection(2) [img, img]
</script>
事件概述
f
可以被 javascript 侦测到的行为
事件三要素
事件源(可以通过获取对象方式获取)
事件类型(设置事件的触发方式)
事件处理程序(通过函数赋值方式完成)
1  | var btn = document.getElementById('btn');  | 
注意: 第一句为获取事件源.onclick为事件类型 function 及后面为事件处理程序
事件执行三步骤:
获取事件源
绑定事件
添加事件处理程序
常见鼠标事件
| 鼠标事件 | 触发事件 | 
|---|---|
onclick | 鼠标点击左键触发 | 
ondblclick | 鼠标双击事件 | 
onmouseover | 鼠标经过触发 | 
onmouseout | 鼠标离开触发 | 
onfocus | 获取鼠标焦点触发 | 
onblur | 失去鼠标焦点触发 | 
onmousemove | 鼠标移动触发 | 
onmouseup | 鼠标弹起触发 | 
onmousedown | 鼠标按下触发 | 
改变元素内容(不适用于表单)
innerText: 不识别 html 标签,非标准,会去除空格和换行innerHTML: 识别 html 标签,W3C 标准,不会去除空格和换行insertAdjacentHTML(位置,目标元素): 可以实现在目标元素中特定位置插入字符串
位置beforebegin:元素自身的前面。afterbegin:插入元素内部的第一个子节点之前。beforeend:插入元素内部的最后一个子节点之后。aftenetd:元素自身的后面。
注: 两个属性可读写,可以获取元素内容
1  | var p = document.querySelector('p');  | 
常用元素属性修改: src、href、title、alt、id
改变表单元素内容
input.value
1  | var btn = document.querySelector('button');  | 
注意:
表单元素更改只能用 value
disabled 实现表单禁用
函数中的 this 指向函数的调用者
这些都是属性不是样式,不用写
styleimgsrc等等
可以通过修改表单type类型实现密码明文密文的转换
改变元素对象样式
element.style.样式 = '属性值';: 一般用于样式较少或功能简单的情况下使用1
2
3
4
5
6var div = document.querySelector('div');
div.onclick = function(){
// div.style 里面的样式用驼峰命名法
this.style.backgroundColor = 'purple';
this.style.width = '400px'; // 修改后的样式为行内样式 权重比较高
}注意:
利用 js style 修改的样式都得用驼峰命名法 如
backgoroundColor、fontSizejs
修改后的样式都以行内样式生成,权重高样式的属性都是在 style 中,所以需要些
xx.style.属性
通过
element.className增加类名从而修改样式(适用于样式较多,功能复杂的情况使用)即在 css 先定义好新的样式在新的类名中,再在 js 中对目标元素设置事件利用
className更换新的类1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20<head>
<style>
.change {
background-color: purple;
color: #fff;
font-size: 25px;
margin-top: 100px;
}
</style>
</head>
<body>
<div>文本</div>
<script type="text/javascript">
var test = document.querySelector('div');
test.onclick = function(){
//将当前类名改为change 从而改变样式
this.className = 'change';
}
</script>
</body>注意:
className 会完全覆盖先前的类名若想同时保留新旧类名 则可以在添加时新旧一起写1
this.className = 'first change';
获得失去焦点
示例
1
<input type="text">
1
var input = document.querySelector("input");
获得焦点(即点击输入框时)
1
2
3input.onfocus = function(){
console.log("获得焦点");
}失去焦点(取消点击输入框时)
1
2
3input.onblur = function(){
console.log("失去焦点");
}
排他思想 (算法)
如果有同一组元素,
想要某一个元素实现某种样式,那么就需要排他思想
步骤 :
先排除其他人的样式
再设置自己的样式
1  | for( var i = 0;i < btns.length;i++){  | 
获取自定义属性
获取属性一般有两种
element.属性element.getAttribute('属性')
1
2var div = document.querySelector('div');
console.log(div.getAttribute('index'));区别
第一种用于获取
元素本身自带的属性第二种一般用于获取通过
setAttribute自定义的属性(即程序员自己定义的属性),通过setAttribute设置的属性只能用第二种获取
设置属性值的方法
element.属性 = '属性值';element.setAttribute('属性','值');
1
2var div = document.querySelector('div');
div.setAttribute('index','2');自定义属性也可以通过第一种设置,但只能用
xxx.属性名获取移除属性的方法
element.removeAttribute('属性');1
div.removeAttribute('index');
h5新增自定义属性方法
data-属性名data-开头的属性必定是自定义属性1
<div data-time="2" data-list-name='andy'></div>
获取data自定义属性方法有两种:
1
<div data-time="2" data-list-name='andy'></div>
element.getAttribute(
'data-属性名')1
2
3console.log(div.getAttribute('data-list-name'));
console.log(div.getAttribute('data-time'));
div.setAttribute('data-index',2); //设置属性值element.dataset.data后面的属性名或element.dataset['data后面的属性名']
1
2
3
4console.log(div.dataset);
console.log(div.dataset.index);
console.log(div.dataset['index']);
console.log(div.dataset['listName']);特别注意: 对于
data-后面还有横杠的命名的属性值在利用 dataset 获取时应该用驼峰命名法, getAttribute 则不用
节点
页面中所有内容都是节点,用 node 表示
节点的三个属性
节点类型(
nodeType)节点名称(
nodeName)节点值(
nodeValue)
1  | 元素节点nodeType = 1  | 
操作的主要是元素节点
节点可以划分为不同的层级关系,常见的是父子兄层级节点
父子节点操作
获取父节点
node.panettNode(获得最近的父节点,如果找不到则返回 NULL )1
2var erweima = document.querySelector('.erweima');
console.log(erweima.panettNode);获取子节点
node.childNodes: 返回的是元素节点以及文本节点node.childnet:只返回元素节点 获得的是伪数组1
console.log(ul.childnet);
获取第一个和最后一个子节点
node.firstChildnode.lastChild以上都返回包括文本节点在内的所有节点
不常用node.firstElementChildnode.lastElementChild只返回元素节点,但是有兼容性问题
实际写法
node.childnet[0] 返回第一个node.childnet[node.childnet.length-1] 返回最后一个1
2console.log(ol.childnet[0]);
console.log(ol.childnet[ol.childnet.length-1]);获取兄弟节点
node.nextSibling: 下一个兄弟节点node.previousSibling: 上一个兄弟节点以上获取的都是包含
文本节点元素节点(#text)的兄弟节点1
2
3var div = document.querySelector('div');
console.log(div.nextSibling);
console.log(div.previousSibling);node.nextElementSibling: 下一个兄弟元素节点node.previousElementSibling: 上一个兄弟元素节点以上都只获取为元素节点的兄弟节点 有兼容性问题
1
2console.log(div.nextElementSibling);
console.log(div.previousElementSibling);解决方案: 自己利用节点类型 nodeType 封装一个函数
创建节点
document.createElement(元素名称)1
var li = document.createElement('li');
添加节点(两种方法)
node.appendChild(child);: node 为父节点 child 为新创建的节点 添加到父级最后面1
2var ul = document.querySelector('ul');
ul.appendChild(li);node.insertBefore(child,指定位置): 即将新创建的child节点添加到指定元素之前1
2var lili = document.createElement('li');
ul.insertBefore(lili,ul.childnet[0]);
删除节点
node.removeChild()1
ul.removeChild(ul.childnet[0]);
克隆节点
node.cloneNode()括号里参数如果为
空或者是false,则是浅拷贝则只复制node 本身、不复制里面的子节点
括号里参数如果为true,则是深拷贝则复制node 本身、里面的子节点1
2var lili = ul.childnet[0].cloneNode(); // li
var lili = ul.childnet[0].cloneNode(true); // <li>1</li>创建文档碎片
document.createDocumentFragment()DocumentFragments是DOM节点。它们不是主DOM树的一部分。通常的用例是创建文档片段,将元素附加到文档片段,然后将文档片段附加到DOM树。在DOM树中,文档片段被其所有的子元素所代替。因为文档片段存在于内存中,并不在DOM树中,所以将子元素插入到文档片段时不会引起页面回流(对元素位置和几何上的计算)。因此,使用文档片段通常会带来更好的性能。
节点的文本内容
node.textContenttextContent 属性设置或者返回指定节点的文本内容。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20<body>
<ul id="myList">
<li id="item1">Coffee</li>
<li id="item2">哈哈哈</li>
<li id="item3">Tea</li>
</ul>
<p id="demo">单击按钮获取列表元素的文本内容</p>
<button onclick="myFunction()">点我</button>
<script>
function myFunction(){
var lst=document.getElementById("myList");
var x=document.getElementById("demo");
x.innerHTML=lst.textContent;
}
</script>
</body>
<!--
结果: Coffee哈哈哈Tea
-->
附: 阻止链接跳转可以对 a 的 href 设置为javascript:; 或 javacript:void(0)
总结
获取父节点
node.panettNode获取子节点
node.childnet获取兄弟节点
node.nextElementSiiblingnode.previousElementSibling(兼容性差)创建节点
document.createElement(节点类型)添加节点 尾部添加
node.appendChild() 某个元素之前添加node.insertBefore(child,指定元素)删除节点
node.removeChild() node为删除目标元素的父元素复制节点
node.cloneNode()
三种动态创建元素区别
document.write()element.innerHTML()配合字符串使用document.createElement()配合 append、insertbefore 使用
注意
document.wirte如果是文档流执行完毕写入,会导致页面全部重绘innerHTML创建多个元素效率更高 前提是不要拼接字符串 而是通过先创建数组再将数组转换为字符串赋予对象的形式createElement()创建多个元素效率相对 innerHTML 的数组赋值方式较低,但是结构更清晰
总结: 不同浏览器下,采取数组赋值的 innerHTML 效率比 creatElement 高
事件高级
注册事件
传统方式和监听注册方式
传统方式(最简单的方式,即将函数赋值给目标对象的事件属性,属性名字都以
"on"开头)变量名.onclick = funciton(){}特点:
唯一性,即同个元素同个事件只能设置一个处理函数,如果重复注册则以最新一个(最后一个)为准1
2
3
4var btns = document.querySelectorAll('button');
btns[0].onclick = function(){
alert('HI');
}监听注册方式(推荐 为 W3C标准 IE9 之前不支持)
变量名.addEventListener('事件触发方式',处理函数,事件流执行顺序参数(布尔值))特点: 用一个元素同一个事件可以注册多个监听器,按注册顺序依次执行
注意:
事件触发方式不能带 on ,且因为是字符串必须加引号;处理函数可以写函数名也可以写整个函数,当事件发生时,会调用该监听函数;事件流执行顺序参数可选参数,是一个布尔值,默认为 false。1
2
3btns[1].addEventListener('click',function(){
alert('22');
})attachEvent方式( IE9 之前支持 了解即可)
变量名.attachEvent(事件类型(带on),时间处理函数)1
2
3btns[2].attachEvent('onclick',function(){
alert('11');
});
在元素上写事件和 addEventListener() 的区别
onclick 添加事件不能绑定多个事件,后面绑定的会覆盖前面的。而 addEventListener 能添加多个事件绑定,按顺序执行。
addEventListener 方式,不支持低版本的 IE。( attachEvent 支持 IE )。
普通方式绑定事件后,不可以取消。addEventListener 绑定后则可以用 removeEventListener 取消。
addEventListener 是 W3C DOM 规范中提供的注册事件监听器的方法。
对于传统事件注册记得加 on ,如 onclick , onkeydown 等
删除事件
对于传统方式注册的事件
变量名.事件类型 = null1
2
3
4
5var divs = document.querySelectorAll('div');
divs[0].onclick = function(){
alert('11');
divs[0].onclick = null;
}对于监听事件注册的事件
变量名.removeEventListener(删除的事件类型,删除的函数)1
2
3
4
5divs[1].addEventListener('click',fn);
function fn(){
alert('22');
divs[1].removeEventListener('click',fn);
}对于attachEvent注册的事件(了解)
变量名.detachEvent(删除的事件类型,删除的函数)1
2
3
4
5divs[2].attachEvent('onclick',fn1);
function fn1(){
alert('33');
divs[2].detachEvent('onclick',fn1);
}
总结:
注册事件
node.onclicknode.addEventListener('事件类型',处理程序,冒泡与否值)删除事件
node.onclick = null;node.removeEventListener ('事件类型',处理程序)
事件流
页面中获取接收事件的顺序
DOM 事件流: 事件发生时会在元素节点之间按照特定顺序传播
DOM事件流有三个阶段:
捕获阶段
事件发生时在页面中从 document 往下一级一级传播的过程
当前目标阶段
事件到达设置了该事件的元素时的阶段
冒泡阶段
事件接受后从事件触发节点逐级向上传播到 DOM 最顶层节点的过程
注意:
JS 只能执行捕获或者冒泡其中一个阶段
onclick和attachEvent只能获得冒泡阶段addEventListener第三个参数如果是 true ,则为捕获阶段(很少用)。如果是 false(默认),则为冒泡阶段一些事件是没有冒泡的,如 onblur , onfocus , onmouseenter , onmouseleave
1
2
3
4
5
6
7
8
9
10//捕获阶段
var son = document.querySelector('.son');
son.addEventListener('click',function(){
alert('son');
},true)
var father = document.querySelector('.father');
father.addEventListener('click',function(){
alert('father');
},true)
// 因为是捕获阶段 所以先弹出 father 再弹出son1
2
3
4
5
6
7
8
9
10
11
12
13
14//冒泡阶段
var son = document.querySelector('.son');
son.addEventListener('click',function(){
alert('son');
},false)
var father = document.querySelector('.father');
father.addEventListener('click',function(){
alert('father');
},false)
document.addEventListener('click',function(){
alert('document');
})
//因为是冒泡,所以如果点击father,则只弹father。点击son,则先弹出son,再弹出father
事件对象
事件的一系列相关数据的集合
xxx.onclick = function(event){}
其中event就是事件对象,写到事件的处理函数小括号里,可以任意命名(一般为 e )
事件对象只有有了事件才会存在,不需要传递参数,系统自动创建
存在兼容性问题 ie678 无法识别,只能通过 window.event 获取
1  | var div = document.getElementByTagName('div');  | 
当函数参数有事件对象参数e以及自定义参数时,自定义参数应该在事件对象之前
常见事件对象的属性和方法
e.target: 返回触发事件的对象(ie678不兼容)
1  | var div = document.querySelector('div');  | 
注意:
this 和 target 的区别为
前者返回的是绑定事件的对象,后者为触发事件的对象,即点击谁之后触发了事件就返回哪个。对于 ie678 应该用
e.srcElement(了解)与 this 相似的属性是
e.curnettTarget(了解)
返回事件类型
e.type: 返回 click mouseover 等,没有on
1  | var div = document.querySelector('div');  | 
阻止默认行为(比如让链接不跳转,让提交按钮不提交)
对于监听注册事件
e.preventDefault()//只适用于高版本浏览器1
2
3
4var a = document.querySelector('a');
a.addEventListener('click',function(e){
e.preventDefault(); //dom标准写法
})对于传统注册方式
e.preventDefault()e.returnValue()适用于 ie678return false 没有兼容性问题 但是后面的代码无法执行
1
2
3
4
5
6
7
8
9var a = document.querySelector('a');
a.onclick = function(e) {
//普通浏览器 e.preventDefault(); 方法
e.preventDefault();
//低版本浏览器 ie678 returnValue 属性
e.returnValue;
//return false 没有兼容性问题 但是后面的代码无法执行
return false;
}
阻止冒泡
e.stopPropagation(); // ie678不兼容阻止当前对象执行事件后向上冒泡
1
2
3
4
5var son = document.querySelector('.son');
son.addEventListener('click',function(e){
alert('son');
e.stopPropagation();
},false)e.cancelBubble = true; //ie678兼容写法(了解)1
2
3
4
5var son = document.querySelector('.son');
son.addEventListener('click',function(e){
alert('son');
e.cancelBubble = true; //ie678兼容写法
},false)
总结
e.target: 返回触发了事件的对象e.type: 返回事件类型e.preventDefault(): 阻止默认行为e.stopPropagation(): 阻止当前冒泡
事件委托
1  | <ul>  | 
事件调用顺序
- 通过设置对象属性或 HTML 属性注册的处理程序一直优先调用
 - 使用 
addEventListener()注册的处理程序按照它们的注册顺序调用 - 使用 
attachEvent()注册的处理程序可能按照任何顺序调用,所以代码不应该依赖于调用顺序 
常用鼠标事件
禁止右键菜单
利用 contextmenu 事件类型中的 e.preventDefault1
2
3document.addEventListener('contextmenu',function(e){
e.preventDefault();
})禁止选中文字
利用 selectstart 事件类型中的 e.preventDefault1
2
3document.addEventListener('selectstart',function(e){
e.preventDefault();
})鼠标事件对象
e.clientX(Y): 鼠标相对于浏览器页面的xy坐标(页面滚动也不影响)e.pageX(Y): 鼠标相对于整个页面文档的xy坐标e.screenX(Y): 鼠标相对于电脑屏幕的xy坐标注意:
通过此事件对对象位置进行改变时记得加px!!!
常用键盘事件
keyup:按键弹起时触发keydown: 按键按下时触发keypress: 按键上下弹起的分界点时触发
注意
对于传统事件注册记得加 on
keypress无法识别ctrl、shift等功能键三个时间执行顺序
keydown -> keypress -> keyup
键盘事件对象
e.keyCode: 返回所按的键的ASCII值
1  | document.addEventListener('keyup',function(e){  | 
注意:
keyup和keydown的keyCode不区分大小写 得到的都是大写的值keypress的keyCode区分大小写keydown和keypress在文本框里的特点: 两个事件触发时,文字还没落入文本框中
滚动事件
element.onscroll: 元素滚动时发生
BOM
Browser Object model 浏览器对象模型,提供了独立于内容而与浏览器窗口进行交互的对象,核心为 window
特点: BOM 由一系列相关的对象组成,并且每个对象提供了很多方法与属性。BOM 缺乏标准,js 语法的标准化组织是 ECMA,DOM 的标准化组织是 W3C,BOM 最初始 Netscape 浏览器标准的一部分
DOM
- 文档对象
 - DOM就是把[
文档]当做一个[对象]来看待 - DOM主要学习的是操作页面元素
 - DOM是W3C标准规范
 
BOM
- 浏览器对象模型
 - 把[
浏览器]当作一个[对象]来看待 - BOM的顶级对象是window
 - BOM学习是浏览器窗口交互的一些对象
 - BOM是浏览器厂商在各自浏览器窗口交互的一些对象
 - BOM是浏览器厂商在各自浏览器上定义的,兼容性较差
 
BOM的构成
Window 是浏览器的顶级对象,被 window 属性引用,代表是一个 web 浏览器窗口。它具有双重角色
它是 JS 访问浏览器窗口的一个接口
它是全局对象,定义在全局作用域中的变量、函数都会变成 window 对象的属性和方法
document 是 window 最重要的属性之一,它是 DOM 的顶级对象
调用的时候可以省略 window
注意: window 有一个特殊属性 window.name 命名变量时不要用 name
Window常见事件
页面加载事件
window.onload = function(){}window.addEventListener('load',function(){})当文档内容
完全加载完成会触发该事件(包括图像、脚本文件、CSS文件等),使用这个事件就可将script放在任意位置不影响执行document.addEventListener('DOMContentLoaded',function(){})当文档内容
不完全加载完成会触发该事件(不包括图像、flash、CSS文件等),速度较上两者较快调整窗口大小事件
window.onresize = function(){}window.addEventListener('resize',function(){});当窗口大小发生变化时触发事件,常用于响应式布局
屏幕当前宽度
window.innerWidthwindow.innerHeight
实现屏幕滚动
window.scroll(x,y): x,y为横向、纵向滚动的距离(不加单位)禁止双击选中文字
window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();定时器
window.setTimeout(调用函数,延迟时间);1
2
3
4
5
6
7
8
9
10setTimeout(function(){
alert('111');
},2000);
function callback(){
console.log('爆炸了');
}
setTimeout(callback,3000);
setTimeout('callback()',3000);
var time1 = setTimeout(callback,1000);
var time2 = setTimeout(callback,3000);注意:
延迟时间单位为毫秒 可以不写 默认为 0
这个调用函数可以直接写函数 也可以写 函数名 也可以 ‘函数名()’
window 可以省略
页面中可能有多个定时器 一般要起标识符
因为 setTimeout 是倒计时完再回调函数,所以也叫作回调函数
window.setInterval(调用函数,延迟时间);1
2
3setInterval(function(){
console.log('11');
},1000);注意: 其他都和 setTimeout 相同,但是 setTimeout 只调用函数一次,而 setInterval 是每隔设定间隔时间就调用一次,常用于倒计时
清除倒计时
window.clearTimeout(定时器的名字)1
2
3
4
5
6
7var btn = document.querySelector('button');
var timer = setTimeout(function(){
console.log('爆炸');
},5000);
btn.onclick = function(){
clearTimeout(timer);
}window.clearInterval(定时器名字)1
2
3
4
5
6
7
8
9
10
11var timer = null;
var begin = document.querySelector('.begin');
var stop = document.querySelector('.stop');
begin.addEventListener('click',function(){
timer = setInterval(function(){
console.log('hello?');
},1000)
})
stop.addEventListener('click',function(){
clearInterval(timer);
})注意:函数内定时器赋予名字时最好现在外面建立全局变量,以便清除
this指向问题
全局作用域或者普通函数中this指向全局对象 window(setTimeout、setInterval也是)
1
2
3
4
5
6
7
8console.log(this);
function fn(){
console.log(this);
}
fn();
setTimeout(function(){
console.log(this);
},1000);方法调用中指向调用方法者
1
2
3
4
5
6
7
8
9var o = {
sayHi: function(){
console.log(this); //指向o 因为这个函数是o的
}
}
o.sayHi();
btn.addEventListener('click',function(){
console.log(this); //指向btn
})构造函数this指向构造函数的实例(谁创建指向谁)
1
2
3
4function Fun(){
console.log(this); //指向fun()
}
var fun = new Fun();
JS的执行队列(非常重要)
JavaScript的一大特点即
单线程,即同一时间只能做一件事
JS有同步和异步
同步: 即按顺序执行任务,前一个任务结束再执行另一个
异步: 执行一件任务的同时可以执行其他任务
JS执行机制 - 分为同步任务和异步任务
同步任务: 都放到主线程上执行,形成一个
执行栈异步任务: JS的异步是通过
回调函数实现的
异步任务三种类型:
普通事件 如: click , resize , readystatechange 等
资源加载 如 load , error 等
定时器中的回调函数
异步任务的相关回调函数添加到任务队列中(消息队列)
执行过程:
先执行执行栈中的同步任务
遇到异步任务触发则将其回调函数放到任务队列中
等所有同步任务执行完毕后,再回去按序执行任务队列中的回调函数
异步进程处理: 用于检测异步任务是否被触发(比如点击,倒计时时间到等),一旦触发,就将其放入任务队列中。执行栈的同步任务全部执行完后,就会到任务队列查看是否有未执行的异步任务,一旦有则将其执行,全部执行完后会不断查看不断执行,形成 事件循环。
Location对象
window 的 location 属性引用了 Location 对象,用于获取 URL 相关属性
URL::统一资源定位符
1  | URL的一般语法格式为:  | 
protocol: 协议, http , ftp , maito 等host: 主机(域名)[www.xxxx.com](http://www.xxxx.com)port: 端口号 可选,省略时使用方案的默认端口 如http的默认端口为80path: 路径 由零个或多个/符号隔开的字符串,一般用来表示主机上的一个目录或文件query: 参数 以键值对的形式通过&符号分隔开fragment: 片段,#后面内容 一般用于链接锚点
location 对象的属性
| location对象属性 | 返回值 | 
|---|---|
location.href | 获取或者设置整个URL | 
location.host | 返回主机(域名) zykjofficial.gitee.io | 
location.port | 返回端口号 如果写返回 空字符串 | 
location.pathname | 返回路径 | 
location.search | 返回参数 | 
location.hash | 返回片段 #后面内容 常见于链接 锚点 | 
location另外几个属性
location.assign: 与href一样,实现页面跳转location.replace: 实现页面跳转,但是没有后退功能location.reload: 刷新页面 等于 f5location.reload(true): 强制刷新location = "#xx": 可以使页面滚动到 id 为 xx 的元素的位置
1  | var btn = document.querySelector('button');  | 
1  | <body>  | 
Navigator对象
window 的 navigator 属性引用的是 Navigator 对象。最常用的属性为 userAgent ,该属性可以返回有客户机发送服务机的 user-agent 头部的值
下列代码可以判断用户哪个终端打开页面,实现跳转
1  | //判断用户哪个终端打开页面,实现跳转  | 
History对象
window 对象给我们提供了一个 history 属性,该属性引用了 History 对象。可以与浏览器历史记录进行交互。该对象包含用户(在浏览器窗口中)访问过的 URL
| history对象方法 | 作用 | 
|---|---|
back() | 可以后退功能 | 
forward() | 前进功能 | 
go(参数) | 前进后退功能 参数如果是1 前进1个页面 如果是-1 后退1个页面 | 
pushState(state, title, url) | 向浏览器历史添加了一个状态。pushState()方法带有三个参数:一个状态对象、一个标题(现在被忽略了)以及一个可选的URL地址 | 
history.replaceState(state, title, url) | 修改当前历史记录条目而并非创建新的条目 | 
history.forward(): 实现前进功能
1  | btn.addEventListener('click',function(){  | 
history.back: 实现后退功能
1  | btn.addEventListener('click',function(){  | 
history.go(参数): 实现前进或后退功能
1  | btn.addEventListener('click',function(){  | 
history.pushState():向浏览器历史添加了一个状态。pushState()方法带有三个参数:一个状态对象、一个标题(现在被忽略了)以及一个可选的URL地址
1  | history.pushState(state, title, url);  | 
假定当前网址是example.com/1.html,使用pushState方法在浏览记录(history对象)中添加一个新记录
1  | var stateObj = { foo: 'bar' };  | 
添加上面这个新记录后,浏览器地址栏立刻显示example.com/2.html,但并不会跳转到2.html,甚至也不会检查2.html是否存在,它只是成为浏览历史中的最新记录。假如这时访问了google.com,然后点击了倒退按钮,页面的url将显示2.html,但是内容还是原来的1.html。再点击一次倒退按钮,url将显示1.html,内容不变
总之,pushState方法不会触发页面刷新,
只是导致history对象发生变化,地址栏的显示地址发生变化如果pushState的url参数,设置了一个新的锚点值(即hash),并不会触发hashchange事件,即使新的URL和旧的只在hash上有区别
如果设置了一个跨域网址,则会报错。这样设计的目的是,防止恶意代码让用户以为他们是在另一个网站上
1
2// 报错
history.pushState(null, null, 'https://twitter.com/hello');
history.replaceState:方法的参数与pushState方法一模一样,不同之处在于replaceState()方法会修改当前历史记录条目而并非创建新的条目
假定当前网页是example.com/example.html
1  | history.pushState({page: 1}, 'title 1', '?page=1');  | 
注: history 对象一般在实际开发中比较少用,但在一些办公OA系统会见到
无干扰的 JavaScript
这种模式强调 JavaScript 自身不应该惹人注意,不应该产生打扰。不应该去干扰用户浏览一个 web 页面,不应该干扰内容作者创建 HTML 标记,或者干扰 Web 设计者创建 HTML 模板或 CSS 样式表
方法
- 分离: 保持 JavaScript 代码与HTML标记的分离。尽可能让 JavaScript 代码的外部文件成为模块
 - 降级: 必须降低优雅性。JavaScript 模块应该首先确保它所需要的客户端功能在代码所运行的浏览器中是可用的
 - 不能降低一个 HTML 页面的可访问性.JS 的角色是增加信息的表现力而不是负责信息的表现。为了实现可访问性,应该尽可能支持独立于设备的事件(onfocus、onchange等)。
 
网页特效-PC端
offset系列
元素偏移量offset: 可以动态的获取元素的位置、大小等
offset系列常用属性
| offset系列属性 | 作用 | 
|---|---|
elememt.offsetPanett | 返回作为该元素带有定位的父级元素 如果父级都没有定位则返回body | 
element.offsetTop | 返回元素相对带有定位父元素上方的偏移 | 
element.offsetLeft | 返回元素相对带有定位父元素左边框的偏移 | 
element.offsetWidth | 返回自身包括padding、边框、内容区的宽度,返回数值不带单位 | 
element.offsetHeight | 返回自身包括paddling、边框、内容区的高度,返回数值不带单位 | 
注意:
返回的数值没有单位
offsetPanett返回的不一定是亲父亲,而是最近的
带有定位的父级元素。panettNode返回的是亲父亲且不管有没有定位
offset与style区别
offset
- offset 可以得到任意样式表中的样式值
 - offset 系列获得的数值是没有单位的
 - offsetWidth 包含padding + border + width
 - offsetWidth 等属性是只读属性,只能获取不能赋值
 所以, 我们想要获取元素大小位置,用offset更合适
style
- style 只能得到行内样式表中的样式值
 - style.width获得的是带有单位的字符串
 - style.width获得不包含padingRaborder 的值
 - style.width 是可读写属性,可以获取也可以赋值
 - 所以, 我们想要给元素更改值,则需要用style改变
 
client系列
通过client的相关属性可以动态获取该元素的边框大小,元素大小等
| client | 作用 | 
|---|---|
element.clientTop | 返回元素上边框的大小 | 
element.clientLeft | 返回元素左边框的大小 | 
element.clientWidth | 返回自身包括padding,内容区宽度,不包含边框 | 
element.clientHeight | 返回自身包括padding,内容区高度,不包含边框 | 
事件对象之offsetX/Y
offsetX 规定了事件对象与目标节点的内填充边(padding edge)在 X 轴方向上的偏移量。
比如在元素内触发点击事件时点击位置距离元素右边距的距离
立即执行函数
主要作用: 创建一个独立的作用域,避免了命名冲突问题
两种写法
(function(形参) {})(实参)1
2
3(function(a,b) {
console.log(a+b);
})(1,2);(function(形参) {} (实参) )1
2
3(function(a,b) {
console.log(a-b);
} (3,2));
scroll系列
通过scroll可以动态获取该元素的大小,滚动距离等
| scroll | 作用 | 
|---|---|
element.scrollTop | 返回被卷去的上侧距离 | 
element.scrollLeft | 返回被卷去的左侧距离 | 
element.scrollWidth | 返回自身实际的宽度,不含边框,包含padding | 
element.scrollHeight | 返回自身实际的高度,不含边框,包含padding | 
页面被卷曲的头部
页面被卷去的头部兼容性解决方案
需要注意的是,页面被卷去的头部,有兼容性问题, 因此被卷去的头部通常有如下几种写法:
声明了DTD ,使用
document.documentElement.scrollTop未声明DTD ,使用
document.body.scrollTop新方法
window.pageYoffset和window.pageXoffset,IE9开始支持
1  | function getScroll() {  | 
重点是window.pageYoffset 和window.pageXoffset
三大系列总结
用途
element.offsetTop(offsetLeft): 获取元素位置element.clientWidth(clientHeight): 获取元素大小element.scrollTop(scrollLeft): 获取元素滚动距离window.pageXOffset(pageYOffset): 获取页面滚动距离
总结:
element.offsetLeft/Top: 获取元素相对于最近的有定位的父元素的坐标,如果没有有定位的父元素,则是文档坐标element.scrollTop/Left: 获取元素滚动卷去的距离element.offsetWidth/Height: 获取元素的宽度高度(包含边框)element.clientWidth/Height: 获取元素的宽度高度(不包含边框)element.scrollWidth/Height: 获取元素的内容宽度高度(包括被卷曲的部分)e.pageX/Y 获取鼠标的文档坐标:(相对于文档而言)e.clientX/Y: 获取鼠标的视口坐标(相对于视口而言)e.screenX/Y: 获取鼠标的屏幕坐标(相对于整个浏览器而言)window.pageY/XOfffset: 获取页面的滚动距离
mouseover/mouseenter
mouseover和mouseenter的区别
mouseover会冒泡,mouseenter不会冒泡 与之对应的mouseleave也不会冒泡
1  | <div class="father">  | 
注:如果是mouseenter则经过父盒子本身才会触发,mouseover经过父盒子和子盒子都会触发
动画函数
核心原理: 通过定时器setInterval()不断移动盒子距离
缓动动画:即动画速度有所变化的动画
逐渐变慢实现原理:每次的移动距离都下降(= (目标距离-移动距离)/定值)
每次移动的距离应该取整,如果是正值则往大了取,因为最后面如果往小取会等于0停止移动,负值同理
解决多次点击按钮速度变快的方法:每次调用定时器时先清除之前的定时器
回调函数写在清除定时器之后
1  | //缓动动画函数封装obj目标对象target目标位置  | 
节流阀
防止轮播图按钮连续点击过快
当上一个动画执行完毕后再允许执行下一次,让事件无法连续触发
核心思路:利用回调函数,添加一个变量来控制,锁住函数和解锁函数
即:
先设置一个变量为true
当变量为true时执行事件,并将变量改为false,关闭水龙头
利用回调函数在事件结束后将变量改为true,打开水龙头
1  | var flag = true;  | 
客户端存储
客户端存储的形式
- web存储(包含 localStorage 和 sessionStorage 两个 API)
 - cookie
 - IE User Data
 - 离线 Web 应用
 - Web 数据库
 - 文件系统 API
 
客户端存储的特性
客户端存储遵循同源策略,因此不同站点的页面是无法互相读取对方存储的数据,而同一站点的不同页面之间是可以互相共享存储数据的
任何形式的客户端都不应该用来保存密码,商业账号或者其他类似的敏感信息
web存储
web存储特性数据存储在用户浏览器中
设置、读取方便
容量较大, sessionStorage 约 5M,localStorage 约 20M
只能存储字符串
window.localStorage 本地存储- 生命周期为永久性的,除非人为删除
 - 作用域限定在文档源中(文档源是通过协议、主机、端口号三者确定的),同源的 localStorage 可以互相读取对方数据,非同源文档则不可以(只要协议、主机、端口号有一个不同就是非同源文档)
 - 作用域也受浏览器供应商限制
 - 键值对形式存储
 
Window.sessionStorage 临时存储生命周期为关闭窗口或标签页
作用域也是限定在同源文档中。此外也被限定在窗口中,即使是同源文档,在不同的浏览器标签页打开也无法共享同个 seesionStorage 数据
以键值对的形式存储使用
存储API存储数据:
sessionStorage.setItem(key,value)获取数据:
sessionStorage.getItem(key)删除数据:
sessionStorage.removeItem(key)删除所有数据:
sessionStorage.clear()存储数据:
localStorage.setItem(key,value)获取数据:
localStorage.getItem(key)删除数据:
localStorage.removeItem(key)删除所有数据:
localStorage.clear()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18// 添加某个数据
set.addEventListener('click',function(){
var val = ipt.value;
sessionStorage.setItem('unmame',val);
sessionStorage.setItem('pwd',val);
})
//获得某个数据
get.addEventListener('click',function(){
console.log(sessionStorage.getItem('unmame'));
})
//删除指定数据
remove.addEventListener('click',function(){
sessionStorage.removeItem('unmame');
})
//删除所有数
del.addEventListener('click',function(){
sessionStorage.clear();
})cookie (指 web 存储的少量数据)
特点:
cookie 数据会自动在 Web 浏览器和 Web 服务器之间传输
兼容性好
所有查询设置删除都要通过 Document 对象的 cookie 属性完成
通过 navigator.cookieEnabled 来检查 cookie 是否启用
cookie的属性: 有效期和作用域有效期: cookie 的默认有效期很短,浏览器一旦关闭 cookie 保存的数据就丢失了。但是不是和 sessionStorage 相同,cookie 是整个浏览器关掉才会消失,而 sessionStorage 是标签页关掉则销毁该标签页的数据其他不影响。可以通过max-age 属性(单位为秒)设置有效期。
作用域: cookie 作用域由文档源和文档路径限制。一个页面的 cookie 可以和文档与其同个目录或者是其子目录的页面共享。
如:
http://www.baidu.com/catalog/index.html创建了一个 cookie ,那么该 cookie 对http://www.baidu.com/catalog/order.html或http://www.baidu.com/catalog/xxx/index.html都是可见的。可以通过修改cookie 的属性 path 来修改 cookie 的路径。如:
http://www.baidu.com/catalog/xxx/index.html创建了 cookie,如果把 path 改为”/catalog”,那么该 cookie 对http://www.baidu.com/catalog/widget/index.html也是可见的cookie的API保存 cookie: 将cookie属性值设置为 name = value 格式的字符串
如:
1
document.cookie = "version = " + encodeURIComponent(document.lastModified);
注意: cookie 中的值不允许包含分号逗号空白符,所以要在存储前对数据进行编码。相应的,读取时也要对获取的数据解码
同样可以设置 cookie的 path、domain、secure 等属性,只需将以下字符串形式追加在 cookie 值后面:
;path = path;domian = domain;secure如果要改变新 cookie 的值,就需要用相同的名字路径和域但是不同的值来设置 cookie 的值,如:
1
document.cookie = "version = " + encodeURIComponent('new value');//更改version的值
要删除 cookie,就需要用相同的名字路径和域但是任意一个非空的值再次设置 cookie
- 读取 cookie: 利用
document.cookie读取,返回值为字符串,一般会先用split分开,然后解码,再利用JSON.parse()方法还原成json对象 
IE userData(通过在 document 元素后面附加一个专属的 “DHTML行为” 实现客户端存储)
步骤:
对元素附加 userData 行为
1
div.style.behavior = "url('#default#userData')";
此时的元素拥有 save() , load() 方法,接下来就可以通过元素的属性来访问这些名/值对形式的数据
通过 getAttribute、setAttribute 存储获取userData数据
1
2
3
4
5
6//存储
div.setAttribute("index",1);
div.save("myindex");
//读取
div.load("myindex");
div.getAttribute("index");
离线Web应用(允许Web应用将应用程序自身本地保存到用户的浏览器中)
是将应用程序自身保存起来——应用程序所需运行的所有文件(HTML、CSS、JavaScript/图片等),不会随着用户清楚浏览器缓存而被清除
基本步骤: 首先要准备一个清单: 包含了所有应用程序依赖的所有 URL 列表,然后通过 html 标签中设置 manifest 属性指向该清单文件即可
清单文件以
.appcache作为文件扩展名。首行内容必须为”CACHE MANIFEST”1
2
3
4
5
6
7CACHE MANIFEST
//以下是文件清单
myapp.html
myapp.js
myapp.css
images/background.png复杂的清单
清单文件中可以使用特殊的区域头来标识该头信息之后清单项的类型
上面都属于
"CACHE:"区域,也是默认的区域此外还有两种
"NETWORK": 该区域标识了该 URL 中的资源从不缓存,都是从网络获取"FALLBACK": 该区域中清单项每行都包含两个 URL ,第一个 URL 是一个前缀,任何能够匹配到该前缀的URL都不会缓存起来,但是可能的话,它们会从网络中载入。第二个 URL 是指需要加载和存储在缓存中的资源。如果从网络中载入这样一个 URL 失败的话。就会使用第二个 URL 指定的缓存资源来代替,从缓存中获取。1
2
3
4
5
6
7
8
9
10
11
12CHCHE MANIFEST
CACHE:
myapp.html
myapp.css
myapp.js
FALLBACK:
video/ offline_help.html
NETWORK:
cgi /
缓存的更新
在线的状态下,浏览器会异步检查清单文件是否有更新。但只是检查清单文件,而不是检查清单文件里的资源是否有更新。想更新资源文件需要手动修改
想要卸载 APP 应用,则要在服务器端删除清单文件,使得请求该文件的时候返回404无法找到的错误,同时,修改 HTML 文件 manifest 属性以便他们与该清单列表”断开连接”
H5新增API
这里的知识需要 jquery
检测网络连接状态
网络连接事件
online 当网络连接时触发
1  | window.addEventListener("online",function(){  | 
网路断开事件
offline 网络断开时触发
1  | window.addEventListener("offline",function(){  | 
全屏显示
全屏显示可以是任意元素,存在兼容性问题,包括高版本浏览器
请求全屏事件
不同浏览器需要添加不同前缀
xx.RequestFullScreen()
xxx.webkitRequestFullScreen()
xxx.mozRequestFullScreen() 等等
ms的screen必须为小写
1  | if(img.requestFullScreen){  | 
取消全屏
跟元素没有关系,一般是用在 document 上,也要加浏览器前缀
1  | document.CancelFullScreen();  | 
检测是否全屏
也是加在 document 上,也要加前缀
1  | document.IsFullScreen();  | 
文件读取
FileReader对象
FileReader 对象: 允许 web 应用程序异步读取存储在用户计算机上的文件,比如一个 input 元素上选择文件后返回的对象
属性
FileReader.result: 用于读取文件的内容,仅在文件读取操作完成后有效,数据的格式取决于使用哪个方法(以下)来启动读取操作
方法
FileReader.readAsDataURL(目标文件): 读取指定的文件的内容,返回 data:URL 格式的字符串(地址)存放在 result 属性中FileReader.readAsText(目标文件): 读取指定文件的内容,以字符串格式返回文件内容到 result 属性中
事件处理
FileReader.onload: 该事件在读取完成时触发
file 类型 input 表单中有一个属性 files,以伪数组形式保存上传的文件信息,可以用 filereader 对象读取
1  | reader.readAsDataURL(file.files[0]);  | 
可以用 onchange 事件处理来检测 file 表单是否上传了文件
video标签
属性
video.duration: 返回当前音频/视频的长度curnettTime: 返回或设置当前音频/视频的播放进度
事件
video.oncanplay: 当前视频/音频可以播放时触发video.onended: 当前视频/音频播放结束时触发video.ontimeupdate: 当前视频/音频播放位置改变时触发 通常与 curnettTime 属性一起使用










