引入

JavaScript 是一种轻量级、跨平台和解释编译的编程语言,也称为网页脚本语言。它以开发网页而闻名,但是许多非浏览器环境也可以使用它。JavaScript 可用于客户端开发以及服务器端开发。它既是命令式又是声明式语言。作为前端三件套之中唯一有编程逻辑的语言,JavaScript 常常用于页面交互、实现一些复杂的动画以及数据传输等。


浏览器工作原理

浏览器分为两个部分:渲染引擎和 JS 引擎

  • 渲染引擎:用来解析HTML和CSS,俗称内核,比如 chrome 的blink,老版本的 webkit
  • JS 引擎:也成为 JS 解释器。用来读取网页中的 JavaScript 代码,对其进行后台处理,比如 chrome 浏览器的 v8

注意:浏览器本身不会执行 JS 代码,而是通过内置 JavaScript 引擎(解释器)来执行JS代码,JS 引擎执行代码时会逐行解释每一行源码(转化为机器语言),然后由计算机去执行


JS 组成

ECMAScript

ECMAScript 是由 ECMA 国际(原欧洲计算机制造商协会)进行标准化的一门编程语言,它规定了 JS 的编程语法和基础核心知识,是所有浏览器厂商共同遵守的一套 JS 语法工业标准

DOM

DOM(Document Object Model,文档对象模型)是 W3C 组织推荐的处理可扩展标记语言(HTML或XML)的标准编程接口。通过此接口我们可以很容易的对页面上的元素的属性进行操作

BOM

BOM(Browser Object Model,浏览器对象模型)是一种独立于内容的,与浏览器窗口进行互动的对象结构。通过 BOM 可以操作浏览器窗口,比如弹出框、浏览器跳转、获取窗口大小、滚动条、分辨率等


JS 数据类型及运算符

JS 是一种弱类型的语言,也就是说某一个变量被定义类型之后,该变量可以根据环境变化自动进行转换,不需要强制转换

字符串

  1. 使用单引号或双引号包裹

  2. \ 为转义字符,通过 \ ,可以打印 Unicode Ascll 字符等

  3. 多行字符串编写

1
2
3
4
5
var msg = `
hello
world
你好
世界`
  1. 模板字符串
1
2
3
4
5
6
7
let name = 'Pillage'
let age = 19

let msg = `你好啊, ${name}`
console.log(msg)

> 你好啊, Pillage
  1. 字符串长度
1
str.length
  1. 可变性:不可变
  2. 大小写转化(对中文没有影响)
1
2
.toUpperCase();
.toLowerCase();
  1. 寻找索引
1
.indexOf('t')
  1. 截取字符串
1
2
.substring(1)    //从下标为1开始截取,包括下标为1的,一直截到最后
.substring(1, 3) //前闭后开

数组

注意:for in 是遍历下标, for of 才是遍历数组具体的值

Array 可以包含任意的数据类型

1
let array = [1, 2, 3, "Hello"]
  1. 长度
1
array.length

注意:此属性可读可写,即可以通过赋值修改数组的大小

  1. 寻找索引
1
array.indexOf(1)
  1. 截取数组,返回一个新数组
1
array.slice()

类似于 String 中的 substring

  1. 操作元素(在尾部)
1
2
array.push()
array.pop()
  1. 操作元素(在头部)
1
2
array.unshift   //压入到头部
array.shift //弹出头部的一个元素
  1. 排序
1
array.sort()
  1. 元素反转
1
array.reverse()
  1. 数组拼接
1
array.concat([1, 2, 3])

注意:concat() 并不会修改原数组,只会返回一个连接后的新数组

  1. 连接数组

打印拼接数组,使用特定的字符串连接

1
array.join('')
  1. 多维数组

类似于 Python。例如二维数组就是一个普通一维数组中的每一个元素又是一个一维数组


对象

定义:

1
2
3
4
5
6
7
8
9
10
11
12
var 对象名 = {
属性名:属性值,
属性名:属性值,
...
属性名:属性值
}

var person = {
name: "pillage",
age: 18,
score: 100
}

JS 中,大括号可以表示一个对象,用键值对描述属性,多个属性之间用逗号隔开,最后一个不需要逗号

JS 中,所有的键都是字符串,值可以是任意类型

  1. 对象赋值
1
person.age = 19
  1. 动态增删属性
1
2
3
4
5
//动态删减 name 属性
delete person.name

//动态增加 sex 属性,只需要给新属性赋值即可
person.sex = "男"
  1. 判断某个属性值是否在这个对象中 xxx in xxx

注意:因为继承机制的存在,所以父类有的属性,子类也会被判定为有 如:

1
2
3
4
5
'toString' in person
> true

'age' in person
> true
  1. 判断某个属性是否在这个对象本身中 hasOwnProperty
1
2
3
4
5
person.hasOwnProperty('toString')
> false

person.hasOwnProperty('age')
> true

注意:Map 和 Set 是 ES6 新特性


Map

定义:

1
var map = new Map([['tom', 100], ['jerry', 99]])

用二维数组的形式可以直接 new 出来

元素操作:

1
2
3
var name = map.get('tom') //通过键获取值
map.set('admin', 1000) //修改值,也可以增加新值
map.delete('tom') //删除操作

Set

无序不重复集合,Set 会自动进行去重操作

定义:

1
var set = new set([1, 2, 3])

操作元素:

1
2
3
set.add(4)    //增加元素
set.delete(1) //删除元素
set.has(1) //查找元素是否存在

遍历

forEach 循环

1
2
3
4
let array = [5, 6, 7]
array.forEach(function(value) {
console.log(value)
})

iterator 迭代器

遍历数组:

1
2
3
4
5
6
7
8
9
10
let array = [5, 6, 7]
//遍历下标,输出结果为 0 1 2
for (let i in array) {
console.log(i)
}
console.log("==========")
//遍历数组的值,输出结果为 5 6 7
for (let i of array) {
console.log(i)
}

遍历 Map 和 Set:

1
2
3
4
5
6
7
8
let map = new Map([['Tom', 100], ['Jerry', 99]])
for (let i of map) {
console.log(i)
}
let set = new Set([3, 4, 5])
for (let i of set) {
console.log(i)
}

变量转换

通过 typeof 变量名 可以输出变量的类型

  1. String 转数字:
1
2
parseInt();//转为整数
parseFloat();//转为浮点数
  1. 强制类型转换
1
2
3
Boolean(value);//把给定的值转换成Boolean型;
Number(value);//把给定的值转换成数字(可以是整数或浮点数);
String(value);//把给定的值转换成字符串。

注意:用这三个函数之一转换值,将创建一个新值,存放由原始值直接转换成的值。这可能会造成意想不到的后果。


逻辑运算符

与 && 或 || 非!

比较运算符:

1
2
3
=      //赋值运算符
== //等于(类型不一样,值一样,也会为 true)
=== //绝对等于(必须类型一样,值也一样,结果才为 true)

注意:

NaN 与任何数值都不相等,包括自己

1
NaN === NaN      //false

只能通过 isNaN(NaN) 这个方法来判断一个数是否为 NaN


JS 常用输入输出方法

方法名 方法的作用 参数解释
alert(msg) 浏览器弹出带有信息的警示框 msg:要显示的信息
console.log(meg) 浏览器控制台打印信息 msg:要打印的信息
console.dir(v) 控制台打印元素对象,从而查看里面的属性和方法 v:变量名
prompt(msg) 浏览器弹出带有一段消息的输入框,获取输入 msg:显示消息,返回值:用户输入内容
confirm(msg) 浏览器弹出带有一段消息的确认框 msg:显示消息,返回值:bool类型用户是否确认

DOM 基础

基本操作

关于 dom 的基操,主要内容有 创建、增、删、改、查、属性操作、事件操作

  1. 创建
1
2
3
document.write
innerHTML
createElement
1
2
appendChild
insertBefore
1
removeChild
1
2
3
4
5
主要修改 dom 的元素属性,dom 元素的内容、属性,表单的值等
1、修改元素属性:src、href、title 等
2、修改普通元素内容:innerHTML、innerText
3、修改表单元素:value、type、disable 等
4、修改元素样式:style、className
1
2
3
4
主要获取查询 dom 的元素
1、DOM 提供的 API 方法:getElementById,getElementByTagName 古老用法 不推荐
2、H5提供的新方法:querySelector,querySelectorAll
3、利用节点操作获取元素:父(parentNode)、子(children)、兄(previousElementSibling、nextElementSibling)
  1. 属性操作
1
2
3
4
主要针对于自定义属性
1、setAttribute
2、getAttribute
3、removeAttribute
  1. 事件操作

给元素注册事件,采取 事件源.事件类型 = 事件处理程序

鼠标事件 触发条件
onclick 鼠标点击左键触发
onmouseover 鼠标经过触发
onmouseout 鼠标离开触发
onfocus 获得鼠标焦点触发
onblur 失去鼠标焦点触发
onmousemove 鼠标移动触发
momouseup 鼠标弹起触发
onmousedown 鼠标按下触发

DOM 获取元素

1
2
3
4
5
6
7
8
9
10
11
12
document.getElementById();//属性名
document.getElementByTagName();//标签名,如p,div,li 返回的是一个伪数组
element.getElementByTagName();//返回element为父元素的指定标签的对象,父元素必须为单个元素

//获取特殊元素
document.body;//获取body标签
document.documentElement;//获取HTML标签

//HTML5新增 ie678不支持
document.getElementByClassName();//通过类名获得对象
document.querySelector();//通过CSS选择器获得对象,返回指定选择器的第一个元素对象
document.querySelectorAll();//返回所有满足选择器的对象,伪数组

事件

事件三要素:事件源、事件类型、事件处理程序

执行事件的步骤:

  1. 获取事件源
  2. 注册事件(绑定事件)
  3. 添加事件处理程序(采取函数赋值形式)
1
2
3
4
5
6
7
<button id="btn">按钮</button>
<script>
var btn = document.querySelector("#btn");
btn.onclick = function() {
console.log("click事件");
}
</script>

this 可以指向事件函数的调用者

操作元素

改变元素的内容

1
2
对象.innerText = ;
对象.innerHTML = ;//使用最多,是W3C推荐标准

这两个属性也能读取对象内的内容

区别:

  • innerText 不能识别 HTML 标签,innerHTML 能识别
  • innerText 在读取内容的时候,会自动去除空格和换行,而 innerHTML 会保留

操作元素属性

1
对象.属性名 = ;

也就是可以直接修改

修改表单属性时需要用到表单特有的属性(比如要修改输入框的内容用 inner HTML 就不好使了):

1
type value checked selected disabled

样式属性的操作

通过 JS 可以修改元素的大小、颜色、位置等属性。

1
2
1. element.style          //行内样式操作 如:div.style.backgroundColor = "purple";
2. element.className //类名样式操作
  1. element.style

    • 属性采用的是驼峰命名法,与CSS不同,如 fontSize backgroundColor
    • JS 修改 style 样式时,产生的是行内样式,权重比 CSS 更高

    如果要修改的样式比较少,或者功能比较简单的时候,可以这样用

  2. element.className

    • 修改元素的类名
    • 可以提前把要修改的内容写入 CSS 中,需要改变时应用该 CSS
    • 会直接更改类名,也就是覆盖掉以前的类名
    • 如果要保留以前的类名,可以在要修改的类名前加上”以前的类名 “(别忘了空格)。(其实原理就是一个元素可以又多个类名)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<style>
div{
width: 10px;
height: 10px;
background-color: purple;
}
.change{
width: 200px;
height: 400px;
background-color: pink;
margin: auto 0;
}
</style>
<script>
window.onload = function() {
var div = document.querySelector("div");
div.onclick = function() {
div.className = "change";
}
}
</script>

鼠标事件

  1. 焦点事件

鼠标点击焦点事件 onfocus

失去鼠标焦点事件 onblur

(鼠标焦点是指鼠标点一下,失去焦点是指鼠标点一下其他地方)

1
2
3
4
5
6
7
8
var input = document.querySelector("input");

input.onfocus = function() {
console.log("得到了焦点");
}
input.onblur = function() {
console.log("失去了焦点");
}

  1. 移入移出事件

鼠标移入事件 onmouseover

鼠标移出事件 onmouseout

1
2
3
4
5
6
7
8
9
window.onload = function() {
var box = document.querySelector(".box");
box.onmouseover = function() {
this.style.backgroundColor = "red";
}
box.onmouseout = function() {
this.style.backgroundColor = "aqua";
}
}

