从零开始的web前端学习-JavaScript

news/2025/3/13 18:08:40/文章来源:https://www.cnblogs.com/kidss/p/18753170

JavaScript 是一种运行在客户端(浏览器)的编程语言,实现人机互动效果:

  • 网页特效(监听用户的某些行为并令网页进行反馈)
  • 表单验证(针对表单数据的合法性进行判断)
  • 数据交互(获取后台数据并渲染到前端)

JavaScript 组成

  • ECMAScript:基础语法核心
  • Web APIs:DOM(页面文档对象模型)、BOM(浏览器对象模型)

JavaScript 引入方式

  • 内部 JavaScript:代码写在 html 文件中,用 script 标签包裹,规范 script 标签写在 上方
  • 外部 JavaScript:代码写在 JavaScript 文件中,通过 script 标签引入到 html 页面
  • 内联 JavaScript:代码写在标签内部

JavaScript 注释

// 单行注释/*
多行
注释
*/

JavaScript 执行顺序
自上而下,但对话框相关语句会优先于页面渲染语句

目录
  • 1输入输出
  • 2变量
  • 3常量
  • 4数据类型
  • 5运算符
  • 6分支结构
  • 7循环结构
  • 8数组
  • 9函数
  • 10匿名函数
  • 11对象-“类”
  • 12Web APIs-DOM获取元素
  • 13Web APIs-DOM事件基础
  • 14Web APIs-DOM事件进阶
  • 15Web APIs-DOM节点操作
  • 16Web APIs-BOM操作浏览器
  • 17Web APIs-正则表达式
  • 18作用域
  • 19函数进阶
  • 20深入对象
  • 21构造函数
  • 22内置构造函数
  • 23编程思想
  • 24原型prototype
  • 25深浅拷贝
  • 26异常处理
  • 27this
  • 28性能优化

1输入输出

输出

  • 文档输出语句:向 body 内输出内容,若输出内容为标签,则会被解析成网页元素
document.write('文档输出语句')
  • 对话框输出语句:页面弹出对话框输出内容
alert('对话框输出语句')
  • 控制台输出语句:向控制台输出内容,调试使用
console.log('控制台输出语句')

输入

  • 对话框输入语句:显示对话框,其中存在输入框
prompt('对话框输入语句')

2变量

变量本质是程序在内存中申请的一块用以存储数据的空间
变量组成:下划线、字母、数字、$,不能以数字开头,区分大小写

let age // 声明变量,声明关键字 变量名
age = 22 // 变量赋值,赋值号 =let height = 180 // 变量声明同时赋值,即变量初始化
height = 181 // 变量更新let age = 18, height = 180 // 多个变量可以同时声明

var 声明的问题:可以先使用后声明、可以重复声明等,let 声明的出现解决 var 声明的问题

作用域

  • 全局作用域:作用于所有代码执行的环境
  • 局部作用域:作用于某一代码块环境

注意:函数内部无声明直接赋值的变量可被当作全局变量,形参视作局部变量,局部变量优先作用

3常量

永远不会改变的变量,不允许再赋值

const G = 9.8 // 常量声明,声明时必须赋值

变量声明,const 优先,需修改则变 let,引用数据类型建议使用 const

4数据类型

  • 基本数据类型:number(数字型)、string(字符串型)、boolean(布尔型)、undefined(未定义型)、null(空类型),存储数据值,存放至栈
  • 引用数据类型:object(对象),存储数据地址,存放至堆
数据类型 说明
number(数字型) 整数、小数、NAN 等数据 NAN,代表计算错误,任何针对 NAN 的操作都会返回 NAN
string(字符串型) 单引号、双引号、反引号包裹的数据 拼接运算符(+),反引号模板字符串实现拼接(`我今年${age}岁`)
boolean(布尔型) 固定值:true、false true 代表真,false 代表假
undefined(未定义型) 固定值:undefined 变量声明不赋值默认 undefined
null(空类型) 固定值:null 代表值为空,可代表未创建的对象

数据类型检测

typeof x // typeof 关键字
typeof(x) // typeof 函数

数据转换

  • 隐式转换(自动):加号两边都有数据,若存在字符串则整体为字符串类型,否则为数字类型,其余算术运算符会将数据自动转换为数字类型
console.log(+'123') // 字符串类型隐式转换为数字类型
  • 显式转换(强制)
Number('123') // 字符串类型显式转换为数字类型,非数字字符串转成 NAN
parseInt('1.23px') // 仅保留整数,开头非数字转成 NAN
parseFloat('1.23px') // 小数同样保留,开头非数字转成 NAN
Boolean('pink') // 字符串类型转换成布尔类型,''、0、undefined、null、false、NAN 转换为 false,其余为 true

5运算符

赋值运算符

符号 = += -= *= /= %=
说明 赋值运算符 加且赋值运算符 减且赋值运算符 乘且赋值运算符 除且赋值运算符 取模且赋值运算符

一元运算符

符号 ++ --
说明 自增 自减

前置自增、后置自增一般情况下显示效果相同,但参与运算存在区别,前置自增先自增再参与运算,后置自增初始值参与运算最后自增

比较运算符

符号 > < >= <= == === != !==
说明 大于 小于 大于等于 小于等于 值相等 值和类型全相等 值不相等 值和类型不全等
console.log(2 == '2') // 字符串类型隐式转换为数字类型,true
console.log(2 === '2') // 类型不等,false
console.log(undefined == null) // true
console.log(undefined === null) // false
console.log(NAN === NAN) // false

字符串比较,实际比较 ASCII 码,顺序比较,长串大
小数比较会存在精度问题

算术运算符

符号 + - * / %
说明 求和 求差 求积 求商 取模(取余数)

运算顺序:从左至右,先乘除取模后加减,括号最优先

