JavaScript笔记
js组成
- ECMAScript
- js语言基础
- Web APIs
- DOM:页面文档对象模型
操作文档,比如对页面元素的移动、大小、添加和删除 - BOM:浏览器对象模型
操作浏览器,比如页面弹窗,检测窗口宽度、存储数据到浏览器等等
- DOM:页面文档对象模型
书写位置
-
行内
- 在body标签上方
- 通常写在底部
-
内部
- 写在标签内部
-
外部
<script src="my.js"></script>
注释
//单行注释
/*
多行注释
*/
;可加可不加
输入输出
输出
document.write('内容')
document.write('<h1>内容</h1>')
alert('弹出内容')
console.log('控制台打印')
输入
弹出对话框:
prompt('请输入你的名字:')
返回字符串
alert()与prompt()优先被执行,其他按文档流顺序执行
字面量
字面量是在计算机中描述事/物
变量
声明:
let var = 19, name = '张三'
var = 18
命名规范
- 不能关键字
- 只能下划线、字母、数字、$组成,不能数字开头
- 严格区分大小写
规范:
- 首字母小写,后面每个单词大写
数组
let array = []
let array = [1, 2, 3]
let array = ['array', 'tete', 'tt']
array[0]
array.length
编号从0开始
常量
const G = 9.8
声明时必须赋值
数据类型
- 基本数据类型
- number
- string
- boolean
- undefined
- null
- 引用数据类型
- object
number
±*/%
加减乘除取模
string
- 推荐使用’’
- \为转义字符
- 用+拼接字符串与变量
模板字符串
let age = 20
`我今年$(age)岁`
boolean
true
false
undefined
只声明不赋值就是该类型
null
把null作为尚未创建的对象
数据类型检测
typeof x
typeof(x)
类型转换
-
隐式转换
2 + '2' = '22' 2 -'2' = 0 +'123' = 123 //转换为number
任何数据类型和字符串相加为字符串
‘’、null转换为0,undefined转换为NaN
-
显示转换
Number(数据) parseInt(数据) //只保留整数 parseFloat(数据) //可以保留小数
运算符
-
赋值
= += /= -= *= %=
-
一元
正负号 ++ --
-
比较
> < >= <= == === 类型与值相同(推荐使用) !==
-
逻辑运算符
&& 与 || 或 ! 非
-
if
if () { } else { } else if () { }
-
三元
条件 ? 代码1 : 代码2
数字补0:
num = num < 10 ? 0 + num : num
-
switch
switch () {
case 值1:
代买1
break
default:
代码n
break
}
循环
while () {
continue
break
}
for (变量起始值; 终止条件; 变量变化量) {
}
数组
a[i] = 1
a.push() //结尾添加新值,返回length
a.unshift() //开头添加
a.pop() //结尾删除
a.shift() //开头删除
a.splice(下标,删除个数)
函数
function 函数名(参数=0) { //可以给默认值
return 0
}
匿名函数
-
赋值
let fn = function() { } fn()
-
立即执行
(function () {})();
逻辑中断
&& 左边为false就短路
|| 左边为true就短路
转换为boolean
Boolean() //0、''、undefined、false、null、NaN为false,其他为true
对象
let object = {
属性名: 属性值,
方法名: 函数
}
let object = new Object()
object.属性名 //查询
object['属性名'] //查询
object.属性名 = 值 //增加/修改
delete object.属性名 //删除
delete.func() //方法
for (let k in object) {
console.log(object[k])
}
内置对象
Math.random()
Math.cell()
Math.floor()
Math.max()
Math.min()
Math.pow()
Math.abs()
Web APIs
let or const
const优先,尽量使用const
建议数组和对象使用const声明
DOM
文档对象模型
操作网页内容,开发网页内容特效和实现用户交互
DOM树
将HTML文档以树状结构直观表现出来
直观体现了标签与标签之间的关系
DOM对象
浏览器根据HTML标签生成的js对象
标签属性在js对象上找到
核心思想:把网页当作对象处理
document对象
用来访问和操作网页内容
网页所有内容都在document里面
获取DOM对象
-
通过CSS选择器来获取DOM元素
-
其他
document.querySelector('css选择器') //返回第一个元素 document.querySelectorALL('css选择器') //返回对象集合(数组),有长度有索引号 const lis = document.querySelector('.nav li') for (let i = 0; i < lis.length; i++) { console.log(lis[i]) } document.getElementById('nav') document.getElementsByTagName('div') document.getElementsByClassName('w')
操作内容
对象.innerText属性 //修改内容,不解析标签
对象.innerHTML属性 //修改内容,会解析标签
修改元素内容
操作常用属性
- href
- title
- src
操作样式属性
对象.style.属性 = 值
多组单词改为小驼峰
box.style.width = '300px'
box.style.backgroundColor = 'hotpink'
操作类名操作css
元素.className = 'active' //替换
通过classList操作css
元素.classList.add('类名') //追加
元素.classList.remove('类名') //删除
元素.classList.toggle('类名') //切换,有就删除,没有就加上
操作表单属性
表单.value = '用户名'
表单.type = 'password'
修改true/false:
- disabled
- checked
- selected
自定义属性
data-开头的都是自定义属性
<div data-id = "1"></div>
const one = document.querySelector('div')
console.log(one.dataset.id)
定时器-间隙函数
let n = setInterval(函数, 间隔时间) //单位毫秒
clearInterval(n)
事件监听
给DOM元素添加事件监听
元素.addEventListener('事件类型', 函数)
-
事件源:哪个DOM元素被事件触发了
-
事件类型:click,mouseover
-
事件调用函数
-
DOM L0
事件源.on事件 = function () {}
-
DOM L2
事件源.addEventListener(事件, 事件处理函数)
区别:on会被覆盖,addEventListener可以绑定多次
调用事件:
next.click()
事件类型
- 鼠标事件(鼠标触发)
- click
- mouseenter
- mouseleave
- 焦点事件(表单获得光标)
- focus
- blur
- 键盘事件(键盘触发)
- Keydown
- Keyup
- 文本事件(表单输入触发)
- input
事件对象
事件绑定的回调函数第一个参数就是事件对象
元素.addEventListener('click', function (e) {})
e为事件对象
常用属性
- type:事件类型
- clientX/clientY:获取光标相对于浏览器可见窗口左上角位置
- offsetX/offsetY:获取光标相对于当前DOM元素左上角位置
- key:用户按下的键盘键的值,不提倡用keyCode
trim方法
str.trim()
str的前缀与后缀空格去除
环境对象
函数内部特殊变量this,代表函数运行时所处环境(谁调用this就是谁,比如被加入事件函数的元素)
function fn() {
console.log(this) //这里this为window
}
window.fn() //等同于fn()
回调函数
函数A作为参数传递给函数B,则A为回调函数
:checked伪类
.ck:checked {
// 选择被勾选的复选框
}
事件流
- 捕获阶段
Document->html->body->div
- 冒泡阶段
div->body->html->Document
事件捕获
从DOM根元素开始执行对应事件
addEventListener第三个参数为true代表捕获阶段触发,默认为false冒泡
L0事件监听只有冒泡
事件冒泡
一个元素的事件被触发,同样的事件会在该元素所有祖先元素中依次被触发
阻止冒泡
事件对象.stopPropagation
阻止事件流动(包括冒泡与捕获)
解绑事件
-
on事件方法,用null覆盖
-
removeEventListener(匿名函数无法解绑)
元素.removeEventListener('事件类型', 函数名[, false)
mouseover、mouseout、mouseenter和mouseleave
- mouseover和mouseout有冒泡效果
- mouseenter和mouseleave没有冒泡效果
事件委托
是一种技巧
利用事件冒泡特点
即给父元素注册事件
e.target //事件对象的元素对象
e.target.tagName //事件对象的元素
if (e.target.tagName === 'LI') { //注意大写
e.target.style.color = 'red'
}
阻止默认行为
比如阻止链接的跳转/表单域的跳转
e.preventDefault()
其他事件
-
页面加载事件
window.addEventListener('load', function () { }) img.addEventListener('load', function () { //也可以针对某个资源绑定 }) document.addEventListener('DOMContentLoaded', function () { //无需等样式表、图像完全加载 })
-
页面滚动事件
window.addEventListener('scroll', function () { })
属性(没有单位,可以修改):
-
scrollLeft
距离左边滚动距离 -
scrollTop
距离上边滚动距离div.add... div.scrollTop window.addEventListener('scroll', function () { const n = document.documentElement.scrollTop })
-
页面尺寸事件
window.addEventListener('resize', function () { })
检测元素宽度(不包括边框、margin和滚动条):
document.documentElement.clientwidth
div.clientwidth
元素尺寸位置
获取宽高,包含padding、border:
- offsetWidth
- offsetHeight
如果是隐藏的,为0
获取位置,只读,相对于最近一级带有定位的祖先元素的左、上:
- offsetLeft
- offsetTop
属性选择器
input[value] {
color: red;
}
input[type=text] {
color: red;
}
<input type="text" value="123">
<input type="password">
const input = document.querySelector('input[value]')
日期对象
实例化
const date = new Date()
const date1 = new Date('2022-5-1 08:30:00')
时间对象方法
getFullYear() //获取四位年份
getMonth() //0~11
getDate() //获得月份中的每一天
getDay() //获取星期,0~6,0为星期天
getHours() //0~23
getMinutes() //0~59
getSeconds() //0~59
const date = new Date()
date.toLocaleString() //2022/4/1 09:41:21
date.tolocaleDateString()
date.toLocaleTimeString()
时间戳
毫秒数
1970/01/01 00:00:00开始的毫秒数
-
getTime()方法
const date = new Date() date.getTime()
-
+new Date()
console.log(+new Date())
-
Date.now()
Date.now()
节点操作
DOM节点
DOM数中每个节点都为DOM节点
- 元素节点
- 所有标签
- html为根节点
- 属性节点
- 文本节点
- 其他
查找节点
根据节点关系查找目标节点
-
父节点
子元素.parentNode //dom对象
-
子节点
父元素.childNodes 父元素.children //所有元素节点,然会伪数组
-
兄弟节点
.nextElementSibling
.previousElementSibling
增加节点
-
创建节点
document.createElement('标签名')
-
增加节点
父元素.appendChild('子元素') 父元素.insertBefore(要插入的元素, 在哪个元素前面)
-
克隆节点
元素.cloneNode(boolean) //true会复制后代,false不包含后代,默认为false
删除节点
父元素.removeChile(要删除的元素)
M端事件
移动端事件
- touchstart
- touchmove
- touchend
js插件
swiper插件
-
下载,找到package文件夹
-
复制css,js文件夹到lib
-
引入
link swiper.min.css
-
复制
Window对象
var定义的、console、document等都在windown对象中
BOM浏览器对象模型
定时器-延时函数
setTimeout(函数, 等待的毫秒数) //返回id
clearTimeout(timer)
js执行机制
单线程
可以创建多个线程,出现同步异步
-
同步:
形成执行栈 -
异步:
添加到任务队列- 普通事件
- 资源加载
- 定时器
js首先执行同步任务,将异步任务放入任务队列
然后按次序读取任务队列中的异步任务
js主线程事件循环:获得任务-执行任务-获得任务-执行任务
location对象
拆分保存url地址的各个部分
属性与方法:
- href:完整的网站地址
- search:获取地址中携带的参数,符号?后面部分
- hash:获取地址中的哈希值,符号#后面部分
- reload(boolean):刷新当前页面,true表示强制刷新
navigator对象
浏览器自身的相关信息
属性与方法:
- userAgent:检测浏览器版本及平台
立即执行匿名函数:
!function(){}()
(function(){})()
history对象
- back() //后退
- forward() //前进
- go(参数) //前进后退,1为前进1个,-1为后退1个
本地存储
介绍
页面刷新不丢失数据
分类
localStorage
-
多窗口共享
-
键值对形式存储
localStorage.setItem('key', 'value') localStorage.getItem('key') //获得的都是字符串 localStorage.removeItem('key')
sessionStorage
- 生命周期为关闭浏览器窗口
- 同一个窗口下共享
- 键值对
- 和localStorage类似
存储复杂数据类型
转换为JSON字符串,存储到本地
JSON.stringify(复杂数据类型)
localStorage.setItem('obj', JSON.stringify(obj))
JSON.parse(localStorage.getItem('obj'))
map()
const arr = ['pink', 'red', 'blue']
const newarr = arr.map(function (item, index) {
console.log(item)
console.log(index)
return item + '老师'
})
join()
const arr = ['pink', 'red', 'blue']
console.log(arr.join('')) //数组元素连在一起
正则表达式
const regObj = /表达式/
regObj.test(被检测的字符串) //返回boolean
regObj.exec(被检测字符串) //查找符合规则的字符串,返回数组,否则返回null
或者
|
边界符
- ^:开头
- $:结尾
量词
- ?:0或1
- *:任意值
- +:大于0
- {n}:重复n次
- {n,}:重复大于等于n次
- {n, m}:重复n~m次
元字符
- [a]:匹配集合
- [^a]:除了a的匹配集合
- .:除了换行任何字符
- [a-z]:所有小写字符
预定义类
- \d:数字
- \D:除了数字
- \w:字母数字和下划线
- \W:除了字母数字下划线
- \s:空格(换行符、制表符、空格)
- \S:除了换行符制表符空格
修饰符
/表达式/修饰符
-
i:不区分大小写
-
g:匹配所有满足正则表达式的结果
const str = 字符串.replace(/正则表达式/gi, ‘替换的文本’)
原型与原型链
原型
函数的prototype属性默认指向一个object空对象(原型对象)
原型对象有个属性constructor指向函数对象
给原型对象添加属性(方法),则函数的所有实例对象自动拥有原型中的属性(方法)
显式原型/隐式原型
- prototype即显示原型
- 定义函数时自动添加,默认为空object对象
- 隐式原型:
- 创建对象时自动添加,默认值为构造函数的prototype属性值
__proto__
- 对象的隐式原型的值为其对应构造函数的显示原型的值
原型链
- 访问一个对象的属性时:
- 先在自身属性中查找,找到返回
- 若没有,再沿着__proto__这条链向上查找
- 若最终没有,返回undefined
- 即隐式原型链
- 作用:查找对象属性(方法)
定义一个函数,该函数也是一个叫Function类的实例,其__proto__指向Function的显示原型
函数的显示原型指向的对象默认是空Object实例对象(Object不满足)
myfun.protype instanceof Object// ture
Object.protype instanceof Object // false
Function.protype instanceof Object // true
所有函数都是Function的实例(包括Function)
Function.__proto__ === Function.prototype // true
Object的原型对象是原型链尽头
属性
- 读取对象属性,自动到原型链中查找
- 设置对象属性时,不会查找原型链
- 方法一般定义在原型中,属性一般通过构造函数定义在对象本身上
instanceof
在原型链上就是true
备注
- new之后__proto__不会更改,即使构造函数的原型改变指向,改之前创建的对象实例的__proto__也不会更改
function F(){}
Object.prototype.a = function(){
}
Function.prototype.b = function(){
}
let f = new F()
f.a() // 有
f.b() // 无
F.a() // 有
F.b() // 有
执行上下文
变量提升/函数提升
var a = 3
function fn () {
console.log(a)
var a = 4
<!-- 相当于:
var a;
console.log(a)
a = 4;
-->
}
fn() // undefined
变量提升:通过var定义,在定义之前就能访问,但值为undefined
函数提升:定义之前可以调用
f3() // 不能调用,为undefined
var f3 = function(){
}
执行上下文
全局执行上下文:
- window确定为全局执行上下文
- 对全局数据预处理
- var定义的全局变量=>undefined,添加为window属性
- function声明的全局函数,添加为window方法
- this=>赋值(window)
- 开始执行全局代码
函数执行上下文: - 调用函数,创建对应函数执行上下文对象(存在栈中)
- 局部数据预处理
- 形参变量添加为执行上下文的属性
- arguments(伪数组)添加为执行上下文属性
- var定义的局部变量=>undefined,添加为执行上下文的属性
- function声明添加为执行上下文方法
- this=>赋值(调用函数的对象)
执行上下文栈
- 全局代码执行前,js引擎创建一个栈存储管理所有执行上下文对象
- 将全局执行上下文(window)压栈
- 函数执行上下文创建后压栈
- 执行完毕后出栈
function a(){}
var a;
console.log(typeof a) // 'function' 先变量提升,再函数提升
if (!(b in window)) {
var b = 1
}
console.log(b) // undefined
var c = 1
function c(c) {
console.log(c)
}
c(2) // 报错,c不是函数
// 变量函数提升后再用1覆盖了c
作用域与作用域链
- 全局作用域
- 函数作用域
- 块作用域(let)
作用域是静态的,函数定义域在函数定义时已经确定
var x = 10
function fn() {
console.log(x);
}
function show (f) {
var x = 20;
f();
}
show(fn); // 10
var fn = function(){
console.log(fn) // function
}
fn()
var obj = {
fn2: function(){
console.log(fn2) // 报错,fn2未定义
}
}
obj.fn2()
闭包
嵌套的内部函数引用了嵌套的外部函数的变量(函数)时,就产生了闭包
闭包存在于嵌套的内部函数中
产生条件:
- 函数嵌套
- 内部函数引用外部函数的数据
闭包是包含被引用变量的对象,作为嵌套的引用外部函数数据的内部函数的属性
定义函数就会产生闭包,不必执行内部函数,但需要执行外部函数
作用
延长局部变量生命周期
让函数外部可以操作读写到函数内部的数据
生命周期
产生:内部函数定义执行完时产生
死亡:内部函数成为垃圾对象时
应用
自定义js模块
缺点
函数执行完后,局部变量没有释放,占用内存时间长
容易造成内存泄漏
能不用就不用
及时释放
内存溢出
超出剩余内存
内存泄漏
占用的内存没有及时释放,多了就导致内存溢出
常见内存泄漏:
- 意外的全局变量
- 没有及时清理的计时器或回调函数
- 闭包
var name = 'window'
var o = {
name : 'zdp';
getNameFunc: function(){
return function(){
return function(){
return this.name;
}
}
}
}
var name = 'window'
var o = {
name : 'zdp';
getNameFunc: function(){
vat that = this;
return function(){
return function(){
return that.name;
}
}
}
}
function fun(n, o) {
console.log(o);
return {
fun: function(m) {
return fun(m, n)
}
}
}
var a = fun(0);
// undefined a = {fun(m){return fun(m, 0)}}
a.fun(1); // 0
a.fun(2); // 0
a.fun(3); // 0
var b = fun(0).fun(1).fun(2).fun(3);
// undefined b = {fun(m){return fun(m, 0)}}
// 0 b = {fun(m){return fun(m, 1)}}
// 1 b = {fun(m){return fun(m, 2)}}
// 2 b = {fun(m){return fun(m, 3)}}
var c = fun(0).fun(1);
// undefined 0 b = {fun(m){return fun(m, 1)}}
c.fun(2); // 1
c.fun(3); // 1
创建对象
- Object
var p = new Object()
p.name = 'zdp';
- 字面量
var p = {
name: 'zdp',
setName: function(){
}
}
- 工厂模式
// 工厂函数
function createPerson(name, age) {
var obj = {
name: name,
age: age
}
return obj
}
- 自定义构造函数模式
function Person(name, age) {
this.name = name
this.age = age
this.setName = function (name) {
this.name = name
}
}
var s = new Person('zdp', 12);
- 构造函数+原型
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.setName = function (name) {
this.name = name
}
var s = new Person('zdp', 18);
继承模式
原型链的继承
- 定义父类型构造函数
- 给父类型的原型添加方法
- 定义子类型的构造函数
- 创建一个父类型的实例赋值给子类型的原型
- 将子类型原型的构造属性设置为子类型
- 给子类型原型添加方法
- 创建子类型的对象:可以调用父类型的方法
- 让子类型的原型的构造器指向子类型
子类型的原型为父类型的一个实例对象
call函数继承
function Person(name, age){
this.name = name;
this.age = age;
}
function s(name, age){
Person.call(this, name, age)// this.Person(name, age);
}
var t = new s(1, 2);
组合继承
function Person(name, age){
this.name = name
this.age = age
}
Person.prototype.setName = function(name){
this.name = name
}
function Student(name, age){
Person.call(this, name, age)// this.Person(name, age)
}
Student.prototype = new Person()
Student.prototype.constructor = Student
var s = new Student('zdp', 25)
线程机制与事件机制
线程进程
js单线程
使用Web Workers可以多线程运行
浏览器多线程运行
浏览器有多进程:chrome/新ie
单进程:老ie/firefox
浏览器内核
chrome,safari:webkit
firefox:Gecko
ie: trident
360+搜狗:trident+webkit
- js引擎模块
- html/css解析模块
- DOM/css模块
- 布局渲染模块
- …
- 定时器模块
- 事件响应模块
- 网络请求模块
定时器
定时器回调函数在js主(单)线程执行
不是完全精准执行,会延迟一会儿
js单线程执行
alert暂停线程而且会暂停计时,点击确定后恢复
- 先执行初始化代码
- 设置定时器
- 绑定监听
- 发送ajax请求
- 回调代码
事件循环模型
- 事件管理模块
- 回调队列
- 执行初始化代码,将事件回调函数给对应模块
- 事件发生时,将回调函数与数据添加到回调队列
- 当初始化代码执行完毕后,遍历读取回调队列中的回调函数执行
- 执行栈
- 浏览器内核
- 任务队列/消息队列/事件队列:回调队列
- 事件轮询
- 事件驱动模型
- 请求响应模型