JavaScript进阶核心知识(4)

深入理解JavaScript中的深浅拷贝、异常处理、this处理和防抖节流

在JavaScript开发中,我们常常会遇到深浅拷贝、异常处理、this处理和防抖节流这些重要概念。掌握这些概念对提升代码质量和开发效率至关重要。本文将详细介绍这些内容,并附上代码实例进行说明。

1. 深浅拷贝

1.1 浅拷贝

浅拷贝是指复制对象的引用,而不是复制对象本身。复制后的新对象与原对象共享同一块内存空间,对新对象的修改会影响原对象。

示例
const original = { a: 1, b: { c: 2 } };
const shallowCopy = Object.assign({}, original);

console.log(shallowCopy); // 输出: { a: 1, b: { c: 2 } }

shallowCopy.b.c = 3;
console.log(original.b.c); // 输出: 3,原对象也受到了影响
  1. 直接赋值和浅拷贝有什么区别?
  • 直接赋值的方法,只要是对象,都会相互影响,因为是直接拷贝对
    象栈里面的地址
  • 浅拷贝如果是一层对象,不相互影响,如果出现多层对象拷贝还会
    相互影响
  1. 浅拷贝怎么理解?
  • 拷贝对象之后,里面的属性值是简单数据类型直接拷贝值
  • 如果属性值是引用数据类型则拷贝的是地址

1.2 深拷贝

深拷贝是指递归复制对象的每一层结构,生成一个完全独立的新对象。深拷贝后的新对象与原对象互不影响。

1.2.1 递归实现深拷贝

通过递归方式实现深拷贝,可以处理嵌套对象。

示例
 <script>
    const obj = {
      uname: 'pink',
      age: 18,
      hobby: ['乒乓球', '足球'],
      family: {
        baby: '小pink'
      }
    }
    const o = {}
    // 拷贝函数
    function deepCopy(newObj, oldObj) {
      for (let k in oldObj) {
        // 处理数组的问题  一定先写数组 在写 对象 不能颠倒
        if (oldObj[k] instanceof Array) {//检查一个对象是否是另一个对象的实例
          newObj[k] = []
          //  newObj[k] 接收 []  hobby
          //  oldObj[k]   ['乒乓球', '足球']
          deepCopy(newObj[k], oldObj[k])
        } else if (oldObj[k] instanceof Object) {
          newObj[k] = {}
          deepCopy(newObj[k], oldObj[k])
        }
        else {
          //  k  属性名 uname age    oldObj[k]  属性值  18
          // newObj[k]  === o.uname  给新对象添加属性
          newObj[k] = oldObj[k]
        }
      }
    }
    deepCopy(o, obj) // 函数调用  两个参数 o 新对象  obj 旧对象
    console.log(o)
    o.age = 20
    o.hobby[0] = '篮球'
    o.family.baby = '老pink'
    console.log(obj)
    console.log([1, 23] instanceof Object)
  </script>

1.2.2 lodash 库中的 cloneDeep

lodash 是一个非常流行的 JavaScript 工具库,其中的 cloneDeep 方法可以方便地实现深拷贝。

示例
const _ = require('lodash');

const original = { a: 1, b: { c: 2 } };
const deepCopy = _.cloneDeep(original);

deepCopy.b.c = 3;
console.log(original.b.c); // 输出: 2,原对象未受到影响

1.2.3 JSON序列化

通过 JSON.stringifyJSON.parse 可以实现深拷贝,但不能处理函数和 undefined

示例
const original = { a: 1, b: { c: 2 } };
const deepCopy = JSON.parse(JSON.stringify(original));

deepCopy.b.c = 3;
console.log(original.b.c); // 输出: 2,原对象未受到影响

小结

  • 浅拷贝 只复制对象的引用,适用于非嵌套对象。
  • 深拷贝 递归复制对象的每一层,适用于嵌套对象。
  • 使用 lodashcloneDeep 或 JSON 序列化可以方便地实现深拷贝。

2. 异常处理

2.1 throw

throw 语句用于抛出一个用户自定义的异常。

示例
function divide(a, b) {
    if (b === 0) {
        throw new Error('Division by zero is not allowed.');
    }
    return a / b;
}

try {
    console.log(divide(4, 0));
} catch (e) {
    console.error(e.message); // 输出: Division by zero is not allowed.
}

