【前端】JavaScript

  • ~25.44K 字
  1. 1. JS基础
    1. 1.1. 语句与标识符
      1. 1.1.1. 结束符
      2. 1.1.2. 语句
      3. 1.1.3. 标识符
      4. 1.1.4. 变量
      5. 1.1.5. 常量
    2. 1.2. 引入到文件
      1. 1.2.1. 嵌入到HTML文件中
      2. 1.2.2. 引入本地独立JS文件
      3. 1.2.3. 引入网络来源文件
      4. 1.2.4. 内联JavaScript
    3. 1.3. I/O方式
      1. 1.3.1. prompt
      2. 1.3.2. alert
      3. 1.3.3. write
      4. 1.3.4. log
      5. 1.3.5. 执行顺序
    4. 1.4. 数据类型
      1. 1.4.1. 原始类型
      2. 1.4.2. 引用类型
      3. 1.4.3. typeof
      4. 1.4.4. 类型转换
    5. 1.5. 运算符
      1. 1.5.1. 严格相等/不等运算符
      2. 1.5.2. 布尔运算符
      3. 1.5.3. 运算符短路
    6. 1.6. 字符串
      1. 1.6.1. 模板字符串
      2. 1.6.2. length方法
      3. 1.6.3. charAt方法
      4. 1.6.4. concat方法
      5. 1.6.5. substring方法
      6. 1.6.6. substr方法
      7. 1.6.7. indexOf方法
      8. 1.6.8. trim方法
      9. 1.6.9. split方法
    7. 1.7. 数组
      1. 1.7.1. 遍历
      2. 1.7.2. isArray方法
      3. 1.7.3. push/pop方法
      4. 1.7.4. shift/unshift方法
      5. 1.7.5. splice方法
      6. 1.7.6. join方法
      7. 1.7.7. concat方法
      8. 1.7.8. reverse方法
      9. 1.7.9. indexOf 方法
    8. 1.8. 函数
      1. 1.8.1. 作用域
      2. 1.8.2. 匿名函数
    9. 1.9. 对象
      1. 1.9.1. 声明
      2. 1.9.2. 使用
      3. 1.9.3. 遍历
      4. 1.9.4. 内置对象
        1. 1.9.4.1. Math对象
        2. 1.9.4.2. Date对象
        3. 1.9.4.3. 环境对象
  2. 2. Web API
    1. 2.1. DOM
      1. 2.1.1. 节点
      2. 2.1.2. 节点树
      3. 2.1.3. DOM对象
      4. 2.1.4. Node.nodeType属性
      5. 2.1.5. 获取DOM对象
      6. 2.1.6. 创建/增加节点
      7. 2.1.7. 修改节点
      8. 2.1.8. 查找节点
      9. 2.1.9. 删除节点
      10. 2.1.10. Element对象
      11. 2.1.11. 获取元素位置
      12. 2.1.12. CSS操作
        1. 2.1.12.1. HTML的style属性
        2. 2.1.12.2. 元素节点的style属性
        3. 2.1.12.3. cssText形式
      13. 2.1.13. 事件处理程序
        1. 2.1.13.1. HTML事件
        2. 2.1.13.2. DOM0事件
        3. 2.1.13.3. DOM2事件
      14. 2.1.14. Event事件对象
        1. 2.1.14.1. 常见事件类型
        2. 2.1.14.2. 属性
        3. 2.1.14.3. 键盘事件
        4. 2.1.14.4. 表单事件
        5. 2.1.14.5. 事件流
        6. 2.1.14.6. 滚动事件
        7. 2.1.14.7. 加载事件
        8. 2.1.14.8. 获取元素大小与位置
      15. 2.1.15. 定时器
        1. 2.1.15.1. setTimeout()
        2. 2.1.15.2. setInterval()
    2. 2.2. 实例化
      1. 2.2.1. 时间对象
      2. 2.2.2. 时间戳
    3. 2.3. BOM
      1. 2.3.1. window对象
        1. 2.3.1.1. JS执行机制
        2. 2.3.1.2. location对象
        3. 2.3.1.3. navigator对象
        4. 2.3.1.4. history对象
      2. 2.3.2. 本地存储
        1. 2.3.2.1. localStorage
        2. 2.3.2.2. sessionStorage
    4. 2.4. 防抖
      1. 2.4.1. 滚动监听防抖
      2. 2.4.2. 思路
    5. 2.5. 节流
      1. 2.5.1. 应用
    6. 2.6. ECMAScript
      1. 2.6.1. Babel转码器
      2. 2.6.2. 对象解构赋值
      3. 2.6.3. 字符串扩展
      4. 2.6.4. 扩展运算符
      5. 2.6.5. 数组扩展
      6. 2.6.6. 对象扩展
      7. 2.6.7. 箭头函数
      8. 2.6.8. set
        1. 2.6.8.1. 定义
        2. 2.6.8.2. 方法

JS基础

JS包括两大部分:ECMAScript与WebAPIs

前者用于定义基础语法知识,后者包括DOM与BOM,分别操作文档与浏览器

语句与标识符

结束符

语句尾以分号或回车结束

也可以不加,浏览器会自动

规定:要么都写要么都不写

语句

JavaScript程序的单位是行(line),每一行就是一个语句,以分号结尾

在html中可以使用<script>标签内联JavaScript语句

标识符

用来识别各种值的合法名称,如变量名

由字母、$、_、数字组成,数字不能开头,保留字也不能作为标识符

变量

使用var或let关键字创建变量

let用于声明局部变量,是块级作用域

而var是函数级作用域

