js 手撕浅拷贝和深拷贝
时间: 2024-09-10 15:23:30 浏览: 125
浅拷贝和深拷贝是JavaScript中复制对象时需要考虑的两种不同方式。
浅拷贝(Shallow Copy)指的是创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是引用类型,拷贝的就是内存地址,因此如果其中一个对象改变了这个地址,就会影响到另一个对象。浅拷贝可以通过如下方式实现:
1. 使用扩展运算符(...):`let obj2 = {...obj};`
2. 使用Object.assign()方法:`let obj2 = Object.assign({}, obj);`
3. 使用Array.prototype.slice()方法:`let arr2 = arr.slice();`
深拷贝(Deep Copy)则是创建一个新对象,且完全复制原对象的所有层级,如果属性是引用类型,会递归复制下去,不会复制原有对象的引用。这样,新对象和原对象就不会互相影响。深拷贝的实现比较复杂,可以使用以下方式:
1. 使用JSON.parse()和JSON.stringify()方法:`let obj2 = JSON.parse(JSON.stringify(obj));`
注意这种方法不能复制函数、undefined、循环引用的对象。
2. 手写递归函数实现深度拷贝:自定义一个函数,通过判断属性的类型,如果是基本类型则直接拷贝,如果是引用类型则递归调用深度拷贝函数。
相关问题
JavaScript手撕题
### JavaScript 手撕题目概述
对于JavaScript手撕题目,在面试或者日常练习中,这些题目旨在考察开发者对语言特性和底层原理的理解程度。下面列举了一些常见的手撕题目及其具体实现方式。
#### 新建对象实例 (New)
新建对象实例的过程可以通过模仿`new`关键字的行为来完成。当使用`new`创建一个函数的实例时,会执行一系列特定的操作[^1]:
```javascript
function myNew(constructor, ...args) {
const obj = Object.create(constructor.prototype);
const result = constructor.apply(obj, args);
return typeof result === 'object' ? result : obj;
}
```
此代码片段展示了如何手动实现`new`操作符的功能,通过`Object.create()`方法设置新对象的原型链,并利用`apply()`调用构造器函数。
#### 冻结对象 (Freeze)
冻结对象意味着防止任何修改发生于该对象上,这可以借助`Object.freeze()`方法达成。为了更好地理解其工作机理,也可以尝试自己编写类似的逻辑:
```javascript
function customFreeze(target) {
// 获取目标对象所有的属性名
let propNames = Object.getOwnPropertyNames(target);
// 对每一个属性进行遍历处理
for (let name of propNames) {
let desc = Object.getOwnPropertyDescriptor(target, name);
if ('value' in desc && typeof desc.value === "object") {
customFreeze(desc.value); // 递归冻结嵌套的对象
}
// 设置当前属性为不可配置且只读
target[name] = { writable: false, configurable: false };
}
// 返回经过处理后的对象
return Object.preventExtensions(target);
}
```
这段代码实现了基本的对象冻结功能,包括阻止新增或删除属性以及改变已有属性特性等行为。
#### 创建继承关系 (Create)
除了上述两个例子外,还有其他重要的概念如`Object.create()`用于建立新的空对象并指定其[[Prototype]]链接指向给定的对象。这里给出了一种可能的手工版本[^3]:
```javascript
function create(proto, propertiesObject) {
function F() {}
F.prototype = proto;
var instance = new F();
if (propertiesObject !== undefined) {
Object.defineProperties(instance, propertiesObject);
}
return instance;
}
```
以上就是几个典型的JavaScript手撕题目案例,它们有助于加深学习者对核心机制的认识。
auc手撕
### 如何手动计算 AUC
AUC 是 ROC 曲线下的面积,用于评估分类模型的质量。以下是关于如何通过公式推导并实现 AUC 的详细说明。
#### 手动计算 AUC 的基本原理
为了计算 AUC 值,可以采用积分的思想来近似求解曲线下的面积。具体来说,可以通过以下步骤完成:
1. **数据准备**
将正类样本和负类样本的预测概率分别提取出来,并按预测概率降序排列[^3]。
2. **计算 FPR 和 TPR**
对于每一个阈值(即预测概率),计算对应的假阳性率 (False Positive Rate, FPR) 和真阳性率 (True Positive Rate, TPR):
- \( \text{FPR} = \frac{\text{FP}}{\text{N}} \),其中 FP 表示假阳性的数量,N 表示总负样例数。
- \( \text{TPR} = \frac{\text{TP}}{\text{P}} \),其中 TP 表示真阳性的数量,P 表示总正样例数。
3. **排序与间距计算**
按照横坐标 FPR 排序后,依次计算每两个相邻点之间的水平距离 (\(dx\)) 和垂直高度 (\(y\)):
- \( dx_i = \text{FPR}_{i+1} - \text{FPR}_i \)
- 取当前点或下一个点的高度作为 \( y_i \)
4. **面积微元累加**
使用梯形法则逐段逼近曲线下方的面积:
\[
ds_i = y_i \cdot dx_i
\]
总面积为所有微元之和:
\[
\text{AUC} = \sum_{i=0}^{n-1} ds_i
\]
#### Python 实现代码
下面是一个简单的 Python 脚本,展示如何基于上述理论手动计算 AUC:
```python
def calculate_auc(fpr_list, tpr_list):
auc = 0.0
prev_fpr = fpr_list[0]
for i in range(len(fpr_list)):
current_fpr = fpr_list[i]
current_tpr = tpr_list[i]
if i > 0:
# Calculate the area of each trapezoid segment
dx = current_fpr - prev_fpr
height_avg = (tpr_list[i - 1] + current_tpr) / 2
auc += dx * height_avg
prev_fpr = current_fpr
return auc
# Example data points from an ROC curve
fpr_values = [0.0, 0.1, 0.3, 0.7, 1.0]
tpr_values = [0.0, 0.2, 0.5, 0.8, 1.0]
auc_value = calculate_auc(fpr_values, tpr_values)
print(f"AUC Value: {auc_value}")
```
此脚本实现了基于给定 FPR 和 TPR 列表的手动 AUC 计算逻辑。
---
###
阅读全文
相关推荐













