防抖和节流

本文详细介绍了JavaScript中的防抖和节流技术,用于优化高频操作,避免资源浪费。同时,讲解了JavaScript对象的特性,包括对象的计算、解构赋值、属性管理和对象拷贝。通过实例展示了如何实现对象的深拷贝,以及对象的getter和setter方法。内容深入浅出,有助于提升JavaScript编程技能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值