2.2 try...catch

try...catch 语句用于捕获和处理异常。try 代码块中包含可能抛出异常的代码,catch 代码块中包含处理异常的代码。

示例
try {
    const result = divide(4, 0);
    console.log(result);
} catch (error) {
    console.error('An error occurred:', error.message); // 输出: An error occurred: Division by zero is not allowed.
}

2.3 debugger

debugger 语句用于暂停代码执行并打开调试工具。

示例
function debugExample() {
    const x = 10;
    const y = 20;
    debugger; // 代码在这里暂停,可以在浏览器控制台查看变量的值
    return x + y;
}

console.log(debugExample()); // 浏览器会暂停在 debugger 处

小结

  • throw 用于抛出自定义异常。
  • try...catch 用于捕获和处理异常。
  • debugger 用于调试代码。

3. 处理 this

3.1 普通函数

在普通函数中,this 的值取决于函数的调用方式。

示例
const obj = {
    value: 42,
    getValue: function() {
        return this.value;
    }
};

console.log(obj.getValue()); // 输出: 42

3.2 箭头函数

箭头函数没有自己的 this,它继承自外层作用域的 this

示例
const obj = {
    value: 42,
    getValue: () => {
        return this.value; // 箭头函数的 this 继承自外层,这里的 this 指向全局对象
    }
};

console.log(obj.getValue()); // 输出: undefined

3.3 改变 this 指向

3.3.1 call

call 方法可以调用一个函数,并显式地指定 this 的值。

示例
<script>
  // 普通函数
  function sayHi() {
    console.log(this);
  }

  let user = {
    name: '小明',
    age: 18
  }

  let student = {
    name: '小红',
    age: 16
  }

  // 调用函数并指定 this 的值
  sayHi.call(user); // this 值为 user
  sayHi.call(student); // this 值为 student

  // 求和函数
  function counter(x, y) {
    return x + y;
  }

  // 调用 counter 函数,并传入参数
  let result = counter.call(null, 5, 10);
  console.log(result);
</script>
  1. call 方法能够在调用函数的同时指定 this 的值
  2. 使用call方法调用函数时,第1个参数为 this 指定的值
  3. call 方法的其余参数会依次自动传入函数做为函数的参数
3.3.2 apply

apply 方法与 call 类似,但接受参数数组。

示例
function greet(greeting, punctuation) {
    console.log(`${greeting}, my name is ${this.name}${punctuation}`);
}

const person = { name: 'Bob' };
greet.apply(person, ['Hi', '!']); // 输出: Hi, my name is Bob!

在这里插入图片描述

3.3.3 bind

bind 方法创建一个新的函数,并永久绑定 this 的值。

示例
function greet() {
    console.log(`Hello, my name is ${this.name}`);
}

const person = { name: 'Charlie' };
const boundGreet = greet.bind(person);
boundGreet(); // 输出: Hello, my name is Charlie

小结

  • 普通函数中的 this 取决于调用方式。
  • 箭头函数没有自己的 this,继承自外层作用域。
  • callapplybind 方法可以显式地改变 this 的指向。

4. 防抖节流

防抖(Debounce)

防抖技术用于限制函数在一定时间间隔内只执行一次。如果在这个时间间隔内函数被再次调用,则重新计时。

示例
function debounce(func, delay) {
    let timeout;
    return function(...args) {
        clearTimeout(timeout);
        timeout = setTimeout(() => func.apply(this, args), delay);
    };
}

window.addEventListener('resize', debounce(() => {
    console.log('Resize event handler called');
}, 300));

节流(Throttle)

节流技术用于限制函数在一定时间间隔内最多执行一次,不管这个时间间隔内函数被调用多少次。

示例
function throttle(func, interval) {
    let lastTime = 0;
    return function(...args) {
        const now = Date.now();
        if (now - lastTime >= interval) {
            lastTime = now;
            func.apply(this, args);
        }
    };
}

window.addEventListener('scroll', throttle(() => {
    console.log('Scroll event handler called');
}, 300));

在这里插入图片描述

小结

  • 防抖:在指定时间间隔内多次调用只执行一次,适用于减少高频率事件的调用次数。
  • 节流:在指定时间间隔内限制函数调用次数,适用于控制事件处理频率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值