逻辑运算符

符号 && || !
说明 逻辑与 逻辑或 逻辑非

逻辑中断:对于 && 和 ||,当满足一定条件时,右侧代码禁止执行

符号 短路条件 特殊
&& 左侧为 false 则短路 两侧都为真,返回最后一个真值
|| 左侧为 true 则短路 两侧存在真值,返回第一个真值

运算符优先级
小括号 -> 一元运算符 -> 算术运算符 -> 关系运算符 -> 相等运算符 -> 逻辑运算符 -> 赋值运算符 -> 逗号运算符

6分支结构

三大流程控制:顺序结构、分支结构、循环结构

  • if 分支语句:单分支、双分支、多分支
if (score >= 80) {document.write('优秀')
} else if (score >= 60) {document.write('及格')
} else {document.write('不及格')
}
  • 三元运算符:if 双分支的简化
age > 18 ? alert('成年') : alert('未成年')
  • switch 分支语句
switch (isTrue) {case true:console.log('成功')breakcase false:console.log('失败')breakdefault:console.log('未知')break
}

注意:值和类型全相等才能执行 case

7循环结构

  • while 循环语句
while (i < 10) {if (i === 1) {i++continue // 退出本次循环}if (i === 2) {break // 退出整个循环}i++
}
  • for 循环语句
for (let i = 0; i < arr.length; i++) {console.log(arr[i]) // 遍历数组if (arr[i] === 4) {break}
}// 嵌套循环
for (let i = 1; i < 10; i++) {for (let j = 1; j <= i; j++) {document.write(`${i} * ${j} = ${i * j} `)}document.write('<br>')
}

8数组

数组可以存储所有类型的数据,下标从零开始

// 数组声明
let age = [1, 2, 3, 4]
let ages = new Array(1, 2, 3, 4)console.log(age[0]) // 数组使用console.log(age.length) // 数组长度属性age[0] = 5 // 数组修改// 遍历数组
for (let i = 0; i < arr.length; i++) {console.log(arr[i])
}// 数组添加元素
arr.push(6) // push() 方法将元素添加至数组末尾,并返回数组新长度
arr.unshift(0) // unshift() 方法将元素添加至数组开头,并返回数组新长度// 数组删除元素
arr.pop() // pop() 方法删除数组末尾元素,并返回删除元素值
arr.shift() // shift() 方法删除数组开头元素,并返回删除元素值
arr.splice(0, 2) // splice(起始位置, 删除个数) 方法从起始位置开始删除指定个数元素,起始位置必须指定,删除个数未指定则删除至末尾// forEach 方法遍历数组,无返回值
arr.forEach(function (item, index) {console.log(item) // 数组元素console.log(index) // 数组下标
})// map 方法:遍历数组并处理数据,返回新数组
const arr = ['red', 'blue', 'green']
const newArr = arr.map(function (item, index) {console.log(item) // 数组元素console.log(index) // 数组下标return ele + '颜色'
})// join 方法:将数组所有元素转换成为一个字符串
const arr = ['red', 'blue', 'green']
console.log(arr.join('')) // 无符号拼接,默认逗号分割 -> arr.join()

9函数

// 函数声明
function getSum(x = 0, y = 0) { // 设置形参默认值,不设置则为 undefinedz = x + yreturn z // 返回值,默认为 undefined
}let sum = getSum() // 函数调用

10匿名函数

  • 匿名函数-函数表达式使用法
let getSum = function (x, y) {return x + y
}getSum(1, 2)

函数表达式与具名函数区别:具名函数调用可在任何位置,函数表达式必须先声明后调用

  • 匿名函数-立即执行法
;(function(){document.write('hello')
})() // 语法一;(function(x, y){document.write(x + y)
} (1, 2)) // 语法二

注意:立即执行法需添加分号,分号可开头也可末尾,末尾小括号相当于函数调用

11对象-“类”

对象由属性和方法组成,属性可以简单理解为基本数据类型,方法可以简单理解为函数

// 对象声明
let student = {'stu-name': 'Tom', // 中划线属性声明age: 18,gender: '男',sayHi: function () {document.write('Hi')},sayGoodbye: function () {document.write('Goodbye')}
}
let obj = new Object() // 不常用// 使用对象属性
console.log(student.gender)
console.log(student['stu-name'])student.age = 19 // 修改对象属性student.height = 180 // 新增对象属性delete student.height // 删除对象属性student.sayHi() // 对象方法调用// 对象遍历
for (let key in student) {console.log(key) // 输出对象属性,数组则为下标,输出类型为字符串类型console.log(student[key]) // 输出对象属性值
}

数学内置对象

调用 说明
Math.PI 圆周率
Math.ceil() 向上取整
Math.floor() 向下取整
Math.round() 四舍五入取近值、大值
Math.max() 最大值
Math.min() 最小值
Math.abs() 绝对值
Math.random() 生成 [0,1) 的随机数,注意随机区间
Math.pow() 幂运算

12Web APIs-DOM获取元素

  • DOM 是用来呈现以及与任意 HTML 或 XML 文档交互的 API,将网页内容视作对象进行处理,可操作网页内容以开发网页内容特效和实现用户交互

  • DOM 树将 HTML 文档以树状结构直观表现,体现标签间关系

  • DOM 对象是浏览器根据 HTML 标签生成的 JavaScript 对象

  • DOM 节点即 DOM 树中每一内容,包含元素节点(所有标签,html 为根节点)、属性节点(所有属性)、文本节点(所有文本)、其他节点

  1. 获取 DOM 元素:根据 CSS 选择器获取 DOM 元素