总结

202112252124168

小思想-排他思想

当用 for 循环对多个元素绑定同一事件时,如果想要某一个元素实现某个样式,则可以:

  1. 清除所有元素的样式
  2. 给当前的元素设置样式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
<button>按钮4</button>
<button>按钮5</button>

<script>
var btns = document.querySelectorAll("button");
for (var i = 0; i < btns.length; i++) {
btns[i].onclick = function() {
//先清除其他元素的格式,再给自己的元素设置格式
for (var j = 0; j < btns.length; j++) btns[j].style.backgroundColor = "";
this.style.backgroundColor = "pink";
}
}
</script>

操作自定义属性

元素自定义属性通常以 data- 开头,如:<p data-time=”20”></p>

  1. 获取元素的属性
1
2
3
4
5
element.属性
- 获取元素的内置属性

element.getAttribute('属性')
- 获取自定义属性和内置属性
  1. 设置元素属性
1
2
element.属性 = "值"
element.setAttribute('属性', '值')
  1. 移除元素属性
1
element.removeAttribute('属性')
  1. H5 新增获取自定义属性
1
2
3
4
5
6
7
8
如果有一个元素为:<a data-index="1"></a>

1. 兼容性获取:element.getArribute('data-index');

2. H5 新增:element.dataset.index 或者 element.dataset['index']
- 只能获取 data- 开头的
- 开头的 data- 省略,如果后面有多个 - 连接的单词,则获取的时候采取驼峰命名法
- ie11 才开始支持

节点操作

简述

一般的,节点至少拥有 nodeType(节点类型)、nodeName(节点名称)和 nodeValue(节点值)这三个基本属性

  • 元素节点 nodeType 为 1
  • 属性节点 nodeType 为 2
  • 文本节点 nodeType 为 3(文本节点包含文字,空格,换行等)

节点操作的主要对象是元素节点

获取父子节点

  1. 父级节点
1
node.parentNode
  • parentNode 返回元素节点的最近的一个父节点(亲爸爸)
  • 如果没有找到返回 null
  1. 子节点
1
parentNode.childNodes
  • 返回值包含了元素的所有子节点,包括元素节点和文本节点
  • 如果只想获取元素节点,则应 专门处理
1
2
3
4
5
6
var ul = document.querySelector('ul');
for (var i = 0; i < ul.childNodes.length; i++) {
if (ul.childNodes[i].nodeType === 1) {
console.log(ul.childNodes[i]);
}
}
  1. 子元素节点
1
parentNode.children
  • children 是一个只读属性,只返回子元素节点,其余节点不返回
  • 非标准的,但是得到了很多浏览器的支持
  1. 第一个/最后一个 子节点
1
2
3
4
5
//第一个子节点
parentNode.firstChild

//最后一个子节点
parentNode.lastChild
  • 节点包含元素节点和文本节点
  1. 第一个/最后一个 子元素节点
1
2
3
4
//第一个子元素节点
parentNode.firstElementChild
//最后一个子元素节点
parentNode.lastElementChild
  • 这两个方法有兼容性问题,ie9 以上才支持

  • 所以可以这样写

1
2
3
4
//第一个子元素节点
parentNode.children[0]
//最后一个子元素节点
parentNode.children[parentNode.children.length - 1]

获取兄弟关系

  1. 兄弟节点
1
2
3
4
//获取元素的下一个兄弟节点,包含所有节点
node.nextSibling
//获取元素的上一个兄弟节点,包含所有节点
node.previousSibling
  1. 兄弟元素节点
1
2
3
4
//下一个兄弟元素节点
node.nextElementSibling
//上一个兄弟元素节点
node.previousElementSibling
  • 兼容性问题,ie9 以上才支持

创建节点

1
document.createElement('tagName')
  • document.createElement() 方法创建由 tagName 指定的 HTML 元素。也称为动态创建元素节点
  • 只是创建并没有添加

添加节点

  1. 在后面追加
1
node.appendChild(child)
  • 将一个节点添加到指定父节点的子节点列表的末尾,类似于 css 中的 after 伪元素
  • 也称为追加元素
  1. 插入节点