1
2
3
4
5
6
>{
let a = 1;
var b = 2;
>}
>console.log(a) // 未定义
>console.log(b) // 2

注意:

  • let不能重复声明
  • let不存在变量提升

现在统一用let即可

规则:

  • 不能用关键字
  • 不能数字开头
  • 区分大小写

规范:小驼峰命名法

变量提升:JavaScript是解释型语言,获取所有被声明的变量并一行行运行,造成的结果是所有变量的声明语句会被提升到代码头部

常量

使用const声明只读常量,const声明的变量不能改变值,因此一旦声明变量就可以立即初始化

作用域与let相同,只在声明所在的块级作用域内有效

const命令声明的常量也不提升,不能重复声明

推荐统一使用const,因为声明的变量基本不需要修改,若需要修改再改为let

引入到文件

嵌入到HTML文件中

写在html文件里,用script标签包裹

规范:script写在</body>上方

因为加载顺序是自顶向下的,若先加载的js期望修改下面的html,可能因为未被加载而失效

1
2
3
4
5
<body>
<script>
var age = 10
</script>
</body>

引入本地独立JS文件

代码写在以.js结尾的文件内

通过script标签引入:中间无序写代码,写了也会被忽略

1
2
3
4
5
<body>
<script type="text/javascript" scr"./">

</script>
</body>

引入网络来源文件

1
2
3
4
5
<body>
<script scr="url">

</script>
</body>

内联JavaScript

代码可以写在标签内部

1
2
3
<body>
<button onclick="alert('111')">点击</button>
</body>

I/O方式

prompt

弹出对话框,包含一条文字信息,提示用户输入文字

prompt('请输入姓名')

注意,接收到的数据是字符串类型,需要按需转换

如转换为整形可以使用+prompt()或parseInt(prompt())等

alert

在浏览器中弹出对话框

1
alert("我是弹出框");

write

使用document.write可以输出到页面

若输入的是标签,会被解析为网页元素

1
document.write("我是输出到页面");

log

使用console.log可以输出到控制台

1
2
var age = 20;
console.log(age);

执行顺序

  • 按HTML文档流顺序执行
  • alert和prompt会跳过页面渲染先被执行

数据类型

JS是一门弱数据类型语言

JS一共由六种数据类型,ES6后又添加了两种新类型

原始类型

包括数值、字符串与布尔值和两种特殊值:

  • null:空值,一般代表对象的空,把它作为尚未创建的对象
  • undefined:未定义,一般代表数值的空,只声明不赋值的情况下变量默认为该值

其中数字类型中包含NaN,表示计算错误,是一个不正确或未定义的数学操作得到的结果

1
2
3
4
5
<script>
var a = 1;
var b = "1";
var c = true;
</script>

引用类型

对象:一个对象可以看作是多个数据类型的容器

1
2
3
4
5
var user = {
a: 1,
b: "1",
c: true,
}

typeof

用于判断(基本)数据类型

语法:

1
typeof var
  • 数值返回number
  • 字符串返回string
  • 布尔返回boolean
  • 对象返回object(不准确,很多情况下都会返回object,如数组也属于对象,返回object)

类型转换

prompt取得的数据类型是字符串类型

隐式转换

默写运算符运行时,内部自动将数据类型进行转换

  • 加号两边只要有一个是字符串,会把另一个转为字符串
  • 除了加号以外的算术运算符都会把数据转为数字类型

显式转换

可以自己识别px

  • Number():转化为数字型,若字符串内有非数字,转换失败结果为NaN
  • parseInt():只保留整数
  • parseFloat():可以保留小数

运算符

加减乘除取余,自加自减,复合运算符均与C++类似

严格相等/不等运算符

==或!=仅比较数值是否相同或不同

===或!==比较数值是否相同或不同的同时,匹配数据类型是否相同或不同

1
2
3
4
var a = "10";
var b = 10;
console.log(a==b); // true
console.log(a===b); // false

布尔运算符

与运算符:&&

或运算符:||

非运算符:!

非布尔值取反:对于非布尔值取反时会将其转为布尔值

其中undefined、null、false、0、NaN、空字符串取反后为true,其余为false

运算符短路

在&&与||中,可以发生短路效果

字符串

字符串是零个或多个排在一起的字符,用单引号或双引号包裹

默认只能写在一行中,分成多行时需要在尾部添加\

模板字符串