document.querySelector('div') // 获取第一个 div(选择器)元素,返回一个 HTML 对象或 null
document.querySelector('ul li:first-child') // 获取第一个 ul 元素中的第一个 li 元素document.querySelectorAll('sapn') // 获取所有 span 元素,返回一个 HTML 对象集合,伪数组,有长度有索引号,但没有 push()、pop() 等方法

除去根据 CSS 选择器获取 DOM 元素,还存在一些过去的旧方法

document.getElementById('nav') // 根据 id 获取元素
document.getElementByTagName('div') // 获取所有 div 元素
document.getElementByClassName('pink') // 获取所有类名为 pink 的元素
  1. 操作元素内容
const box = document.querySelector('.box') // 获取元素console.log(box.innerText) // 获取元素文字内容,不解析标签
console.log(box.innerHTML) // 获取元素内容,包含标签解析box.innerText = 'hello' // 修改元素文字内容
box.innerHTML = '<strong>hello</strong>' // 修改元素内容
  1. 操作元素属性
// 操作常用属性
const pic = document.querySelector('img')
pic.src = './images/1.png'
pic.title = '测试1'// 操作样式属性
const box = document.querySelector('.box')
box.style.width = '400px' // 通过 style 修改属性
box.style.backgroundColor = 'black' // 中划线变小驼峰命名
box.style.border = '2px solid while' // 通过 style 添加属性
document.body.style.backgroundImage = './test.png' // body 元素唯一可直接调用而不获取// 通过类名修改属性
.box {...
} // 定义类修改样式
const div = document.querySelector('div')
div.className = 'box' // 为元素添加或修改类名以更行样式,可同时添加多个类// 通过 classList 修改样式
div.classList.add('box') // 追加类名
div.classList.remove('box') // 删除类名
div.classList.toggle('box') // 有则删除,无则追加// 操作表单元素属性
const val = document.querySelector('input') // 文本框
console.log(val.value) // 获取表单元素值
val.value = 'hello' // 修改表单元素值
console.log(val.type) // 获取表单元素类型
val.type = 'password' // 修改表单元素类型const ipt = document.querySelector('input') // 下拉菜单
ipt.checked = true // 勾选const button = document.querySelector('button') // 按钮
ipt.diabled = true // 禁用
  1. 自定义属性:以 data- 开头
<div data-id="1" data-address="home">1</div> // 设置自定义属性
const one = document.querySelector('div')
console.log(one.dataset.id) // 获取自定义属性
  1. 间歇函数
setInterval(function () {
console.log('hello')
}, 1000) // 开启定时器,每 1000ms 执行一次匿名函数,返回一个 id 数字setInterval(fn, 1000) // 有名函数基本形式
setInterval('fn()', 1000) // 有名函数特殊形式let n = setInterval(fn, 1000) // 获取 id
clearInterval(n)

13Web APIs-DOM事件基础

  1. 事件监听:事件源(who)、事件类型(what)、执行函数(how)
const btn = document.querySelector('button')
btn.addEventListener('click', function () {alert('hello')
}) // 点击事件// 旧版本
btn.onclick = function () { // 该方法的原理为赋值,故可能被覆盖,但上面方法是追加,并且该方法都在冒泡阶段执行,无法实现捕获alert('Hi')
}
  1. 事件类型
    |事件|说明|
    |-|-|
    |click|鼠标点击|
    |mouseenter|鼠标经过|
    |mouseleave|鼠标离开|
    |focus|获得焦点(表单)|
    |blur|失去焦点(表单)|
    |Keydown|键盘按下触发|
    |Keyup|键盘抬起触发|
    |input|用户输入事件(表单)|

注意:mouseover,mouseout 的效果同 mouseenter、mouseleave 的效果相同,但前者会存在事件冒泡,可能影响父级元素

  1. 事件对象:事件监听中执行函数的第一个参数
    |属性|说明|
    |-|-|
    |type|获取当前事件的类型|
    |clientX、clientY|获取光标相对于浏览器可见窗口左上角的位置|
    |offsetX、offsetY|获取光标相对于当前 DOM 元素左上角的位置|
    |key|用户按下的键盘值|

  2. 环境对象:this,常规情况下 this 指向调用者

  3. 回调函数:如果将函数 A 作为参数传递给函数 B,那么函数 A 称为回调函数

14Web APIs-DOM事件进阶

  1. 事件流:事件完整执行过程中的流动路径

  2. 事件捕获:从 DOM 的根元素开始执行对应事件

box.addEventListener('click', function () {alert('hello')
}, true) // true 代表开启事件捕获机制,默认为 false
  1. 事件冒泡:当一个元素的事件触发时,同样的事件将会在该元素的所有祖先元素中依次被触发
box.addEventListener('click', function () {alert('hello')
}) // 默认为 false,开启事件冒泡机制

默认开启事件冒泡机制,容易影响父级元素,则需要组织事件冒泡

box.addEventListener('click', function (e) {alert('hello')e.stopPropagation() // 阻止事件流动,既可以阻止事件捕获,也可阻止事件冒泡
})
  1. 解绑事件
const btn = document.querySelector('button')
btn.onclick = function () {alert('Hi')
}
btn.onclick = null // 旧版本解绑事件function fn () { // 匿名函数无法解绑alert('Hi')
}
btn.addEventListener('click', fn)
btn.removeEventListener('click', fn)
  1. 事件委托:利用事件冒泡特点为父级元素注册事件,进而减少事件注册次数,提高程序性能
