Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

【JavaScript】赋值与深浅拷贝 #20

Open
Tracked by #6
swiftwind0405 opened this issue Mar 3, 2020 · 0 comments
Open
Tracked by #6

【JavaScript】赋值与深浅拷贝 #20

swiftwind0405 opened this issue Mar 3, 2020 · 0 comments

Comments

@swiftwind0405
Copy link
Owner

swiftwind0405 commented Mar 3, 2020

image


数据类型

先回忆一下JavaScript中的数据类型:

数据分为基本数据类型(String, Number, Boolean, Null, Undefined,Symbol)和引用数据类型。

  • 基本数据类型的特点:直接存储在栈(stack)中的数据
  • 引用数据类型的特点:存储的是该对象在栈中引用,真实的数据存放在堆内存里

引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。

image

赋值(Copy)

赋值是将某一数值或对象赋给某个变量的过程,分为下面 2 部分:

  • 基本数据类型:赋值,赋值之后两个变量互不影响
  • 引用数据类型:赋址,两个变量具有相同的引用,指向同一个对象,相互之间有影响

浅拷贝(Shallow Copy)

创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址 ,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。

浅拷贝使用场景:

  • Object.assign()
  • 展开语法 Spread
  • Array.prototype.slice() / Array.prototype.concat()

深拷贝(Deep Copy)

深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存。当对象和它所引用的对象一起拷贝时即发生深拷贝。深拷贝相比于浅拷贝速度较慢并且花销较大。拷贝前后两个对象互不影响。

深拷贝使用场景:

  • JSON.parse(JSON.stringify(object))
    该方法有以下几个问题:
    • 会忽略 undefined
    • 会忽略 symbol
    • 不能序列化函数
    • 不能解决循环引用的对象
    • 不能正确处理 new Date()
    • 不能处理正则
  • 手写递归方法(比如 jQuery 中的 extend()lodash 中的 cloneDeep()

三者的区别

-- 和原数据是否指向同一对象 第一层数据为基本数据类型 原数据中包含子对象
赋值 改变会使原数据一同改变 改变会使原数据一同改变
浅拷贝 改变不会使原数据一同改变 改变会使原数据一同改变
深拷贝 改变不会使原数据一同改变 改变不会使原数据一同改变

手动实现 Object.assign()

实现一个 Object.assign 大致思路如下:

  1. 判断原生 Object 是否支持该函数,如果不存在的话创建一个函数 assign,并使用 Object.defineProperty 将该函数绑定到 Object 上。
  2. 判断参数是否正确(目标对象不能为空,我们可以直接设置 {} 传递进去,但必须设置值)。
  3. 使用 Object() 转成对象,并保存为 to,最后返回这个对象 to
  4. 使用 for..in 循环遍历出所有可枚举的自有属性。并复制给新的目标对象(使用 hasOwnProperty 获取自有属性,即非原型链上的属性)。
if (typeof Object.assign2 != 'function') {
  // Attention 1
  //原生情况下挂载在 Object 上的属性是不可枚举的,但是直接在 Object 上挂载属性 a 之后是可枚举的,所以这里必须使用 Object.defineProperty
  Object.defineProperty(Object, "assign2", {
    value: function (target) {
	   // JS 对于不可写的属性值的修改静默失败(silently failed),在严格模式下才会提示错误
      'use strict';
      if (target == null) { // Attention 2
        throw new TypeError('Cannot convert undefined or null to object');
      }

      // Attention 3
      var to = Object(target);
        
      for (var index = 1; index < arguments.length; index++) {
        var nextSource = arguments[index];

        if (nextSource != null) {  // Attention 2
          // Attention 4
		  // 使用 for..in 遍历对象 nextSource 获取属性值
		  // 此处会同时检查其原型链上的属性
          for (var nextKey in nextSource) {
		    // 有的对象可能没有连接到 Object.prototype 上(比如通过 Object.create(null) 来创建),这种情况下,使用 object.hasOwnProperty(..) 就会失败,因此用 call
            if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
              to[nextKey] = nextSource[nextKey];
            }
          }
        }
      }
      return to;
    },
	// 默认值是 false,即 enumerable: false
    writable: true,
    configurable: true
  });
}

参考资料

@swiftwind0405 swiftwind0405 changed the title React Hooks 【Day12】浅拷贝与深拷贝 Mar 5, 2020
@swiftwind0405 swiftwind0405 changed the title 【Day12】浅拷贝与深拷贝 【Day13】浅拷贝与深拷贝 Mar 16, 2020
@swiftwind0405 swiftwind0405 changed the title 【Day13】浅拷贝与深拷贝 【Day15】浅拷贝与深拷贝 Mar 16, 2020
@swiftwind0405 swiftwind0405 changed the title 【Day15】浅拷贝与深拷贝 【Day15】数据类型与赋值及深浅拷贝 Mar 18, 2020
@swiftwind0405 swiftwind0405 changed the title 【Day15】数据类型与赋值及深浅拷贝 【Day15】赋值及深浅拷贝 Mar 28, 2020
@swiftwind0405 swiftwind0405 changed the title 【Day15】赋值及深浅拷贝 【Day15】赋值与深浅拷贝 Mar 28, 2020
@swiftwind0405 swiftwind0405 changed the title 【Day15】赋值与深浅拷贝 【JavaScript】赋值与深浅拷贝 Apr 29, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant