1. 浅拷贝与深拷贝

1.1. js 数据类型

  • 基本数据类型:string, number, boolean, null, undefine, symbol

  • 引用数据类型:object, array, function

  • 区别:

    • 基本数据类型存储在栈内存中。

    • 引用数据类型在栈内存中存储的的是应用地址,这个应用地址指向堆内存对象。

1.2. 赋值,浅拷贝和深拷贝

  • 赋值:基本数据类型没问题,引用数据类型会指向同一个堆内存地址。

  • 浅拷贝:引用数据类型的浅拷贝,只会拷贝第一层。

    • Array.concat()

    • Object.assign()

    • es6 解构

const clone = source => {

  if (Object.prototype.toString.call(source)=== '[object Object]') {
    const newObj = {}
    for (let i in source) {
      if (source.hasOwnProperty(i)) {
        newObj[i] = source[i]
      }
    }
    return newObj
  }

  if (Object.prototype.toString.call(source)=== '[object Array]') {
    const newArr = []
    for (let [i, item] of source.entries()) {
      newArr[i] = item
    }
    return newArr
  }

}

const objects = {test: [{ 'a': 1 }, { 'b': 2 }]};

const newObj = clone(objects);

console.log({ objects, newObj }, newObj.test === objects.test);

const arr = [{ 'a': 1 }, { 'b': 2 }];

const newArr = clone(arr);

console.log({ arr, newArr }, newArr[0] === arr[0]);
  • 深拷贝:引用数据类型的深拷贝,不仅会拷贝第一层,还会递归深层次拷贝。

    • JSON.parse()和JSON.stringify() 无法识别 Symbol 类型, 无法识别循环引用的问题。

    • 递归

      • 特别注意:arr.entries() 是数组特有的方法,Object.entries(target) 适合数组和对象。

      • Object.prototype.toString.call: 判断数据类型

        • Object.prototype.toString.call(Symbol()) === '[object Symbol]'
        • Object.prototype.toString.call(new Date()) === '[object Date]'
        • Object.prototype.toString.call(new RegExp()) === '[object RegExp]'
        • Object.prototype.toString.call(null) === '[object Null]'
    const deepClone = target => {
      let result, targetType = Object.prototype.toString.call(target)
      if (targetType === '[object Object]') {
        result = {}
      } else if (targetType === '[object Array]') {
        result = []
      } else {
        return target
      }
      for (let [key, value] of Object.entries(target)) {
        result[key] = deepClone(value)
      }
      return result
    } 
    
    const objects = {test: [{ 'a': 1 }, { 'b': 2 }]};
    
    const newObj = deepClone(objects);
    console.log(newObj.test[0])
    
    • 上面的深拷贝代码,未考虑各种特殊类型的数据,例如:Date、RegExp、Symbol,最重要的是未考虑循环引用的问题。

      • for (let [key, value] of Object.entries(obj)) 无法识别 Symbol 作为 key 的情形

      • WeakMap 的特性:弱引用,游离于垃圾回收机制以外; hash.add() hash.has()

      • Object.keys() 与 Reflect.ownKeys() 的区别:Reflect.ownKeys() 可以遍历对象和数组

      • typeof: 判断数据类型

        • typeof null === 'object'
        • typeof new Date() === 'object'
        • typeof new RegExp() === 'object'
        • typeof Symbol() === 'symbol'
        • typeof function() {} === 'function'
    const deepClone = (obj, hash = new WeakSet()) => {
      if (obj === null) {
          return null
      }
    
      if (obj instanceof Date) {
          return new Date(obj)
      }
    
      if (obj instanceof RegExp) {
          return new RegExp(obj)
      }
    
      if (typeof obj !== 'object') {
          return obj
      }
    
      console.log({ hash, obj })
      if (hash.has(obj)) {
        return undefined
      }
    
      const resObj = Array.isArray(obj) ? [] : {}
      hash.add(obj)
    
      Reflect.ownKeys(obj).forEach(key => {
          resObj[key] = deepClone(obj[key], hash)
      })
    
      return resObj
    }
    

1.3. 深浅拷贝函数参数判断:对象和数组的判断方法

  • instanceof
const arr = [1, 2, 3, 4]
const obj = { a: 1 }

console.log(arr instanceof Array)
console.log(obj instanceof Object)

console.log(arr.__proto__ === Array.prototype)
console.log(obj.__proto__ === Object.prototype)
  • constructor
const arr = [1, 2, 3, 4]
const obj = { a: 1 }

console.log(arr.constructor === Array)
console.log(obj.constructor === Object)
  • toString
const arr = [1, 2, 3, 4]
const obj = { a: 1 }

console.log(Object.prototype.toString.call(arr) === '[object Array]')
console.log(Object.prototype.toString.call(obj)=== '[object Object]')
  • Array.isArray()
const arr = [1, 2, 3, 4]
const obj = { a: 1 }

console.log(Array.isArray(arr))
console.log(Array.isArray(obj))
  • length
const arr = [1, 2, 3, 4]
const obj = { a: 1 }

console.log(typeof arr && !isNaN(arr.length))
console.log(typeof obj && !isNaN(obj.length))
Copyright © tomgou 2022 all right reserved,powered by Gitbook该文章修订时间: 2023-08-28 17:33:23

results matching ""

    No results matching ""