const ul = document.querySelector('ul') // 为父级元素注册事件
ul.addEventListener('click', function (e) {if (e.target.tagName === 'LI') { // 检验标签类型e.target.style.color = 'red' // 获取点击元素并改变样式}
})
  1. 阻止元素默认行为
const a = document.querySelector('a')
a.addEventListener('click', function (e) {e.preventDefault()
})
  1. 页面加载事件:外部资源加载完毕时触发的事件
window.addEventListener('load', function () { // 监听页面所有资源加载完毕alert('Hi')
})document.addEventListener('DOMContentLoaded', function () { // 无需等待样式表、图像等资源加载alert('Hi')
})

注意:load 不仅可以对所有资源,也可以针对某个资源

  1. 页面滚动事件:滚动条滚动时触发的事件
window.addEventListener('scroll', function () { // 页面滚动console.log('document.documentElement.scrollTop') // 获取 html 元素比较特殊
})const div = document.querySelector('div')
div.addEventListener('scroll', function () { // 针对某个页面if (div.scrollTop > 4 && div.scrollLeft > 2) { // 检测滚动范围alert('hello')  }
})

注意:scroll 不仅可以对整个页面,也可以针对某个页面

  1. 页面尺寸事件:窗口尺寸改变时触发的事件
window.addEventListener('resize', function () { // 页面尺寸let w = document.documentElement.clientWidth // 获取 html 元素宽度let h = document.documentElement.clientHeight // 获取 html 元素高度console.log(w, h)
})

注意:clientWidth、clientHeight 不包含边框 border

  1. 元素尺寸与位置
window.addEventListener('resize', function () { // 页面尺寸let w = document.documentElement.offsetWidth // 获取 html 元素宽度let h = document.documentElement.offsetHeight // 获取 html 元素高度console.log(w, h)
})

注意:offsetWidth、offsetHeight 包含元素自身设置的宽高、padding、border,隐藏返回 0

const div = document.querySelector('div')
console.log(div.offsetLeft) // 获取 div 元素距离父级元素的左距离
console.log(div.offsetTop) // 获取 div 元素距离父级元素的上距离

注意:offsetLeft、offsetTop 是只读属性

15Web APIs-DOM节点操作

  1. 日期对象:获得当前系统时间
const date = new Date() // 实例化,获得当前时间
const dates = new Date('2025-9-1 00:00:00') // 实例化,获得指定时间
console.log(date.getFullYear()) // 调用日期对象方法
console.log(date.getMonth() + 1) // 注意加一
方法 作用 说明
getFullYear() 获得年份 获取四位年份
getMonth() 获得月份 取值为0~11
getDate() 获取月份中的每一天 不同月份取值不同
getDay() 获取星期 取值为0~6,星期天为0
getHours() 获取小时 取值为0~23
getMinutes() 获取分钟 取值为0~59
getSeconds() 获取秒 取值为0~59
toLocalString() 获取年月日时分秒
toLocalDateString() 获取年月日
toLocalTimeString() 获取时分秒
  1. 时间戳:利用毫秒数进行时间计算,实现倒计时
// 方法一
const date = new Date()
console.log(date.getTime()) // 获取时间戳// 方法二
+new Date('2024-1-2 12:34:00') // 获取指定时间戳// 方法三
Date.now() // 无需实例化,但仅能得到当前时间戳
  1. 查找节点:关系查找,返回对象
const ul = document.querySelector('ul')
const li = document.querySelector('ul li:nth-child(2)')console.log(li.parentNode) // 返回最近父级节点对象,无则返回 nullconsole.log(ul.children) // 返回最近子级节点伪数组,仅返回元素节点
console.log(ul.childNodes) // 获得所有子级节点,包括文本节点(空格、换行)等console.log(li.previousElementSibling) // 返回上一个兄弟节点,仅返回元素节点
console.log(li.nextElementSibling) // 返回下一个兄弟节点
  1. 增加节点
const newLi = document.createElement('li') // 创建标签
newLi.innerHTML = 'li 标签' // 标签文本元素编辑const ul = document.querySelector('ul') // 获取父级节点ul.appendChild(newLi) // 父级节点末尾增加节点ul.insertBefore(newLi, ul.children[0]) // 父级节点开头增加节点,后面子级节点伪数组可控制插入位置
  1. 克隆节点:增加节点的特殊形式
const ul = document.querySelector('ul')
const newLi = ul.children[0].cloneNode(true) // true 代表克隆包含所有节点(文本节点、属性节点等),默认 false,仅包含标签节点
ul.appendChild(newLi) // 末尾追加
  1. 删除节点
const ul = document.querySelector('ul') // 获取父级节点
ul.removeChild(ul.children[0]) // 删除子级节点

注意:不存在父子关系,删除失败,删除后节点不复存在

  1. M 端事件:移动端事件
const div = document.querySelector('div')
div.addEventListener('touchstart', function () {console.log('开始触屏')
})
触屏 touch 事件 说明
touchstart 手指触摸至 DOM 元素触发
touchend 手指从 DOM 元素移开时触发
touchmove 手指在 DOM 元素移动时触发
  1. swiper 插件:实习移动端滑动效果
    https://swiper.com.cn/

16Web APIs-BOM操作浏览器

  1. Window 对象:全局对象,基本 BOM 的属性和方法都属于 window,所有 var 声明的全局变量、函数都会成为 window 对象的属性和方法,window 对象下的属性和方法可以省略 window 调用

  2. 延时函数

setTimeout(function () {console.log('Hi')
}, 2000) // 延时函数,2s 后执行函数,但不重复执行,返回一个 id 数字let timer = setTimeout(function () {console.log('Hi')
}, 2000)
clearTimeout(timer) // 清除延时函数,递归必须清除

注意:延时函数 setTimeout 内部无法删除定时器,因为定时器还在运作

  1. JavaScript 执行机制
  • JavaScript 是单线程语言,但 HTML5 提出 Web Worker 标准,允许 JavaScript 脚本创建多个线程,于是 JavaScript 出现同步和异步机制

  • 同步任务:皆在主线程执行,形成执行栈

  • 异步任务:JavaScript 的异步通过回调函数实现,包含普通事件(click、resize 等)、资源加载(load、error 等)、定时器(setInterval、setTimeout 等),异步任务添加至任务队列(消息队列)

  • 执行机制:先执行执行线中的同步任务,然后异步任务放入任务队列,最后依次执行消息队列中的异步任务

  • 事件循环(event loop):主线程不断从任务队列中重复获得任务、执行任务、再获取任务、再执行的机制

  1. location 对象
