JS实现深拷贝、instanceof、判断是否为数组

WEB前端 206 2018-10-24 16:54

JS深拷贝

JS中拷贝对象可以按照拷贝的程度可以分为浅拷贝和深拷贝,有些时候我们需要拷贝之后的对象和拷贝之前的对象解耦,即脱离联系,也就是改变其中一者,另一者不会变化,典型的场景有:状态的回溯。如果我们对状态对象使用浅拷贝,则无法对状态进行回溯,但如果使用深拷贝,则可以很容易的对状态进行回溯和跟踪。实现深拷贝,主要由以下两种方式:(值得一提的是,JS原生数组中的 concat、slice 方法还有 Object.assign 方法都是一层拷贝,即浅拷贝)

  1. JSON (缺点:无法拷贝函数)
function copy(o) {
    return JSON.parse(JSON.stringify(o))
}
  1. 递归实现
var deepCopy = function(obj) {
    if (typeof obj !== 'object') return obj
    var newObj = (Object.prototype.toString.call(obj) === '[object Array]') ? [] : {}
    for (var key in obj) {
        if (obj.hasOwnProperty(key)) {
            newObj[key] = (typeof obj[key] !== 'object') ? obj[key]: deepCopy(obj[key])
        }
    }
    return newObj
}

instanceof

instanceof 是用来判断对象是是某类的实例,或者是否是某类的子类的实例,它的实现原理可以是下面这样,L 表示实例,R 表示某类。

function instanceOf(L, R) {
    R = R.prototype
    L = L.__proto__
    while (true){
        if (L === null)
            return false
        if (R === L) 
            return true
        L = L.__proto__
    }
}

判断是否为数组

JS中数组也属于对象,所以无法通过 typeof 直接判断,这个时候就得采用其他方式,主要有一下几种方式:

  1. 使用 instanceof
var arr = []
console.log(arr instanceof Array)
  1. 使用 constructor
var arr = []
console.log(arr.constructor === Array)
  1. 判断对象是否有 push 等数组的一些方法
var arr = []
console.log(!!arr.push && !!arr.concat)
  1. 使用对象的 toString
var arr = []
console.log(Object.prototype.toString.call(arr) === '[object Array]')
  1. 使用 ES5 中的 Array.isArray 方法
var arr = []
console.log(Array.isArray(arr))

方法 1-3 有兼容性问题,方法 5 可能不兼容老款浏览器,所以最好使用方法 4

文章评论