1
node.insertBefore(child, 指定元素)
  • 将一个节点插入到父节点的指定子节点的前面

删除节点

1
node.removeChild(childNode)

复制节点

1
node.cloneNode()
  • 克隆相当于新建,克隆后需要添加操作
  • 如果括号参数为空或者 false,则是浅拷贝,即只克隆复制节点本身,不克隆里面的子节点
  • 如果括号里面为 true,则是深拷贝,既复制节点本身,也复制里面的子节点

三种动态创建元素的区别

  • document.write()

    • 是直接将内容写入页面的内容流,但是会导致页面全部重绘
  • element.innerHTML

    • 是将内容写入某个 DOM 节点,不会导致页面全部重绘
    • 创建多个元素效率更高(不要采取拼接字符串,采取数组形式拼接),结构稍微复杂
  • document.createElement()

    • 创建多个元素效率会稍微低一些,但是结构更清晰

DOM 高级

注册事件(绑定事件)

概述

  • 给元素添加事件,称为注册事件或者绑定事件
  • 注册事件有两种方式:传统方式和方法监听注册方式
  1. 传统注册方式
    • 利用 on 开头的事件,如 onclick
    • <button onclick = “alert(‘hi’)”></button>
    • btn.onclick = function() { }
    • 特点:注册事件的唯一性
    • 同一个元素同一个事件只能设置一个处理函数,最后注册的处理函数将会覆盖前面注册的处理函数
  2. 方法监听注册方式
    • w3c 标准推荐方式
    • addEventListener() 是一个方法
    • ie9 之前的 ie 不支持此方法,可使用 attachEvent() 代替
    • 特点:同一个元素同一个事件可以注册多个监听器
    • 按注册顺序依次执行

addEventListener 事件监听方式

1
eventTarget.addEventListener(type, listener, [useCapture])

此方法会将指定的监听器注册到 eventTarget(目标对象)上,当该对象触发指定的事件时,就会执行事件处理函数

同一个元素,同一个事件可以添加多个侦听器

该方法接收三个参数:

  • type:事件类型字符串(别忘了加引号),比如 click, mouseover, 等,注意不用带 on
  • listener:事件处理函数,事件发生时,会调用该监听函数
  • useCapture:可选参数,是一个布尔值
    • 当为 true 时,事件处于捕获阶段
    • 当为 false 或者 省略 时,事件处于冒泡阶段
1
2
3
btn2.addEventListener('click', function() {
alert("使用addEventListener添加点击事件")
})

attachEvent 事件监听方式(了解)

此方法只有 ie9 及以前的浏览器才支持,chrome 等浏览器不支持

1
eventTarget.attachEvent(eventNameWithOn, callback)

参数:

  • eventTarget:目标对象
  • eventNameWithOn:事件类型字符串,比如 onclick, onmouseover,等,要带 on
  • callback:事件处理函数

删除事件(解绑事件)

  1. 传统方式删除事件

.onclick = null;

1
2
3
4
5
//如:想让一个div点击一下以后就不能再次点击
div.onclick = function() {
alert("111");
div.onclick = null;
}
  1. 删除方法监听注册的事件

eventTarget.removeEventListener(type, listener, [useCapture])

1
2
3
4
5
6
7
//如:想让一个div点击一下以后就不能再次点击
div.addEventListener("click", fn) //fn不需要加小括号

function fn() {
alert("222")
div.removeEventTarget("click", fn);
}
  1. 删除 attachEvent 事件

eventTarget.detachEvent(eventNameWithOn, callback)

1
2
3
4
5
6
7
//如:想让一个div点击一下以后就不能再次点击
div.attachEvent("onclick", fn);

function fn() {
alert("333")
div.detachEvent("onclick", fn);
}

DOM 事件流

事件发生时会在元素节点之间按照特定的顺序进行传播,这个传播过程叫做 DOM 事件流

  • JS 代码只能执行捕获或者冒泡中的一个阶段
  • onclick 和 attachEvent 只能得到冒泡阶段
  • addEventListener 的第三个参数如果为 true 表示在捕获阶段调用事件处理程序,如果为 false 或 不写则表示在冒泡阶段调用事件处理程序
  • 有些事件是没有冒泡的,如:onblur、onfocus、onmouseenter、onmouseleave