location.href = 'www.baidu.com' // 属性获取完整 URL,但赋值操作实现自动跳转至网站
console.log(location.search) // 返回 URL 问号后面的内容,包含问号
console.log(location.hash) // 返回 URL 井号后面内容,包含井号
location.reload() // 刷新当前页面
location.reload(true) // 强制刷新当前页面
  1. navigator 对象
console.log(navigator.userAgent) // 检测浏览器版本及平台
  1. history 对象
history.back() // 后退
方法 作用
back() 实现后退功能
forward() 实现前进功能
go(1)、go(-1) 前者代表前进一个页面,后者代表后退一个页面
  1. 本地存储
    localStorage 可以将数据永久存储至本地直至手动删除,可以多窗口共享,以键值对的形式存储使用(仅能存储字符串类型)
localStorage.setItem('uname', 'Tom') // 键值对存储
localStorage.setItem('uname', 'Mary') // 键值修改数据
console.log(localStorage.getItem('uname')) // 键值获取数据
localStorage.removeItem('uname') // 键值删除数据// 存储复杂数据类型
const obj = {uname: 'Tom',age: 18
}
localStrage.setItem('obj', JSON.stringify(obj)) // JSON 字符串 {"uname":"Tom", "age":"18"}// 获取复杂数据类型
console.log(JSON.parse(localStorage.getItem('obj'))) // JSON 字符串转换对象

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

17Web APIs-正则表达式

const str = 'you are a real man'
const reg = /real/ // 检测模式
reg.test(str) // 用模式 reg 检测 str 中是否有 real,匹配则返回 true,否则返回 false
reg.exec(str) // 匹配则返回数组,否则返回 null

元字符:具有特殊含义的字符

  • 边界符:表示位置,开头、结尾
const regHead = /^H/ // 开头为 H
const regTail = /T$/ // 末尾为 T
const reg = /^Y$/ // 精确匹配,字符串仅含 Y 时才返回 true
  • 量词:表示重复位置
const regOne = /^H*$/ // 以 H 为开头结尾,H 出现零次或更多次
const regSnd = /^H{2}$/ // 以 H 为开头结尾,H 出现两次
const regTrd = /^H{4,6}$/ // 以 H 为开头结尾,H 出现四次到六次
  • 字符类:表示某一类字符
console reg = /[abc]/ // 包含其中一个就返回 true
console reg = /[a-z]/ // 小写字母,- 为连字符(表示一个范围)
console reg = /[0-9]/ // 数字
console reg = /[^a-z]/ // 除去小写字母,此处 ^ 为取反符
console reg = /./ // 匹配除换行符外的任何单个字符
console reg = /a/i // 不区分大小写
console reg = /a/g // 匹配所有满足正则表达式的结果 
元字符 说明
^ 表示匹配行首的文本
$ 表示匹配行尾的文本
* 重复零次或更多次
+ 重复一次或更多次
? 重复零次或一次
重复 n 次
重复 n 次或更多次,无空格
重复 n 到 m 次,无空格
[] 匹配字符集合
\d 匹配 0-9 间的任一数字
\D 匹配除 0-9 的字符
\w 匹配任意字母、数字和下划线
\W 匹配除字母、数字和下划线的字符
\s 匹配空格(包括换行符、制表符、空格符等)
\S 匹配非空格的字符

替换

const str = 'java'
const reg = /java/i // 逻辑或写法 /java|JAVA/
const re = 'python'
str.replace(reg, re) // 用 reg 模式匹配后用 re 替换匹配结果

18作用域

  1. 局部作用域
  • 函数作用域:在函数内部声明的变量只能在函数内部被访问,外部无法直接访问
  • 块作用域:大括号包裹的内容被称为代码块,代码块内部声明的变量外部将有可能无法访问(var 声明无法被块作用域约束)
  1. 全局作用域
  • 为 window 对象动态添加的属性默认为全局变量
  • 函数中未使用任何关键字声明的变量视作全局变量
  1. 作用域链
    本质是底层的变量查找机制,在函数被执行时,会优先查找当前函数作用域,若当前作用域查找无果则依次逐级查找父级作用域直到全局作用域

  2. 垃圾回收机制

  • 内存分配:声明变量、函数、对象时,系统自动分配内存
  • 内存使用:读写内存,即使用变量、调用函数等
  • 内存回收:使用完毕后,垃圾回收器自动回收不再使用的内存

注意:全局变量一般不被回收直至关闭页面,局部变量一般会被自动回收

内存泄漏:程序中分配的内存由于某种原因未释放或无法释放

  1. JavaScript 闭包
    一个函数对周围状态的引用捆绑在一起,内层函数中访问到其外层函数的作用域(闭包 = 内层函数 + 外层函数的变量),可能会产生内存泄漏问题

闭包主要用以封闭数据,提供操作,外部可以访问使用函数内部的变量

function outer () {let a = 10function inner () {console,log(a)  }return fn
}
const fun = outer()
fun()
  1. 变量提升
    var 声明的变量会被提升至当前作用域最开始,但仅仅提升变量声明,不提升变量赋值

19函数进阶

  1. 函数提升
    函数的声明会被提升至当前作用域最开始,但仅仅提升函数声明,不提升函数调用,但函数表达式不存在函数提升

  2. 函数参数

  • 动态参数:arguments 是函数内部内置的伪数组变量,包含调用函数时传入的所有实参
