1.防抖和节流
1.1防抖
在高频操作下,我们只识别一次触发(可以控制开始触发或是最后一次触发),一般设置一个阀值,在这个阀值内无论你操作多少次,只执行一次。
function debounce(fn, wait = 500, now = true) {
// 定时器返回值标识
let timer = null
return function (...params) {
// 保存this指向
let self = this
// 如果设置了开始执行且计时器还没有运行 为 true
let start = now && !timer
// 清除上次定时器
clearTimeout(timer)
timer = setTimeout(function () {
timer = null
// 最后执行,注意改变this指向
!now ? fn.call(self, ...params) : null
}, wait);
// 点击就立刻执行 取决于第3个参数
start ? fn.call(self, ...params) : null
}
}
const clickFn = debounce(function (evt) {
console.log('点击按钮了', evt, this)
}, 500, true);
document.getElementById('button').onclick = clickFn
1.2 节流
在高频操作下,我们不是只识别一次,按照我们设定的间隔时长,操作的时长达到设置的时长就会触发一次。如:默认情况下,页面滚动中,浏览器在最快的反应时间内(4到6ms之间),就会认别一次事件触发,把绑定的方法执行,这样导致方法执行的次数过多,造成不必要的资源浪费。
function throttle(fn, wait = 500) {
// 定时器返回值标识
let timer = null
// 上一次操作的时间
let prevTime = 0
return function (...params) {
let self = this
// 当前这次触发操作的时间
let nowTime = new Date().getTime()
// 剩余时间
let remaining = wait - (nowTime - prevTime)
if (remaining <= 0) {
// 达到设置的触发时间
// 清除定时器
clearTimeout(timer)
timer = null
// 上一次操作时间为当前触发时间
prevTime = nowTime
// 两次间隔时间超过wait了,直接执行即可
fn.call(self, ...params)
} else if (!timer) { // 此条件满足,上一次没有达到时长去触发,就已经不进行操作了
// 没有超过设置时长,则设置定时器,让其等待
timer = setTimeout(function () {
clearTimeout(timer)
timer = null
prevTime = new Date().getTime()
fn.call(self, ...params)
}, remaining);
}
}
}
const scrollFn = throttle(function (ev) {
console.log('ok', ev)
});
window.onscroll = scrollFn
2.js中的对象
对象是包括属性与方法的数据类型,JS中大部分类型都是对象如String、Boolean、Symbol、Number、BigInt、Object、Array、RegExp、Date、Function 等
2.1 对象的计算
1.对象直接参与计算时,系统会根据计算的场景在 string/number/default 间转换
2.对象内部自定义Symbol.toPrimitive、valueOf、toString方法用来处理所有的转换场景
let obj = {
name: "张三",
num: 1,
/*
// 它的优先级最高,它存在后,其它的方法将不会查找
[Symbol.toPrimitive]: function () {
return this.num;
}, */
// 如果没有toPrimitive方法,则计算时会先找它,它不存在时再找toString
valueOf: function () {
return this.num;
},
toString: function () {
return this.name;
}
};
console.log(obj + 1)
console.log(`你好 -- ${obj}`)
2.2对象解构赋值
/* var obj = { id: 1, name: '张三' }
// 解构原则,看右边,如果是对象则key相同,如果是数组,名称随意,右左类型相同
var { id, name } = obj
console.log(id, name) */
// ====================================
/* var obj = { id: 1, child: [{ tag: 'li' }] }
var { id, child: [{ tag }] } = obj
console.log(id, tag) */
// ====================================
/* var obj = { id: 1, child: [1, 2, 3, { tag: 'div' }] }
// var { id, child: [a, b, c, { tag }] } = obj
var { id, child: [, , c, { tag }] } = obj
console.log(c, tag) */
// ====================================
/* var arr = [1,2,3]
var [a,b,c] = arr
console.log(a) */
// ====================================
/* var obj = { title: '网页标题' }
// :给原来的名称另一个名称, =给变量赋值默认值
var { title: aa, url = '网址' } = obj
console.log(aa, url)*/
// ====================================
/* function fn({
id = 1,
name = '张三',
age
}) {
return { id, name, age }
} */
/* function fn(opts) {
let {
id = 1,
name = 'aaa',
age
} = opts
return { id, name, age }
} */
/*
function fn(opts) {
let obj = { ...opts, id: 1, name: '张三' };
return obj
}
*/
// console.log(fn({ age: 20 }))
2.3 属性管理
// 添加属性
// obj.name = 'aaa'
// obj['name1'] = 'aaabb'
// console.log(obj)
//============================
// 删除属性
/* delete obj.id
console.log(obj) */
//===============================
// 检测属性
/* var obj = {
id: 1,
name: 'abc'
};
console.dir(obj) */
// 检查指定名称是否是当前对象的私有属性
// console.log(obj.hasOwnProperty('name'))
// in 关键词它可以检查公有属性, 先私和后公 它会在__proto__(原型链)中去找
// console.log('name' in obj)
// 检查当前给定属性是否为公有
// console.log(!obj.hasOwnProperty('name') && ('name' in obj))
/* console.log(isPublic(obj, 'id'))
//========================================
// 打印当前对象私有属性,但不能获取到Symbol设置属性
// console.log(Object.keys(obj))
// console.log(Object.getOwnPropertyNames(obj))
// 获取value值 私有属性中的value值
// console.log(Object.values(obj))
// 专门用于获取Symbol对象属性
// console.log(Object.getOwnPropertySymbols(obj))
// 得到当前对象中所有的私有属性
/* let arr = [
...Object.getOwnPropertyNames(obj),
...Object.getOwnPropertySymbols(obj)
];
//==================================
// 不可枚举,循环不可以读出来,起到一个保护作用 vue2.0核心
// 不可枚举不代码,不可以直接去调用 xxx.属性
/* Object.definePropertie({}, 'aa', {
enumerable: false
}) */
//=====================================
// obj1中的属性,此时,相对于obj2就是公有的属性
// obj2.__proto__ = obj1
// Object.setPrototypeOf(obj2, obj1)
// console.log(Object.getOwnPropertyNames(obj2))
// 对象的迭代 for in
// in 迭代原型链中所有可枚举的属性
/* for (var key in obj2) {
console.log(key)
} */
//========================================
// 严格模式 禁止给对象添加属性设置后,开启了严格模式,如果你还添加属性,则报错,后续代码将不执行
//在非严格模式中程序不会报错,但也添加不了属性
// 'use strict';
/* var obj = {
id: 1
}
console.log(111)
// 禁用属性可添加
Object.preventExtensions(obj)
obj.name = 'aaa'
obj.id = 10000
console.log(222)
console.log(obj)
//============================================
// ============== 冻结对象 --> 把对象定义为一个常量
/* var obj = {
id: 1000
}
// 把对象冻结一下
Object.freeze(obj)
// 查看对象是否是冻结对象
// console.log(Object.isFrozen(obj))
obj.id = 12
console.log(obj) */
//=============================================
// ============== 修改器和获取器
const _idsy = Symbol()
var obj = {
// 私有属性
[_idsy]: 1000,
// 调用时,不能把它当用方法,当作属性
// es6+ 获取器 帮助获取属性值
get id() {
if (this[_idsy] > 100) {
return '长寿'
}
return this[_idsy]
},
// 调用时,不能把它当用方法,当作属性
// es6+ 修改器,修改成属性
set id(value) {
// 写条件
value = isNaN(Number(value)) ? 0 : Number(value)
this[_idsy] = value
}
}
2.4对象拷贝
// es6+ 扩展运算符
/* let obj2 = {...obj1}
obj2.id = 10000
console.log(obj1,obj2) */
// assign合并对象
// 把源1,源2等这些对象给合并到目标对象上,并且把此对象返回,此对象地址和源1和源2等地址不关联
// Object.assign(目标,源1,源2,...)
/* var obj1 = {
id: 1
} */
/* var obj2 = {}
var obj3 = Object.assign(obj2, obj1)
obj2.id = 10000
console.log(obj2 === obj3)
console.log(obj3, obj2, obj1)
var obj2 = {}
Object.assign(obj2, obj1)
obj2.id = 10000
console.log(obj2, obj1)
*/
//=========================================
// 深拷贝
/* var obj2 = deepClone(obj1)
obj2.id = 10000
obj2.user.name = '换中文'
console.log(obj2, obj1) */
/* var obj2 = {
...obj1,
user: { ...obj1.user }
}
obj2.id = 10000
obj2.user.name = '换中文'
console.log(obj2, obj1)
*/
//=============================================
// 字面量对象 {}
function deepClone(obj) {
if (typeof obj !== "object") return obj
// 判断当前传入过来的数据对象还是数组
let target = 'push' in obj ? [] : {};
/* for (var key in obj) {
if (obj.hasOwnProperty(key)) {
if (typeof obj[key] == 'object') {
target[key] = deepClone(obj[key])
} else {
target[key] = obj[key]
}
}
} */
for (var [key, value] of Object.entries(obj)) {
target[key] = typeof value == 'object' ? deepClone(value) : value
}
return target
}