以反引号`开头的字符串,可以在字符串中添加变量

这样就不需要将多个字符串用+号连接起来

1
var a = `<a href="${href}">${text}</a>`

length方法

返回字符串长度

1
2
var s = "111";
console.log(s.length); // 3

charAt方法

传入下标,返回对应字母

若参数为负数,或大于等于字符串长度,则返回空字符串

1
2
var str = "123";
console.log(str.charAt(0)); // 1

concat方法

连接两个字符串,返回新字符串,不改变原字符串

concat可以接受多个参数,同时连接

若传入的不是字符串类型,则会转换为字符串类型

其实可以用+拼接字符串

1
2
3
4
5
var a = "1";
var b = "2";
var c = "3";
var re = a.concat(b,c);
console.log(re);

substring方法

截取字符串,返回新字符串,不改变原字符串,第一个参数表示开始位置,第二个参数表示结束位置(不含)

  • 若省略第二个参数,则表示子字符串一直到原字符串结束
  • 若第一个参数大于第二个参数,则会自动更换两个参数的位置
  • 若参数是负数,会自动把负数转为0
1
'12345'.substring(0,2); // '12'

substr方法

substr的作用和substring一样,但第二个参数表示截取字符串长度

  • 若省略第二个参数,则直到原字符串结束

  • 若第一个参数是负数,表示倒数计算的字符位置

  • 若第二个参数是负数,则会自动转为0,返回空字符串

indexOf方法

确定一个字符串在另一个字符串中第一次出现的位置,返回结果是匹配开始的位置,若返回-1则表示不匹配

也可以接受第二个参数,表示从该位置开始向后匹配

1
2
'hello'.indexOf('o'); // 4
'Hollo'.indexOf('o',3); // 4

trim方法

用于去除字符串两端的空格、制表符、换行符、回车符等,返回新字符串,不改变原字符串

1
' hello world '.trim(); // 'hello world'
  • trimEnd():去除后面的
  • trimStart():去除前面的

split方法

按给定规则分割字符串,返回一个由分割出来的子字符串组成的数组

  • 若分割规则为空字符串,则返回的是每一个字符
  • 若省略参数,则返回数组唯一成员是原字符串
  • 可以接受第二个参数,限定返回数组的最大成员数

数组

方括号括起来的数组,任何数据都可以放进数组

不需要提前分配内存,可以一直往后加

遍历

除了传统方法,可以使用for in遍历数组

1
2
3
4
var a = [1,2,3,4,5];
for (var i in a){
console.log(a[i]);
}

isArray方法

返回布尔值,表示参数是否为数组

push/pop方法

push用于在数组末端添加一个或多个元素,并返回添加新元素后的数组长度

可以同时添加多个数据,用逗号分隔

pop用于删除数组的最后一个元素,并返回该元素

shift/unshift方法

shift用于删除数组第一个元素,并返回该元素

unshift用于在数组第一个位置添加元素,并返回添加新元素后的数组长度

splice方法

用于删除指定元素,语法:arr.splice(起始位置, 删除元素个数)

第二个参数缺省默认删除到最后

1
arr.splice(1,2);

join方法

以指定参数作为分隔符,将所有数组成员连接为一个字符串返回,默认用逗号分隔

若数组成员是undefined或null或空位,会被转换成空字符串

1
2
3
var a =[1,2,3,4];
a.join(' ') // '1 2 3 4'

join可以配合split实现数组与字符串的互换

1
2
3
4
var arr = ['a', 'b', 'c'];
var myarr = arr.join("");
console.log(myarr);
console.log(myarr.split(""));

concat方法

用于多个数组的合并,将新数组的的成员添加到原数组成员的尾部,返回一个新数组

也可以接受其他值类型作为参数添加到目标数组尾部

应用场景:上拉加载,合并数据

1
2
['a'].concat(['b','c']);
['a'].concat('b','c');

reverse方法

颠倒数组元素,返回改变后的数组

1
2
var a=['a','b','c'];
a.reverse(); // ['c', 'b', 'a']

indexOf 方法

返回给定元素在数组中第一次出现的位置,若没有出现则返回-1

也可以接受第二个参数,表示搜索开始的位置

1
2
3
var a = [1,2,3,4,3];
a.indexOf(3); // 2
a.indexOf(3,3); // 4

函数

使用function命令,后面接代码名、圆括号里写入传参、大括号里写入函数体

使用return返回返回值,若没有return默认返回值是undefined

1
2
3
function print(s){
console.log(s);
}

JavaScript将函数名视同变量名,采用function声明函数时,整个函数会提升到代码头部

作用域

限定某个变量的可用性的代码范围就是这个变量的作用域

函数内部的形参位于局部作用域

注意:若作用域内变量未声明就定义,默认为var,看作全局变量

访问原则:能够访问到的情况下,先局部再全局,即采用就近原则来查找变量最终的值

匿名函数

没名字的函数,两种使用方法:

  • 将匿名函数赋值给一个变量,作为函数名,称为函数表达式

    1
    let f = fucntion(){return 1+1};
  • 不需要调用,直接执行,称为立即执行函数

    注意:多个立即执行函数之间用分号分隔

    1
    2
    3
    (function(){console.log(11)})();

    (function(){console.log(11)}());

对象

JavaScript中的对象是一组键值对的集合,是一种无序的复合数据集合

声明

对象的每一个键名称为属性,可以是任何数据类型

对象通过对象名.属性读取

若一个属性的值为函数,将这个属性称为方法,可以像函数那样调用

若一个属性的值还是一个对象,就形成了链式引用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var user={
name: 'aaa',
f: function (name){
return name;
}
container:{
a: 1;
b: 2;
}
}

let user = new Object()

user.f('bbb');
console.log(user.container.a); // 1

使用

  • 增:对象.新属性名 = 新值
  • 删:delete 对象名.属性名
  • 查:对象.属性或对象['属性']
  • 改:对象.属性 = 值

遍历

1
2
3
4
for(let k in obj){
console.log(k)
console.log(obj[k])
}

内置对象

JS中提供了一些即时调用的内置对象

Math对象

  • Math.abs():返回参数的绝对值

  • Math.max()/min():返回参数值中的最大值或最小值,若参数为空,则返回Infinity或-Infinity

  • Math.floor()/ceil():对参数向下/向上取整

  • Math.random():返回之间的伪随机数

    可以用以下方法生成一个任意范围的伪随机数

    1
    2
    3
    4
    5
    function getRandomNumber(min, max){
    return Math.random()*(max-min)+min;
    }

    getRandomNumber(5,10);

Date对象

Data对象是原生的时间库,以Unix时间戳表示

  • Date.now():返回当前时间距离时间零点的毫秒数,相当于Unix时间戳*1000

  • get方法:Date对象提供了一系列get方法,用于获取实例对象某个方面的值

    得到时间戳后,可以向Date对象传入时间戳,以获取具体信息

Date.get

环境对象

指函数内部特殊的变量this,代表着当前函数运行时所处对的环境

函数的调用方式不同,this指代的对象也不同

大致规则:谁调用this就是谁,如果直接调用就是window.调用,this指代window

Web API

WebAPI分为DOM(文档对象模型)与BOM(浏览器对象模型)

DOM

DOM是用来呈现以及与任意HTML或XML文档交互的API

浏览器会根据DOM模型,将结构化文档解析为一系列节点,再组成一个树状结构(DOM Tree),所有节点和最终的树状结构,都有规范的对外接口

DOM只是一个接口规范,可以用各种语言实现,JS是最常用于DOM操作的语言

节点

DOM的最小组成单位是节点,每个节点可以看作文档树的叶子,节点有其中类型

  • Document:整个文档树的顶层节点
  • DocumentType:doctype标签
  • Element:网页的各种HTML标签
  • Attribute:网页元素的属性
  • Text:标签之间或标签包含的文本
  • Comment:注释
  • DocumentFragment:文档片段

节点树

节点数将html文档以树状结构表现,直观体现了标签之间的关系

浏览器原生提供document节点,代表整个文档

除了根节点,其他节点有三种层级关系

  • 父节点:直接上级节点

  • 子节点:直接下级节点

  • 同级节点:拥有同一个父节点的节点

DOM对象

浏览器根据HTML标签生成的js对象

  • 所有标签属性都可以在这个对象上面找到
  • 修改对象属性会自动映射到标签身上

如document对象就是DOM里提供的一个对象,他提供的属性和方法都是用来访问和操作网页内容的

Node.nodeType属性

不同节点的nodeType属性值不同,还有对应常量

获取DOM对象

  • document.getElementsByTagName():

    搜素HTML标签名,返回符合条件的元素,返回值是一个类似数组的对象,可以试试反应HTML文档变化,若没有任何匹配元素,则返回一个空集,若传入'*'则返回文档中所有HTML元素

    可以使用[index]选择需要的标签

1
2
3
4
5
6
7
8
9
<body>
<div>hello</div>
<div>world</div>
<script>
var divs = document.getElementsByTagName("div")[0];
console.log(divs);
</script>

</body>
  • document.getElementsByClassName():

​ 返回包含所有class名字复合指定条件的元素

​ 参数可以是多个class,使用空格分隔

1
2
3
4
5
6
7
8
<body>
<p class="text">hello2</p>
<script>
var text = document.getElementsByClassName("text")[0];
console.log(text);
</script>

</body>
  • document.getElementsByName():

​ 选择拥有name属性的HTML元素,返回NodeList示例

1
2
3
4
5
6
7
8
<body>
<form name="a">hello3</form>
<script>
var names = document.getElementsByName("a");
console.log(names);
</script>

</body>
  • document.getElementById():

​ 返回匹配指定id属性的元素节点,若没有发现则返回null

  • document.querySelector():

    接受一个CSS选择器作为参数,返回匹配该选择器的元素节点,若有多个匹配条件,则返回第一个匹配的节点,若没有发现匹配的节点,则返回null

  • document.querySelectorAll():

​ 与上面用法类似,接受一个或多个有效的CSS选择器作为参数,区别是返回一个NodeList对象,包含所有匹配给定选择器的节点

​ 注意,这里的NodeList对象是一个为数组,有长度与索引,但是没有数组方法,需要通过for遍历获得每一个对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<body>

<div class="nav">hello5</div>
<div class="nav">hello6</div>
<script>

var sel = document.querySelector(".nav");
console.log(sel);
var sels = document.querySelectorAll(".nav");
console.log(sels);

</script>

</body>

创建/增加节点

  • document.createElement():

    生成元素节点并返回该节点

  • document.createTextNode():

    生成文本节点(text实例)并返回该节点,参数是文本节点的内容

  • document.createAttribute():

    生成一个新的属性节点(attr实例)并返回该节点

    使用id.value(值)对id赋值

    使用var.setAttributeNode(id)将id放入元素,只有属性的放入有这个方法

  • var.appendChild(var):

    将内容或子元素放入容器中

  • var.insertBefore(要插入的节点, 在哪个节点前面):

    插入到父元素中某个子元素的前面

  • var.cloneNode(boolen):

    克隆一个已有节点,其中true表示克隆时包含后代节点,false表示不包含,默认false

1
2
3
4
5
6
7
8
9
10
11
12
<body>
<script>
var text = document.createElement("p");
var content = document.createTextNode("text");
var id = document.createAttribute("id");
id.value = "root";
text.appendChild(content);
text.setAttributeNode(id);

console.log(text);
</script>
</body>

修改节点

  • document.write():

    追加文本内容,且只能追加到</body>之前的位置

    文本中的标签会被解析

查找节点

  • 父节点查找:
    • Element.parentNode:返回最近一级的父节点,找不到返回null
  • 子节点查找:
    • Element.childNode:返回所有子节点,包括文本,注释等
    • Element.children:仅获得所有元素节点,返回一个NodeList对象
  • 兄弟节点查找:
    • nextElementSibling:下一个兄弟节点
    • previousElementSibling:上一个兄弟节点

删除节点

Element.removeChild(要删除的元素)

注意:

  • 在原生DOM操作中,要删除元素必须通过父元素删除
  • 若不存在父子关系则删除不成功
  • display:none是隐藏,这个才是真的删除

Element对象

Element对象对应网页的HTML元素,每个元素在DOM树上都会转换为一个Elment节点对象

  • Element.id:

    返回指定元素的id属性,可读写

    1
    2
    3
    4
    var p = document.querySelector('p');
    p.id;

    p.id = "123";
  • Element.className:

    用来读写当前元素节点的class属性,值是一个字符串,每个class之间用空格分割

    1
    2
    3
    4
    5
    6
    var div = document.getElementById('myDiv');
    div.className;

    // 注意,一般要同时添加自身class
    div.className = "box0 box1";

  • Element.属性:

    其实标签中包含的元素属性都可以进行修改

    1
    2
    3
    let pic = document.querySelector('img');
    pic.src = './img/1.png';
    pic.title = '这是图片'

    注意,对表单属性进行修改是,对于添加就有效果,移除就没有效果的,统一使用布尔值表示是否添加

  • Element.classList:

    • add():添加某class
    • remove():移除某class
    • contains():判断是否存在某class
    • toggle():切换某个class
  • Element.innerHTML/innerText:

    返回一个字符串,等同于该元素包含的所有HTML代码/文本,可读写

    常用来设置某个节点的内容

    与innerText的区别在于innerText无法识别标签,会被直接渲染为字符串

获取元素位置

  • 前两者若有水平滚动条,则要减去水平滚动条的高度

  • document.documentElement.clientHeight返回当前视口的高度

    document.body.clientHeight返回网页的实际高度

  • offsetLeft/offsetTop是相对于父级的,会一直往上找有定位的父级知道文档顶

CSS操作

HTML的style属性

最简单的方式是使用网页元素节点的setAttribute方法直接操作网页的style属性

setAttribute有两个参数,分别为设置样式的属性,设置的值

1
2
3
4
div.setAttribute(
'style',
'background-color:red'
);

元素节点的style属性

1
2
3
4
var divstyle = document.querySelector('div').style;
divstyle.backgroundColor = 'red';
divstyle.border = '1px solid black';
divstyle.width = '100px';

cssText形式

1
box.style.cssText = "width:200px;height:200px;backgroudn:red;"

注意,若属性中有-连接符,需要转换为小驼峰命名,且不要忘记添加单位

事件处理程序

事件指的是系统内发生的动作或事情

HTML事件

创建一个函数来设置HTML中的事件,在对应事件属性中添加该函数名即可

缺点:HTML与JS没有分开

1
2
3
4
5
6
7
8
<body>
<button onclick="click()">点击</button>
<script>
function click(){
console.log("hello world");
}
</script>
</body>

DOM0事件

实现了HTML与JS的分离,但是无法同时添加多个事件(后面的会覆盖前面的)

格式为Element.on事件 = function(){}

1
2
3
4
5
6
7
8
9
<body>
<button id="btn">点击</button>
<script>
var btn = document.getElementById("btn");
btn.onclick = function(){
console.log("点击了");
}
</script>
</body>

DOM2事件

可以添加多个事件,实现事件监听

使用Element.addEventListener('事件', 要执行的函数)进行监听

1
2
3
4
5
6
7
8
<body>
<button id="btn">点击</button>
<script>
var btn = document.getElementById("btn");
btn.addEventListener("click",function(){console.log("1");});
</script>

</body>

Event事件对象

事件发生后,会产生一个事件对象,作为参数传给监听函数

该对象内存储了事件触发时的相关信息

在事件绑定的回调函数的第一个参数就是事件对象,一般命名为e, event等

常见事件类型

  • 鼠标事件
鼠标事件
  • 焦点事件
    • focus:获得焦点
    • blur:失去焦点
  • 键盘事件
    • keydown:键盘按下触发
    • keyup:键盘抬起触发
  • 文本事件
    • input:用户输入事件

属性

  • event.target

    返回事件当前所在的节点,返回后就可以进行编辑

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <body>
    <button id="btn">点击</button>
    <script>
    var btn = document.getElementById("btn");
    btn.onclick = function(event){
    console.log(event.target);
    }
    </script>

    </body>
  • event.type

    返回字符串,表示事件类型

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <body>
    <button id="btn">点击</button>
    <script>
    var btn = document.getElementById("btn");
    btn.onclick = function(event){
    event.target.innerHTML = "after";
    console.log(event.type);
    }
    </script>

    </body>
  • event.clientX/clientY

    获取光标相对于浏览器可见窗口左上角的位置

  • event.offsetX/offsetY

    获取光标相对于当前DOM元素左上角的位置

  • event.key

    获取用户按下的键盘键的值

键盘事件

对于keyCode,现在不提倡使用,故删去

可以使用event对象中的key属性代替

表单事件

使用表单元素及输入框元素时可以监听的一系列事件

input事件

当<input>,<select>,<textarea>的值发生变化时触发,用户改变复选框与单选框选项时也会触发这个事件

input事件可以实时读取数据

1
2
3
4
5
6
7
8
9
10
<body>
<input type="text" id="username">

<script>
var username = document.getElementById("username");
username.oninput = function(e){
console.log(e.target.value);
}
</script>
</body>
select事件

当在<input>,<textarea>里面选中文本时触发

1
2
3
4
5
6
7
8
9
10
11
<body>
<input type="text" id="username">

<script>
var username = document.getElementById("username");
username.onselect = function(e){
console.log(e.target.value);
}

</script>
</body>
change事件

当<input>,<select>,<textarea>的值发生变化时触发,不会连续触发,只有当全部修改完成时才会触发(失去焦点或回车)

1
2
3
4
5
6
7
8
9
10
11
<body>
<input type="text" id="username">

<script>
var username = document.getElementById("username");
username.onchange = function(e){
console.log(e.target.value)
}

</script>
</body>
reset与submit事件

发生在表单对象<form>中

reset事件当表单重置(所有表单成员变回默认值)时触发

submit事件当表单数据向服务器提交时触发

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<body>
<form id="myform" onsubmit="submitHandle">
<input type="text" id="username">
<button id="resetb">重置</button>
<button>提交</button>
</form>
<script>
var resetb = document.getElementById("resetb");
var myform = document.getElementById("myform")
reset.onclick = function(){
myform.reset();
}
function submitHandle(){
console.log("submit")
}
</script>
</body>

事件流

事件被触发时,会经历两个阶段:捕获阶段与冒泡阶段

事件冒泡

当一个元素的事件被触发时,同样的事件会在该元素的所有祖先元素中依次被触发

即当一个元素触发事件后,会依次向上调用所有父级元素的同名事件

事件捕获

从DOM的根元素开始执行对应事件,需要手动编写代码

DOM.addEventListener(事件类型, 事件处理函数, 是否使用捕获机制)

  • 第三个参数传入true代表捕获阶段触发,传入false代表冒泡阶段触发
  • 若用DOM0事件监听,则只有冒泡阶段
事件代理/事件委托

由于事件会在冒泡阶段向上传播到父节点,因此可以把子节点的监听函数定义在父结点上,由父节点的监听函数统一处理多个子元素的事件,这种方法叫做事件的代理

1
2
3
4
5
6
7
8
9
10
11
12
<body>
<ul id="list">
<li>列表1</li>
<li>列表2</li>
</ul>
<script>
var list = document.getElementById("list");
list.onclick = function(e){
console.log("触发")
}
</script>
</body>

如这里的事件是放在ul标签中的,但点击子元素时同样可以触发父元素事件

故我们可以将子元素事件统一放给父元素处理

使用Element.target可以获得真正触发事件的元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<body>
<ul id="list">
<li>列表1</li>
<li>列表2</li>
</ul>
<script>
var list = document.getElementById("list");
// list.onclick = function(e){
// console.log("触发")
// }
list.addEventListener("click", function(e){
if(event.target.tagName==="LI"){
console.log(event.target.innerHTML);
}
})
</script>
</body>

DOM2事件也可以,指定监听标签

阻止事件流动
  • event.preventDefault()

    该方法可以取消浏览器对当前事件的默认行为,如点击链接后,浏览器会跳转到另一个页面,使用后就不会跳转了

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <body>
    <a href="https://baidu.com" id="it">点击</button>
    <script>
    var it = document.getElementById("it");
    it.onclick = function(e){
    e.preventDefault();
    console.log("点击A");
    }
    </script>

    </body>

  • event.stopPropagation()

    若想将事件限制在当前元素内,就需要阻止事件流动

​ 该方法可以阻断事件流动传播,在冒泡和捕获阶段都有效

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<body>
<div class="root" id="root">
<div class="box" id="box"></div>
</div>
<script>
var root = document.getElementById("root");
var box = document.getElementById("box");
it.onclick = function(e){
e.stopPropagation();
console.log("点击A");
}
</script>

</body>

滚动事件

当我们滚动页面或某个元素时就会触发滚动事件,包括如下操作:

  • 使用右侧滚动条
  • 使用鼠标滚轮
  • 点击锚点链接
  • 调用JS函数

事件名称:scroll

使用addEventListener或onscroll树形绑定事件处理函数

监听整个网页滚动

给window对象绑定scroll事件

1
2
3
4
5
6
7
8
9
10
<div style="height: 6000px;">
1
</div>

<script>
window.onscroll = function(event) {
console.log('滚动');
};
</script>

1
window.addEventListener('scroll', function(){})

当滚动页面时,可以发现scroll函数一直在触发,控制台一直在打印

滚动偏移量

window对象有两个与滚动事件相关的属性scrollX或scrollY,返回当前页面水平与垂直滚动的像素数,返回double值,若没有滚动,默认为0

1
2
3
4
5
6
7
8
9
<div style="width: 3000px; height: 6000px;">
1
</div>

<script>
window.addEventListener('scroll',(event) => {
console.log(window.scrollX, window.scrollY)
});
</script>

加载事件

加载外部资源完毕时触发的事件

不仅可以监听整个页面资源加载完毕,也可以针对某个资源绑定load事件

事件名:load

1
window.addEventListener('load', function(){})

当初始HTML文档被完全加载和解析完成后,还会触发另一个事件DOMContentLoaded,而无需等待样式表与图像等完全加载

事件名:DOMContentLoaded

1
window.addEventListener('DOMContentLoaded', function(){})

获取元素大小与位置

scroll
  • 使用scrollTop与scrollLeft设置或获取元素内容垂直滚动与从左边缘滚动的偏移数

  • 使用scrollWidth与scrollHeight获取内容总宽高(不包括滚动条)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<script>
let control = document.querySelector('#control');

control.addEventListener('click', function (e) {
// 获取滚动容器元素
let div = document.getElementById('scrollDemo');
// 获取点击的目标元素
let target = e.target;
// 处理每个按钮的行为
switch (target.id) {
case 'btnScrollLeft':
div.scrollLeft += 20;
break;

case 'btnScrollTop':
div.scrollTop += 20;
break;
}
});
</script>

offset
  • 使用offsetWidth与offsetHeight获取元素自身宽高,包含自身设置的宽高,padding,border等

  • 使用offsetLeft与offsetTop获取元素距离自己定位父级元素的左、上距离,均只读

client
  • 使用clientWidth与clientHeight获取元素的可见部分宽高(即不包括边框、进度条等)

  • 使用clientLeft与clientTop获取左边框与上边框宽度,均只读

同时会在窗口尺寸改变时触发resize事件

1
window.addEventListener('resize', function(){})

定时器

JS提供定时执行代码的功能,叫做定时器主要由setTimeout()和setInterval()两个函数来完成,它们向任务队列添加定时任务

setTimeout()

setTimeout()用来指定某个函数或某段代码在多少毫秒后执行,返回一个整数表示定时器的编号,接受两个参数,第一个参数是要推迟执行的函数名或一段代码,第二个参数是推迟执行的毫秒数

1
2
3
4
5
6
7
<body>
<script>
setTimeout(function(){
console.log("hello");
},3000);
</script>
</body>

注意,如果回调函数是对象的方法,那么setTimeout使得方法内部的this关键字指向全局环境,而不是定义时所在的那个对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<body>
<script>
var name = "a";
var user = {
name: "b",
getName: function(){
setTimeout(function(){
console.log(this.name);
},3000);
}
}
user.getName();

</script>
</body>

此时打印的是a

结局方法就是将this存储在临时变量里,使用临时变量读取成员变量

定时器可以取消:

1
2
var id = setTimeout(f, 1000);
clearTimeout(id);

setInterval()

用法与上面一致,但setInterval指定某个任务每隔一段时间执行一次,setInterval返回一个该定时器的id

1
2
3
4
5
6
7
8
9
10
11
12
<body>
<script>
var user = {

var i = 0;
setInterval(function(){
i++;
console.log(i);
}, 1000);

</script>
</body>

同样可以使用clearInterval(定时器id)清楚

实例化

使用new关键字对对象实例化,如时间对象

时间对象

  • 获得当前时间:let date = new Date();
  • 获得指定时间:let date = new Date(指定时间)

其他方法如下:

时间戳

获取方法:

  • 获取时间戳,括号内可以指定时间

    1
    2
    let date = new Date();
    console.log(date.getTime());
  • +new Date():上面的简写

  • Date.now():无需实例化,但是只能得到当前时间戳

BOM

BOM是浏览器对象模型,其中windows对象是浏览器内置的全局对象,下面包含了navigator、location、document、history、screen 5个属性

window对象

其中document是实现DOM的基础

依附于window对象的属性与方法使用时可以省略window

JS执行机制

JS是单线程,前一个任务结束才会执行后一个任务,如果JS执行时间过长,就会导致页面的渲染不连贯,有阻塞的感觉

因此HTML5开始,允许JS创建多个线程,出现了同步与异步

同步任务都在主线程上,形成一个执行栈

异步任务通过回调函数实现,一般有以下三种类型

  • 普通事件
  • 资源加载
  • 定时器

异步任务相关添加到任务队列中

JS的执行顺序如下:

  1. 先执行执行栈中的同步任务
  2. 异步任务放入任务队列
  3. 一旦执行栈中的所有同步任务执行完毕,系统就会按序读取任务队列中的异步任务,被读取的异步任务结束等待,进入执行栈开始执行

这种机制被称为事件循环

location对象

location拆分并保存了url地址的各个部分

  • herf属性获取完整url地址
  • searchs属性获取地址中携带的参数,即?后面的部分
  • hash属性获取地址中的哈希值,即#后面的部分
  • reload()方法用于刷新当前页面,传入true时表示强制刷新

navigator记录了浏览器自身的相关信息

  • userAgent属性用于检测浏览器版本与平台
1
2
3
4
5
6
7
8
9
10
11
12
//检测userAgent(浏览器信息)
!(function(){
constuserAgent=navigator.userAgent
//验证是否为Android或iPhone
constandroid=userAgent.match(/(Android);?[\s\/]+([\d.]+)?/)
constiphone=userAgent.match(/(iPhone\sOS)\s([\d_]+)/)
//如果是Android或iPhone,则跳转至移动站点
if(android|| iphone){
location.href='http://m.itcast.cn'
}
})()

history对象

history与浏览器地址栏的操作相对应

  • back()方法用于后退
  • forward()方法用于前进
  • go()方法用于前进后退若干页面,参数正数表示前进若干,负数表示后退若干

本地存储

localStorage

  • 可以将数据暂存于用户浏览器中

  • 生命周期永久生效,除非手动删除,否则关闭页面也会存在

  • 可以多窗口共享

  • 以键值对形式存储使用

方法如下:

  • 存储:localStorage.setItem(key, value)

  • 获取:localStorage.getItem(key)

  • 删除:localStorage.removeItem(key)

复杂数据类型需要转为JSON字符串

  • 对象转为JSON,存储在本地:JSON.stringify(数据)
  • JSON转换为对象,取出使用:JSON.parse(JSON)

sessionStorage

  • 生命周期为关闭浏览器窗口
  • 在同一窗口下数据可以共享
  • 键值对形式存储使用,用法与localStorage基本相同

防抖

防抖操作是优化性能的一种操作,对于短时间内连续触发的事件,防抖使得在某个时间期限内,事件处理函数只执行一次

滚动监听防抖

我们可以发现,滚动监听中的默认执行频率太高,会浪费性能

思路

在第一次触发事件时,不立即执行函数,而是给出一个期限值

  • 若在200ms内没有再触发滚动事件,就执行函数
  • 若再200ms内再次触发滚动事件,则当前计时取消,重新开始计时
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<script>
function debounce(fn, delay){
var timer = null;
return function(){
if (timer){
clearTimeout(timer)
}

timer = setTimeout(fn,delay)
}
}
window.onscroll = debounce(scrollHandle,200)
function scrollHandle(){
var scrollTop = document.documentElement.scrollTop;
console.log(scrollTop);
}
</script>

节流

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<script>
function throttle(fn, delay){
var valid = true;
return function(){
if (!valid){
return false;
}
valid = false;
setTimeout(function(){
fn()
valid = true;
},delay)
}
}
window.onscroll = throttle(scrollHandle,2000)
function scrollHandle(){
var scrollTop = document.documentElement.scrollTop;
console.log(scrollTop);
}
</script>

应用

  • 搜索框input事件,支持实时搜索时可以使用节流,或实现某个输入间隔大于某个值
  • 页面resize事件,常用于需要页面适配时,需要根据最终呈现的页面进行DOM渲染,一般使用防抖,因为只需要判断最后一次的变化

ECMAScript

ECMAScript是JS的一种规范

Babel转码器

该转码器可以将ES6代码转为ES5代码

通过在.babeirc中进行配置,用来设置转码规则与插件,

需要下载babel-env环境后配置如下内容

1
2
3
4
5
6
{
"presets": [
"@babel/env"
],
"plugins": []
}

用法如下:

1
2
3
4
5
6
# 转码结果输出到标准输出
npx babel example.js
# 转码结果写入文件
npx babel example.js -o compiled.js
# 整个目录转码
npx babel src -d lib

对象解构赋值

结构可以用于对象,对象属性没有次序,变量必须与属性同名,才能取到正确值

1
2
3
4
5
var user = {
name:"a",
age:10
}
let{name, age} = user

常用于将现有对象方法复制到某个变量

1
let{log}=console

字符串扩展

  • 允许采用\uxxxx形式来用unicode码点表示一个字符

  • 可以使用for…of循环遍历

1
2
3
for (let i of "abcd"){
console.log(i);
}
  • includes():返回bool,表示是否找到参数字符串,第二个参数为开始搜索的位置

  • startsWith():返回bool,表示参数字符串是否在原字符串的头部,第二个参数为开始搜索的位置

  • endsWith():返回bool,表示参数字符串是否在原字符串的尾部,第二个参数为开始搜索的位置

  • repeat():返回一个新字符串,表示将原字符串重复n次

  • padStart():若某个字符串不够指定长度,会在头部自动补全

  • padEnd():若某个字符串不够指定长度,会在尾部自动补全

  • trimStart():消除字符串头部空格

  • trimEnd():消除字符串尾部空格

  • at():接受一个整数作为参数,返回参数指定位置的字符,支持负索引

    若超出字符串范围,返回undefined

扩展运算符

由...组成的运算符,将一个数组转为用逗号分隔的参数序列

有了拓展运算符,就不需要使用apply方法将数组转为函数参数了

1
console.log(Math.max(...arr));

可以使用扩展运算符合并数组

1
console.log([...arr1, ...arr2]);

数组扩展

  • Array.form():将类数组转换为真正的数组

    常见类数组如下:

    • arguments:函数中的可选参数,即在不需要传参的函数中传参时的参数,存在arguments中
    • 元素集合:如document中选择所有指定标签组成的集合
    • 类似数组的对象:一个对象,但是键是012下标,且存在一个length值

​ 类数组只能读取元素,长度,不能使用数组方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<script>
// arguments
function add(){
console.log(arguments);
var re = Array.from(arguments);
re.push(40);
console.log(re);
}
add(10,20,30);

// 元素集合
let titles = document.querySelectorAll('h3');
console.log(Array.from(titles));

// 类数组的对象
var user = {
"0": '小明',
"1": '小红',
"2": '小刚',
length: 3
}
console.log(Array.from(user));
</script>
  • Array.of():用于将一组值转化为数组
1
Array.of(3,11,8);

对象扩展

  • 简介表示:ES6允许在大括号内直接写入变量和函数,作为对象的属性和方法,更简洁
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<script>
let name = "小明";

const user={
// 相同值的变量可以直接省略
name,
age: 18,
// 函数的简写
getName(){
console.log(this.name);
},
// 返回值的简写
getInfo(){
return {name, age};
}
}
</script>
  • 属性名表达式:允许字面量定义对象时,用表达式作为对象的属性名,即把表达式放到方括号内
1
2
3
4
5
6
<script>
let id = "a";
let user = {
[id]:"111"
}
</script>

此时相当于a对应的111

  • 对象扩展运算符:...也可以用于对象

箭头函数

简化函数

1
2
3
4
5
6
7
8
9
10
11
12
13
<script>
// 多个参数
let f = (x,y) => x + y;
// 单个参数
let f2 = x => x * 2;
// 无参数
let f3 = () => console.log('hello');
// 多行语句
let f4 = (x,y) => {
let sum = x + y;
return sum * 2;
};
</script>

由于大括号被解释为代码块,所以若箭头函数直接返回一个对象,必须在外面加括号

用处:简化回调函数

1
2
3
4
5
6
7
<script>
// 简化回调
let arr = [10,20,30];
arr.map(item=>{
console.log(item);
})
</script>

注意:箭头函数没有自己的this对象,内部的this就是定义时上层作用域中的this

set

定义

集合,成员唯一

  • Set()本身是一个构造函数
  • Set()函数可以接受一个数组作为参数
  • 使用add(x)向set中添加成员
1
2
3
const s = new Set(); // 直接构造
const s = new Set([1,2,3]); // 数组构造
[2,3,4].forEach(x=>s.add(x)); // 添加元素
  • 数组去除重复成员/字符
1
2
[...new Set(array)];
[...new Set('abcccd')].join('');
  • 注意,向set加入值时不会转换数据类型

方法

  • add():添加元素
  • delete():删除某个元素,返回布尔值,表示是否删除
  • has():返回一个布尔值,表示该值是否为set的成员
  • clear():清除所有成员
赞助喵
非常感谢您的喜欢!
赞助喵