function getSum () {let sum = 0for (let i = 0; i < arguments.length; i++) {sum += arguments[i]}return sum
}
  • 剩余参数:将一个不定量的参数表示为一个数组(真数组)
function getSum (a, b, ...arr) {if (arr.length === 0) { // 没有剩余参数return a + b}else {let sum = a + bfor (let i = 0; i < arr.length; i++) {sum += arr[i]}return sum}
}
  1. 展开运算符(...):将数组进行展开
const arr1 = [1, 2, 3]
const arr2 = [4, 5, 6]
console.log(Math.max(...arr)) // 配合 Math 方法使用求最大最小值
const arr = [...arr1, ...arr2] // 合并数组
  1. 箭头函数:替代匿名函数,多用于函数表达式
const fn = () => { // 箭头函数声明console.log('Hi')
}
fn() // 箭头函数调用const fn = x => { // 单一参数简洁形式console.log(x)
}const fn = x => console.log(x) // 单一语句简洁形式const fn = (x, y) => x + y // return 简洁形式const fn = (uname) => ({name: uname}) // 返回对象形式const fn = (...arr) => { // 箭头函数配合剩余函数,无动态参数let sum = 0for (let i = 0; i < arr.length; i++) {sum += arr[i]}return sum
}

注意:箭头函数不会创建 this,会沿用上层作用域的 this,回调函数不推荐使用箭头函数

  1. 数组解构:将数组的单元值快速批量赋值给一系列变量的简洁语法
const = [100, 60, 80]
const [max, min, avg] = arrlet a = 1
let b = 2
;[b, a] = [a, b] // 用以变量交换,注意分号,数组开头前必须加分号const [a, b, c, d] = [1, 2, 3] // d 为 undefined
const [a = 0, b = 0, c = 0, d = 0] = [1, 2, 3] // 默认值防止 undefined
const [a, b, c] = [1, 2, 3, 4] // 4 不赋值
const [a, b, ...c] = [1, 2, 3, 4] // 剩余参数接收
const [a, b, , c] = [1, 2, 3, 4] // 按需赋值
const [a, b, [c, d]] = [1, 2, [3, 4]] // 多维数组支持
  1. 对象解构:将对象的属性和方法快速批量赋值给一系列变量的简洁语法
const obj = {uname: 'Tom',age: 18
}
const {uname, age} = obj // 一般情况下声明变量名与属性名必须相同
const {uname: name, age} = obj // 改名解决变量名冲突// 数组对象解构
const person = [{name: 'Mary', age: 18}]
const [{name, age}] = person// 多级对象解构
const pig = {name: '佩奇',family: {mother: '猪妈妈',father: '猪爸爸',brother: '乔治'},age: 6
}
const {name, family: {mother, father, brother}, age} = pig// 数组多级对象解构
const arr = [{name: '佩奇',family: {mother: '猪妈妈',father: '猪爸爸',brother: '乔治'},age: 6
}]
const [{name, family: {mother, father, brother}, age}] = arr

20深入对象

// 创建对象语法一
const obj = {uname: 'Tom',age: 18
}// 创建对象语法二
const obj = new Object()
obj.uname = 'Tom'

注意:还可以通过构造函数创建对象

21构造函数

function Person (name, age, gender) { // 构造函数大写字母开头this.name = namethis.age = agethis.gender = gender
} // 无需返回值
const student = new Person('Tom', 18, '男') // 构造函数通过 new 执行,实例化

实例化过程:

  1. 创建新的空对象
  2. 构造函数 this 指向新对象
  3. 执行构造函数代码,修改 this,添加新的属性
  4. 返回新对象

实例成员:通过构造函数创建的对象称为实例对象,实例对象中的属性和方法称为实例成员
实例成员为构造函数传入参数,创建结构相同但值不同的对象,构造函数创建的实例对象彼此独立互不影响

静态成员:构造函数的属性和方法称为静态成员
静态成员只能通过构造函数访问,静态方法中的 this 指向构造函数

22内置构造函数

数据类型在底层存在构造函数

  1. Object
const user = new Object({name: 'Tom', age: 18}) // 实例化对象console.log(Object.keys(user)) // 静态方法获取对象中的所有属性名,返回数组
console.log(Object.values(user)) // 静态方法获取对象中的所有属性名,返回数组const obj = {}
Object.assign(obj, user) // 将 user 拷贝至 obj,常用来添加属性(以对象拷贝的形式)
  1. Array
const arr = new Array(1, 2, 3)arr.reduce(function (prev, current) { // 匿名函数可用箭头函数简化return prev + current
}, 10) // 初始值为 10,计算结果为数组和 + 10console.log(arr.every(item => item > 1))const grand = [{name: '小米'},{name: '华为'},{name: '苹果'}
]
arr.find(item => item.name === '小米') // find 方法常用于查找数组对象
方法 作用 说明
forEach 遍历数组 不返回数组,经常用于查找遍历数组元素
filter 过滤数组 返回新数组,返回结果为满足筛选条件的数组元素
map 迭代数组 返回新数组,返回结果为处理后的数组元素
reduce 累计器 返回累计处理的结果,经常用于数组求和
join 拼接数组 返回字符串
find 查找元素 返回符合条件的第一个元素,否则返回 undefined
every 检测数组 所有元素符合条件返回 true,否则为 false
some 检测数组 存在元素符合条件返回 true,否则为 false
concat 合并数组 返回新数组
sort 数组排序 对数组元素进行排序
splice 修改数组 删除或替换数组元素
reverse 翻转数组 返回新数组
findIndex 查找元素的索引值 返回索引
  1. String
