JavaScript 学习笔记
JavaScript 是一种轻量级、跨平台和解释编译的编程语言,也称为网页脚本语言。它以开发网页而闻名,但是许多非浏览器环境也可以使用它。JavaScript 可用于客户端开发以及服务器端开发。它既是命令式又是声明式语言。作为前端三件套之中唯一有编程逻辑的语言,JavaScript 常常用于页面交互、实现一些复杂的动画以及数据传输等。
浏览器分为两个部分:渲染引擎和 JS 引擎
- 渲染引擎:用来解析HTML和CSS,俗称内核,比如 chrome 的blink,老版本的 webkit
- JS 引擎:也成为 JS 解释器。用来读取网页中的 JavaScript 代码,对其进行后台处理,比如 chrome 浏览器的 v8
注意:浏览器本身不会执行 JS 代码,而是通过内置 JavaScript 引擎(解释器)来执行JS代码,JS 引擎执行代码时会逐行解释每一行源码(转化为机器语言),然后由计算机去执行
ECMAScript 是由 ECMA 国际(原欧洲计算机制造商协会)进行标准化的一门编程语言,它规定了 JS 的编程语法和基础核心知识,是所有浏览器厂商共同遵守的一套 JS 语法工业标准
DOM(Document Object Model,文档对象模型)是 W3C 组织推荐的处理可扩展标记语言(HTML或XML)的标准编程接口。通过此接口我们可以很容易的对页面上的元素的属性进行操作
BOM(Browser Object Model,浏览器对象模型)是一种独立于内容的,与浏览器窗口进行互动的对象结构。通过 BOM 可以操作浏览器窗口,比如弹出框、浏览器跳转、获取窗口大小、滚动条、分辨率等
JS 是一种弱类型的语言,也就是说某一个变量被定义类型之后,该变量可以根据环境变化自动进行转换,不需要强制转换
使用单引号或双引号包裹
\ 为转义字符,通过 \ ,可以打印 Unicode Ascll 字符等
多行字符串编写
1
2
3
4
5
var msg = `
hello
world
你好
世界`
- 模板字符串
1
2
3
4
5
6
7
let name = 'Pillage'
let age = 19
let msg = `你好啊, ${name}`
console.log(msg)
> 你好啊, Pillage
- 字符串长度
1
str.length
- 可变性:不可变
- 大小写转化(对中文没有影响)
1
2
.toUpperCase();
.toLowerCase();
- 寻找索引
1
.indexOf('t')
- 截取字符串
1
2
.substring(1)
.substring(1, 3)
注意:for in 是遍历下标, for of 才是遍历数组具体的值
Array 可以包含任意的数据类型
1
let array = [1, 2, 3, "Hello"]
- 长度
1
array.length
注意:此属性可读可写,即可以通过赋值修改数组的大小
- 寻找索引
1
array.indexOf(1)
- 截取数组,返回一个新数组
1
array.slice()
类似于 String 中的 substring
- 操作元素(在尾部)
1
2
array.push()
array.pop()
- 操作元素(在头部)
1
2
array.unshift
array.shift
- 排序
1
array.sort()
- 元素反转
1
array.reverse()
- 数组拼接
1
array.concat([1, 2, 3])
注意:concat() 并不会修改原数组,只会返回一个连接后的新数组
- 连接数组
打印拼接数组,使用特定的字符串连接
1
array.join('')
- 多维数组
类似于 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
person.age = 19
- 动态增删属性
1
2
3
4
5
delete person.name
person.sex = "男"
- 判断某个属性值是否在这个对象中 xxx in xxx
注意:因为继承机制的存在,所以父类有的属性,子类也会被判定为有 如:
1
2
3
4
5
'toString' in person
> true
'age' in person
> true
- 判断某个属性是否在这个对象本身中 hasOwnProperty
1
2
3
4
5
person.hasOwnProperty('toString')
> false
person.hasOwnProperty('age')
> true
注意:Map 和 Set 是 ES6 新特性
定义:
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 会自动进行去重操作
定义:
1
var set = new set([1, 2, 3])
操作元素:
1
2
3
set.add(4)
set.delete(1)
set.has(1)
1
2
3
4
let array = [5, 6, 7]
array.forEach(function(value) {
console.log(value)
})
遍历数组:
1
2
3
4
5
6
7
8
9
10
let array = [5, 6, 7]
for (let i in array) {
console.log(i)
}
console.log("==========")
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 变量名 可以输出变量的类型
- String 转数字:
1
2
parseInt();
parseFloat();
- 强制类型转换
1
2
3
Boolean(value);
Number(value);
String(value);
注意:用这三个函数之一转换值,将创建一个新值,存放由原始值直接转换成的值。这可能会造成意想不到的后果。
与 && 或 || 非!
比较运算符:
1
2
3
=
==
===
注意:
NaN 与任何数值都不相等,包括自己
1
NaN === NaN
只能通过 isNaN(NaN) 这个方法来判断一个数是否为 NaN
关于 dom 的基操,主要内容有 创建、增、删、改、查、属性操作、事件操作
- 创建
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
2
3
4
主要针对于自定义属性
1、setAttribute
2、getAttribute
3、removeAttribute
- 事件操作
给元素注册事件,采取 事件源.事件类型 = 事件处理程序
1
2
3
4
5
6
7
8
9
10
11
12
document.getElementById();
document.getElementByTagName();
element.getElementByTagName();
document.body;
document.documentElement;
document.getElementByClassName();
document.querySelector();
document.querySelectorAll();
事件三要素:事件源、事件类型、事件处理程序
执行事件的步骤:
- 获取事件源
- 注册事件(绑定事件)
- 添加事件处理程序(采取函数赋值形式)
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 = ;
这两个属性也能读取对象内的内容
区别:
- innerText 不能识别 HTML 标签,innerHTML 能识别
- innerText 在读取内容的时候,会自动去除空格和换行,而 innerHTML 会保留
1
对象.属性名 = ;
也就是可以直接修改
修改表单属性时需要用到表单特有的属性(比如要修改输入框的内容用 inner HTML 就不好使了):
1
type value checked selected disabled
通过 JS 可以修改元素的大小、颜色、位置等属性。
1
2
1. element.style
2. element.className
element.style
- 属性采用的是驼峰命名法,与CSS不同,如 fontSize backgroundColor
- JS 修改 style 样式时,产生的是行内样式,权重比 CSS 更高
如果要修改的样式比较少,或者功能比较简单的时候,可以这样用
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>
- 焦点事件
鼠标点击焦点事件 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("失去了焦点");
}
- 移入移出事件
鼠标移入事件 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";
}
}
当用 for 循环对多个元素绑定同一事件时,如果想要某一个元素实现某个样式,则可以:
- 清除所有元素的样式
- 给当前的元素设置样式
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
2
3
4
5
element.属性
- 获取元素的内置属性
element.getAttribute('属性')
- 获取自定义属性和内置属性
- 设置元素属性
1
2
element.属性 = "值"
element.setAttribute('属性', '值')
- 移除元素属性
1
element.removeAttribute('属性')
- 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
node.parentNode
- parentNode 返回元素节点的最近的一个父节点(亲爸爸)
- 如果没有找到返回 null
- 子节点
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
parentNode.children
- children 是一个只读属性,只返回子元素节点,其余节点不返回
- 非标准的,但是得到了很多浏览器的支持
- 第一个/最后一个 子节点
1
2
3
4
5
parentNode.firstChild
parentNode.lastChild
- 节点包含元素节点和文本节点
- 第一个/最后一个 子元素节点
1
2
3
4
parentNode.firstElementChild
parentNode.lastElementChild
这两个方法有兼容性问题,ie9 以上才支持
所以可以这样写
1
2
3
4
parentNode.children[0]
parentNode.children[parentNode.children.length - 1]
- 兄弟节点
1
2
3
4
node.nextSibling
node.previousSibling
- 兄弟元素节点
1
2
3
4
node.nextElementSibling
node.previousElementSibling
- 兼容性问题,ie9 以上才支持
1
document.createElement('tagName')
- document.createElement() 方法创建由 tagName 指定的 HTML 元素。也称为动态创建元素节点
- 只是创建并没有添加
- 在后面追加
1
node.appendChild(child)
- 将一个节点添加到指定父节点的子节点列表的末尾,类似于 css 中的 after 伪元素
- 也称为追加元素
- 插入节点
1
node.insertBefore(child, 指定元素)
- 将一个节点插入到父节点的指定子节点的前面
1
node.removeChild(childNode)
1
node.cloneNode()
- 克隆相当于新建,克隆后需要添加操作
- 如果括号参数为空或者 false,则是浅拷贝,即只克隆复制节点本身,不克隆里面的子节点
- 如果括号里面为 true,则是深拷贝,既复制节点本身,也复制里面的子节点
document.write()
- 是直接将内容写入页面的内容流,但是会导致页面全部重绘
element.innerHTML
- 是将内容写入某个 DOM 节点,不会导致页面全部重绘
- 创建多个元素效率更高(不要采取拼接字符串,采取数组形式拼接),结构稍微复杂
document.createElement()
- 创建多个元素效率会稍微低一些,但是结构更清晰
- 给元素添加事件,称为注册事件或者绑定事件
- 注册事件有两种方式:传统方式和方法监听注册方式
- 传统注册方式
- 利用 on 开头的事件,如 onclick
- <button onclick = “alert(‘hi’)”></button>
- btn.onclick = function() { }
- 特点:注册事件的唯一性
- 同一个元素同一个事件只能设置一个处理函数,最后注册的处理函数将会覆盖前面注册的处理函数
- 方法监听注册方式
- w3c 标准推荐方式
- addEventListener() 是一个方法
- ie9 之前的 ie 不支持此方法,可使用 attachEvent() 代替
- 特点:同一个元素同一个事件可以注册多个监听器
- 按注册顺序依次执行
1
eventTarget.addEventListener(type, listener, [useCapture])
此方法会将指定的监听器注册到 eventTarget(目标对象)上,当该对象触发指定的事件时,就会执行事件处理函数
同一个元素,同一个事件可以添加多个侦听器
该方法接收三个参数:
- type:事件类型字符串(别忘了加引号),比如 click, mouseover, 等,注意不用带 on
- listener:事件处理函数,事件发生时,会调用该监听函数
- useCapture:可选参数,是一个布尔值
- 当为 true 时,事件处于捕获阶段
- 当为 false 或者 省略 时,事件处于冒泡阶段
1
2
3
btn2.addEventListener('click', function() {
alert("使用addEventListener添加点击事件")
})
此方法只有 ie9 及以前的浏览器才支持,chrome 等浏览器不支持
1
eventTarget.attachEvent(eventNameWithOn, callback)
参数:
- eventTarget:目标对象
- eventNameWithOn:事件类型字符串,比如 onclick, onmouseover,等,要带 on
- callback:事件处理函数
- 传统方式删除事件
.onclick = null;
1
2
3
4
5
div.onclick = function() {
alert("111");
div.onclick = null;
}
- 删除方法监听注册的事件
eventTarget.removeEventListener(type, listener, [useCapture])
1
2
3
4
5
6
7
div.addEventListener("click", fn)
function fn() {
alert("222")
div.removeEventTarget("click", fn);
}
- 删除 attachEvent 事件
eventTarget.detachEvent(eventNameWithOn, callback)
1
2
3
4
5
6
7
div.attachEvent("onclick", fn);
function fn() {
alert("333")
div.detachEvent("onclick", fn);
}
事件发生时会在元素节点之间按照特定的顺序进行传播,这个传播过程叫做 DOM 事件流
- JS 代码只能执行捕获或者冒泡中的一个阶段
- onclick 和 attachEvent 只能得到冒泡阶段
- addEventListener 的第三个参数如果为 true 表示在捕获阶段调用事件处理程序,如果为 false 或 不写则表示在冒泡阶段调用事件处理程序
- 有些事件是没有冒泡的,如:onblur、onfocus、onmouseenter、onmouseleave