一.windows对象
1.1location对象
- href:可以获取或者设置当前页面的url地址
- search:可以获取url地址中的查询字符串 符号?后面部分
- hash:可以获取url地址中的哈希值 符号#后面部分
- reload:可以刷新当前页面(传入参数为true时强制刷新)
1.2navigator对象
1.3history对象
- 前进:history.go(1) history.forward()
- 后退:history.go(-1) history.back()
1.4本地存储
<body>
<script>
//本地存储locationStorage (sessionStorage同理,略)
localStorage.setItem('name','gzbn')
console.log(localStorage.getItem('name'))
localStorage.removeItem('name')
//本地存储复杂数据类型
const obj = {
id: 1,
uname:'gzbn',
hobby:['吃饭','睡觉','玩游戏']
}
//需要将复杂数据类型转换成JSON字符串,再存储到本地
localStorage.setItem('obj',JSON.stringify(obj))
const objItem = localStorage.getItem('obj')
console.log(objItem);
//取出来的是字符串,不是对象,无法直接使用, 所以转化为字符串
console.log(JSON.parse(objItem))
</script>
</body>
1.5.正则表达式
1.5.1语法
console.log(/哈/.test(‘哈’))
1.5.2元字符
- 边界符(^ $)
- 量词(表示重复次数)
- 字符类([a-z] \d \s)
| 量词 | 说明 |
|---|---|
| + | 重复至少1次 |
| ? | 重复0次或1次 |
| * | 重复0次或多次 |
| {m,n} | 重复m到n次 |
| 字符类 | 说明 |
|---|---|
| \d或[0-9] | 0-9都可以 |
| \D或[^0-9 ] | 除0-9外的所有字符 |
| \w或[A-Za-z0-9_] | 匹配任意字母,数字,下划线 |
| \s或[\t\r\n\v\f] | 匹配空格(包括换行符,制表符,空格符等) |
| . | 匹配除换行符之外的任何单个字符 |
1.5.3修饰符
- i 是单词 ignore 的缩写,正则匹配时字母不区分大小写
- g 是单词 global 的缩写,匹配所有满足正则表达式的结果
replace替换:
const str = '你是xx'
console.log(str.replace(/xx/,'好人'));
二.作用域&函数进阶&解构
2.1作用域
2.1.1作用域:
局部作用域(函数作用域和块作用域)和全局作用域(script标签 和 .js 文件)
总结:
- let const声明的变量会产生块作用域,var不会产生块作用域
- 推荐使用let/const
作用域链:会优先查找当前函数作用域中查找变量;查找不到则会依次逐级查找父级作用域直到全局作用域
2.1.2垃圾回收机制:
JS中内存的分配和回收都是自动完成的,内存在不使用的时候会被垃圾回收器自动回收
内存泄漏:不再用到的内存,没有及时释放,就叫做内存泄漏
堆栈空间分配:
- 栈(操作系统): 由操作系统自动分配释放函数的参数值、局部变量等,基本数据类型放到栈里面
- 堆(操作系统): 一般由程序员分配释放,若程序员不释放,由垃圾回收机制回收。复杂数据类型放到堆里面
常见浏览器垃圾回收算法:
- 引用计数法:是看一个对象是否有指向它的引用,没有引用了就回收对象,每引用一次就+1,减少就-1,引用次数为0,则释放内存(遇到循环引用会导致内存泄漏)
- 标记清除法:从根部扫描对象,能查找到的就是使用的,查找不到的就要回收
2.1.3闭包
闭包:内层函数 + 外层函数的变量
作用:封闭数据,实现数据私有,外部也可以访问函数内部的变量; 闭包很有用,因为它允许将函数与其所操作的某些数据(环境)关联起来
问题:可能引用内存泄漏
2.1.4变量提升
- var字声明变量会有变量提升
- 只提升变量声明, 不提升变量赋值
2.2函数进阶
2.2.1函数提升
函数表达式不存在提升的现象
fn()
function fn() {
console.log(1)
}
fn1()
var fn1 = function(){
console.log(1) //函数表达式不会提升
}
2.2.2函数参数
- 动态参数:arguments(伪数组,只存在于函数中) - 不确定函数参数个数时可使用
function sum(){
let s = 0
for(let i = 0;i < arguments.length; i++){
s += arguments[i]
}
console.log(s)
}
sum(2,3) //5
- 剩余参数:… 是语法符号,置于最末函数形参之前,用于获取多余的实参
function getNum2(a,b,...arg){
console.log(arg);//(2) [4, 5]
}
getNum2(2,3,4,5)
展开运算符:用于数组
const arr1 = [1,2,3]
const arr2 = [4,5]
console.log(...arr1)// 1 2 3
console.log(Math.max(...arr1)) //求最大值 3
console.log(...arr1,...arr2) //合并数组 1 2 3 4 5
2.2.3箭头函数
箭头函数语法总结:
- 只有一个参数时可以省略圆括号()
- 函数函数体只有一行代码时可以省略花括号{},并自动做为返回值
- . 加括号的函数体返回对象字面量表达式
箭头函数参数总结: - 普通函数有arguments 动态参数
- 箭头函数没有 arguments 动态参数,但是有 剩余参数 …args
//箭头函数1:基本写法
const fn1 = () => {
console.log('箭头函数写法');
}
//箭头函数2:只有一个参数时
const fn2 = x => {
console.log('只有一个参数时,可省去()');
}
//箭头函数3:函数体只有一行时,可以写到一行上,可省去return关键字
const fn3 = () => console.log('函数体只有一行代码时')
const fn4 = (x,y) => x+y
console.log(fn4(1,2))
//箭头函数4:加括号的函数体返回对象字面量表达式
//不使用箭头函数
const fn6 = function(uname){
return{uname:uname}
}
console.log(fn6('oo'));
//使用箭头函数
const fn5 = uname => ({uname:uname})
console.log(fn5('gzbn'));
箭头函数this:箭头函数不会创建自己的this,它只会从自己的作用域链的上一层沿用this
2.3解构
2.3.1数组解构
是将数组的单元值快速批量赋值给一系列变量的简洁语法
// 3.剩余参数 变量少, 单元值多
const [tou,shou,...body] = ['头','手','脚','腿']
console.log(tou); //头
console.log(shou); // 手
console.log(body);// (2) ['脚', '腿']
// 4. 防止 undefined 传递
const [x = 0, z = 0] = [1, 2]
// const [a = 0, b = 0] = []
console.log(x) // 1
console.log(z) // 2
// 5. 按需导入赋值
const [u, v, , w] = [1, 2, 3, 4]
console.log(u) // 1
console.log(v) // 2
console.log(w) // 4
// 多维数组解构
// const arr = [1, 2, [3, 4]]
const [h, i, j] = [1, 2, [3, 4]]
console.log(h) // 1
console.log(i) // 2
console.log(j) // [3,4]
2.3.2对象解构
是将对象属性和方法快速批量赋值给一系列变量的简洁语法
// 1. 对象解构的变量名 可以重新改名 旧变量名: 新变量名
const { uname: username, age } = { uname: 'gzbn', age: 18 }
console.log(username);//gzbn
console.log(age);//18
三.构造函数&常用函数
3.1深入对象
3.1.1创建函数的方式
- {}
- new Object({})
- 构造函数
<body>
<script>
//创建对象 1
const obj1 = {
name:'leo',
age:18
}
//创建对象2 new Object
const obj2 = new Object({uname:'aa',age:18})
//创建对象3 构造函数
// 以下面为例:name age属于实例成员 count属于静态成员
function Pig(name,age){
this.name = name
this.age = age
}
const obj3 = new Pig('ll',14)
console.log(obj1);//{name: 'leo', age: 18}
console.log(obj2);//{uname: 'aa', age: 18}
console.log(obj3);//Pig {name: 'll', age: 14}
Pig.count = 10
console.log(Pig.count);// 10
</script>
</body>
3.1.2实例成员与静态成员
实例对象的属性和方法即为实例成员;构造函数的属性和方法被称为静态成员
3.2内置构造函数
Object、Array、String、Number等
3.2.1Object
常用静态方法:
- keys():获取所有的属性
- values():获取所有的属性值
- assign(NewObj,obj):对象拷贝
3.2.2Array
常用方法:
- map():返回新数组,新数组里面的元素是处理之后的值,经常用于处理数据
- forEach():不返回,用于不改变值,经常用于查找打印输出值
- filter(): 筛选数组元素,并生成新数组
- reduce():返回函数累计处理的结果,经常用于求和等
- from():伪数组转换为真数组
- splice() join() concat()…
3.2.3String
常用方法:
- split():将字符串拆分成数组
- substring():字符串截取
- startWith():判断是否以某字符串开头
- match():查找字符串
- …
3.2.4Number
- toFixed() 设置保留小数位的长度
- …
四.构造函数深度解析
4.1编程思想
- 面向过程编程:分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候再一个一个的依次 调用就可以了。
- 面向对象编程:面向对象是把事务分解成为一个个对象,然后由对象之间分工与合作。
总结:
| 优点 | 缺点 | |
|---|---|---|
| 面向过程 | 性能比面向对象高 | 没有面向对象易维护、易复用、易扩展 |
| 面向对象 | 易维护、易复用、易扩展 | 性能比面向过程低 |
4.2构造函数
构造函数缺点:浪费内存
function Star(uname,age){
this.uname = uname
this.age = age
this.sing = function(){
console.log('唱歌');
}
}
const ldh = new Star('ldh',14)
const zxy = new Star('zyx',14)
console.log(ldh === zxy);//false
console.log(ldh.sing === zxy.sing);//false
问题:ldh和zxy时两个不同的对象,所以创建了两个对象,创建了两个sing
4.3原型
4.3.1原型对象prototype
每一个构造函数都有一个 prototype 属性,指向另一个对象,所以我们也称为原型对象
- 通过原型分配的函数是所有对象共享的
- 原型对象实例化不会多次创建原型上函数,节约内存
- 构造函数和原型的this指向实例化对象
作用:共享方法;把那些不变的方法,直接定义在 prototype 对象上
4.3.2constructor 属性
每个原型对象里面都有个constructor 属性(constructor 构造函数),属性指向该原型对象的构造函数
作用:指向该原型对象的构造函数
4.3.3对象原型__proto__
对象都会有一个属性__proto__ 指向构造函数的 prototype 原型对象,之所以我们对象可以使用构造函数 prototype 原型对象的属性和方法,就是因为对象有__proto__ 原型的存在。
对象原型里面也有一个 constructor属性,指向创建该实例对象的构造函数
4.3.4原型继承
问题:男人和女人都同时使用了同一个对象,根据引用类型的特点,他们指向同一个对象,修改一个就会都影响
需求:男人和女人不要使用同一个对象,但是不同对象里面包含相同的属性和方法
解决:构造函数 new 每次都会创建一个新的对象
4.3.5原型链
查找规则:
- 当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性
- 如果没有就查找它的原型(也就是__proto__指向的 prototype 原型对象)
- 如果还没有就查找原型对象的原型(Object的原型对象)
- 依此类推一直找到 Object 为止(null)
- 对象原型的意义就在于为对象成员查找机制提供一个方向,或者说一条路线
- 可以使用 instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上
五.进阶
5.1深浅拷贝
5.1.1浅拷贝
拷贝的是地址
常见方法:
- 拷贝对象:Object.assgin() / 展开运算符 {…obj} 拷贝对象
- .拷贝数组:Array.prototype.concat() 或者[…arr]
5.1.2深拷贝
拷贝的是对象,不是地址
常见方法:
- lodash/cloneDeep
- 通过JSON.stringify()实现
5.2异常处理
- throw new Error() - 抛出异常
- try/catch/finally - 捕获异常
- debugger
5.3处理this
函数内不存在this,沿用上一级的,过程:向外层作用域中,一层 一层查找this,直到有this的定义
场景:
- 不适用构造函数,原型函数,字面量对象中函数,dom事件函数
- 适用需要使用上层this的地方
5.3.1改变this
- fn.call(thisArg, arg1, arg2, …)
- fn.apply(thisArg, [argsArray]) argsArray必须是个数组
- fn.bind(thisArg, arg1, arg2, …) 不会调用函数
<body>
<button>点击</button>
<script>
// call()
const obj={age:14}
function fn(x){
console.log(this); //{age: 14}
console.log(x); //1
}
fn.call(obj,1)
// apply()
const arr = [100, 44, 77]
const max = Math.max.apply(Math, arr)
const min = Math.min.apply(null, arr)
console.log(max, min)
// bind()
// 需求,有一个按钮,点击里面就禁用,2秒钟之后开启
document.querySelector('button').addEventListener('click', function () {
// 禁用按钮
this.disabled = true
window.setTimeout(function () {
// 在这个普通函数里面,我们要this由原来的window 改为 btn
this.disabled = false
}.bind(this), 2000) // 这里的this 和 btn 一样
})
</script>
</body>
5.4性能优化
5.4.1防抖
触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间
5.4.2节流
指连续触发事件但是在 n 秒中只执行一次函数
案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
.box {
width: 500px;
height: 500px;
background-color: #ccc;
color: #fff;
text-align: center;
font-size: 100px;
}
</style>
</head>
<body>
<div class="box"></div>
<script src="js/lodash.min.js"></script>
<script>
const box = document.querySelector('.box')
let i = 1 // 让这个变量++
// 鼠标移动函数
function mouseMove() {
box.innerHTML = i++
// 如果里面存在大量操作 dom 的情况,可能会卡顿
}
// box.addEventListener('mousemove', mouseMove)
// lodash 节流写法
box.addEventListener('mousemove', _.throttle(mouseMove, 3000))
// lodash 防抖的写法
// box.addEventListener('mousemove', _.debounce(mouseMove, 500))
</script>
</body>
</html>

被折叠的 条评论
为什么被折叠?