const str = 'hello,world'
const arr = str.split(',') // split 方法分割拆分成数组,以 , 为分割符console.log(str.substring(1, 4)) // substring 方法截取下标 1 至 3 部分为子串(左闭右开),省略 end 参数则取完console.log(str.startwith('llo', 2)) // startwith 方法从下标为 2 的位置开始判断是否以某字符开头console.log(str.includes('world', 4)) // includes 方法从下标为 4 的位置开始判断是否包含某字符
方法 说明
length 获取字符串长度
split 将字符串拆分成数组
substring 字符串截取
startwith 检测是否以某字符开头
includes 判断是否包含,返回布尔值
toUpperCase 字母转大写
toLowerCase 字母转小写
indexOf 检测是否包含某字符
endwith 检测是否以某字符结尾
replace 替换字符串,支持正则表达式
match 查找字符串,支持正则表达式

23编程思想

  • 面向过程:分析解决问题的步骤,接着用函数实现步骤,使用时依次调用函数(性能较高)
  • 面向对象:将事务分解成对象,由对象分工合作实现(易维护、易复用、易扩展)

面向对象特性:封装性、继承性、多态性

构造函数实现 JavaScript 的封装性,但存在浪费内存的问题,this 指向实例对象

原型实现 JavaScript 的继承性,this 指向实例对象

24原型prototype

JavaScript 规定,每一个构造函数都有一个 prototype 属性,指向一个对象,该对象称为原型对象,构造函数通过原型分配的函数由所有对象共享,因此可以利用原型对象实现属性或方法的共享,节省内存

function Star (uname, age) { // 公共属性写入构造函数this.uname = unamethis.age = age
}Star.prototype.sing = function () { // 公共方法写入原型对象console.log('sing')
}

constructor 属性:指向该原型对象的构造函数

function Star () {}Star.prototype = { // 以对象赋值方式添加公共方法,会导致 constructor 属性丢失constructor: Star // 找回 constructor 属性sing: function () { // 添加公共方法console.log('sing')}
}

对象原型 proto([[prototype]]):对象都会存在属性 proto,指向构造函数的原型对象 prototype,这使得对象可以使用原型对象的属性和方法,proto 是 JavaScript 非标准属性,只读属性,对象原型 proto 中同样存在 constructor 属性,指向创建该实例对象的构造函数

function Star () {}
const s = new Star()console.log(s.__proto__ === Star.prototype) // true
console.log(s.__proto__.constructor === Star) // true

原型继承

function Person () {this.ear = 2this.head = 1
}function Woman () {}
Woman.prototype = new Person() // 继承的同时为独有方法的添加开辟空间
Woman.prototype.constructor = Woman // prototype 改变导致 constructor 指向改变,要恢复指向
Woman.prototype.baby = function () { // 添加独有方法console.log('baby')
}

原型链:针对对象原型 proto 指向
基于原型对象的继承使得不同构造函数的原型对象关联在一起,并且这种关联的关系是一种链状的结构,这种链状结构关系被称为原型链

查找规则:当访问一个对象的属性或方法是,首先查找这个对象自身有没有该属性,如果没有就查找该对象的原型,如果还没有就查找原型对象的原型,依次类推查找到 Object 为止,proto 对象原型的意义在于为对象成员查找机制提供方向

instanceof:检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上

console.log(Tom instanceof Person) // true or false

25深浅拷贝

  • 浅拷贝(简单数据类型拷贝值,引用数据类型拷贝地址)
// 对象拷贝
const obj = {}const o1 = {...obj} // 展开运算符拷贝
const o2 = {}
Object.assign(o2, obj) // assign 方法拷贝// 数组拷贝:Array.prototype.concat() 或者 [...arr]
  • 深拷贝(简单数据类型拷贝值,引用数据类型创建新对象赋值旧内容)
// 递归函数实现
const obj = {}
const o = {}
function deepCopy (newOb, oldObj) {for (let k in oldObj) {// 处理引用数据类型if(oldObj[k] instanceof Array) { // 判断是否为数组newObj[k] = []deepCopy(newObj[k], oldObj[k])} else if(oldObj[k] instanceof Object) { // 判断是否为对象newObj[k] = {}deepCopy(newObj[k], oldObj[k])} else {newObj[k] = oldObj[k]}}
}
deepCopy(o, obj)// lodash 实现(需要导入 JavaScript 库)
const o = _.cloneDeep(obj)// JSON 实现
const o = JSON.parse(JSON.stringify(obj))

26异常处理

// throw 方式
function fn (x, y) {if (!x || !y) {throw new Error('传递参数为空') // throw 会自动中止程序}return x + y
}// try catch finally 方式
function fn () {try {const p = document.querySelector('p')p.style.color = 'red'} catch (err) {console.log(err.message)return // 中断程序}finally {alert('警报')}
}

27this

  • 普通函数:一般情况下,this 指向普通函数的调用者,若没有明确调用者则指向 window,严格模式下没有调用者 this 指向 undefined

  • 箭头函数:箭头函数会默认绑定外层 this 的值,其引用最近作用域的 this,若没有则会依次向外层作用域查找 this(构造函数、原型、DOM 事件函数等需要利用 this 时不使用箭头函数)

改变 this 指向

const obj = {}
function fn (x, y) {} // this 指向 window// call 方法
fn.call(obj, 1, 2) // 改变 this 指向 obj,1、2 为传入参数,返回值为函数返回值// apply 方法
fn.apply(obj, [1, 2]) // 改变 this 指向 obj,数组传递参数,返回值为函数返回值
console.log(Math.max.apply(Math, [1, 2, 4])) // 指向可为 Math 或者 null,求最大值// bind 方法
fn.bind(obj) // 改变 this 指向 obj,返回值为新函数(this 指向改变,其余拷贝旧函数)

区别:
call 和 apply 会调用函数,并且改变函数内部 this 指向
call 和 apply 传递的参数形式不同
bind 不会调用函数,可以改变函数内部 this 指向

28性能优化

  • 防抖:单位时间内,频繁触发事件,只执行最后一次
const box = document.querySelector('.box')
let i = 1
function mouseMove () {box.innerHTML = i++
}// lodash 实现防抖
box.addEventListener('mouseMove', _.debounce(mouseMove, 500)) // 500ms 间隔// 手动实现
function debounce (fn, t) {let timerreturn function () {if (timer) clearTimeout(timer)timer = setTimeout(function () {fn()}, t)}
}box.addEventListener('mouseMove', _.debounce(mouseMove, 500))
  • 节流:单位时间内,频繁触发事件,只执行一次
// lodash 实现节流
box.addEventListener('mouseMove', _.throttle(mouseMove, 500)) // 500ms 间隔// 手动实现
function throttle (fn, t) {let timer = nullreturn function () {if (!timer) {timer = setTimeout(function () {fn()timer = null}, t)}}
}box.addEventListener('mouseMove', _.throttle(mouseMove, 500))

防抖强调最后一次的执行,如搜索框输入等场景,而节流强调原子性操作(不被中断),如鼠标移动、页面尺寸缩放、滚动条滚动等高频事件

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/898284.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Azure Service Bus】分享使用 Python Service Bus SDK 输出SDK内操作日志

问题描述 使用Python代码消费Service Bus中的消息,默认情况 Console 中的信息都是通过 print 打印输出。 有时候需要调查更多SDK中的日志,那么如何才能让SDK输出更多的日志呢?问题解答 方法就是引入 Logging SDK,然后再初始化 ServiceBusClient 对象时,设置logging_enabl…

nvm和nodejs安装

nvm和nodejs安装安装 nvm 全名 node.js version management,顾名思义是一个nodejs的版本管理工具。通过它可以安装和切换不同版本的nodejs。首先下载安装包,可以用GitHub上的,可以有点看,也可以用一些镜像,然后点击安装一直下一步即可。 然后打开命令行,可以用nvm -v指令…

dify文件上传到http节点

dify系统上传sys.files变量是Array[File]类型,由于 HTTP 请求节点不支持 Array[File] 上传,需要单独处理每个文件,以下是实现此功能的步骤: 添加迭代节点 迭代输入选sys.files 输出选http请求body http请求body类型选form-data 键值选迭代的item.File 本文使用dify版本为0.…

可行性分析(第五组)

目录 第1章 系统分析 1.1 可行性分析 1.1.1 技术可行性分析 1.1.2 经济可行性分析 1.1.3 社会可行性分析 1.1.4 法律可行性分析 1.2 系统流程分析 1.2.1 系统开发总流程 1.2.2 登录流程 1.2.3 系统操作流程 1.2.4 系统性能分析 第1章 可行性分析 1.1可行性分析 下面分别从技术可…

C# 子窗体中调用父窗体中的方法(或多窗体之间方法调用)

看似一个简单的功能需求,其实很多初学者处理不好的,很多朋友会这么写:C# Code://父窗体是是frmParent,子窗体是frmChildA //在父窗体中打开子窗体 frmChildA child = new frmChildA(); child.MdiParent = this; child.Show();//子窗体调父窗体方法: //错误的调用!!!!!!!! …

Qt HTTP模块——调用API对话DeepSeek

HTTP模块 Qt的网络模块(QtNetwork)支持HTTP/HTTPS协议,提供异步、非阻塞的API,实现客户端与服务器之间的 HTTP 请求与响应交互。核心类:QNetworkAccessManager:负责协调网络操作(如GET/POST请求),管理请求队列和返回的响应。 QNetworkRequest:封装HTTP请求的详细信息…

Linux下环境变量

Linux打印环境变量: echo $PATH

GitLearning

创建新仓库 创建新文件夹,打开,然后执行 git init创建新的 git 仓库 (也可以直接 git clone 远程仓库) git clone /path/to/repository git clone username@host:/path/to/repository工作流 本地仓库由 git 维护的三棵树。第一个是工作目录,它持有实际文件;第二个是暂存区(…

ai理解需求生成测试用例-deepseek

ai:把用例捡起来!把用例捡起来! 给大模型需求文档,让它完成设计用例,编写用例,包括功能用例、接口用例、自动化测试用例,自执行~最后发送至工作群中 直接使用deepseek即可 执行一下看看: 调用ds分析需求: 生成功能/接口用例: 生成自动化用例: 看一下自动生成的功…

Win下的Cursor连MCP都是坑?

最近研究了下MCP(模型上下文协议),MCP是由Anthropic(Claude母公司)在2024年11月25日提出并开源的,算是一个比较新的东西。 目前已经被Claude桌面端、Cline、Continue、Cursor、Windsurf等工具应用。在Windows上还是有蛮多坑的,Mac调用会相对简单很多。先来说下MCP能做什…

足球滚球大小球技巧:现代化AI技术 基于机器学习的高精度预测模型与动态策略优化

​ 在足球竞技赛事领域,滚球大小球策略因其动态性和实时性成为复杂数据分析与机器学习(ML)技术的前沿应用场景。本文旨在通过系统化的数据建模与算法优化,探讨如何构建高精度的进球数预测模型,并制定动态调整的策略。文章将从数据预处理、特征工程、模型构建、实时预测优化…

Ubuntu git 上传项目代码

Ubuntu git 上传项目代码 记录使用实验室电脑第一次上传实验代码的过程。 配置SSH密钥 1、本机生成 RSA 密钥对 本机使用ssh-keygen -t rsa命令生成 RSA 密钥,前面步骤都忘记截图啦。根据生成的密钥所在目录,打开id_rsa.pub并复制。这里复制的是公钥。 2、github 配置 SSH KE…