js原型、继承、深拷贝之间的关系

152 阅读2分钟

js 对象之间的关系仔细分析是有着环环相扣的关系,今天来说说继承吧

构造函数

首先来看一个构造函数

function Person(name) {
          this.name = name
         this.age = 20
         this.hobby = function() {
             console.log('篮球')
         }
     }

    // 对象的比较方法  1.值 2.内存地址
    let zhangsan = new Person('张三')
    let lisi = new Person('李四')
    console.log(zhangsan.hobby === lisi.hobby) //false

new 开辟了新的内存地址,值相同,耗费性能; 如何节约内存空间? 请看下面的原型继承

原型继承

 function Person(name) {
          this.name = name
         this.age = 20
     }
         Person.prototype.hobby = function() {
        console.log('篮球')
    }

    Person.prototype.fn = function() {
        // ...
    }

    let zhangsan = new Person('张三')
    let lisi = new Person('李四')
    console.log( Person.prototype === zhangsan.__proto__)


    console.log(zhangsan.hobby === lisi.hobby) //true

功能空间原型: 当存在公共功能或变量时,可以放在原型上,原型是公用的,原型中的this也是指向实例化对象,也就是说在原型中统一可以拿到Person中的name、age

上面的代码看起来好像解决了性能问题,但是也不是完全适用的,比如说
 function Dad(name, age) {
        this.name = name
        this.age = age
        this.money = "10000"
    }

    Dad.prototype.fn = function() {
        console.log('fn')
    }

    function Son(name, age) {
        Dad.call(this, name, age)
        this.sex = 'man'
    }
        // zhangsan.fn()  报错

    // let zhangsan = new Son("zhansgan", 20)
    console.log(zhangsan.money) //10000
    
    Dad.prototype = Son.prototype // 引用地址一样
    Son.prototype.fn = function() {
        console.log('重写fn')
    }
    
    let zhangsan = new Son()
    // console.log(zhangsan.fn)  重写fn
    
    let zhangyi = new Dad()
    // console.log(zhangyi.fn)  重写fn  父类的fn被改变了

    //复杂数据类型传值  地址之间有引用关系,相互影响

    // 简单数据类型传值 新开辟内存地址
    let a = 10
    let b = a
    b = 20
    console.log(a)  // 10

当遇到复杂类型时就不再适用了,如何解决请接着往下看

深拷贝

先来介绍下深拷贝 深拷贝
序列化: 1.先转换为json字符串,变成基本类型就会开辟新的内存空间

2.再转换为对象 实现方式:JSON.parse(JSON.stringify(obj))

缺点: 对象中出现function 、 undefined,会被丢失 只能拷贝一级,对象嵌套则无效

    let Dad = {
        name: 'zhangsan',
        age: 50,
    }

    
    let Son = JSON.parse(JSON.stringify(Dad))
    Son.name = 'xiaozhang' 
    console.log(Dad.name) //zhangsan
    console.log(Son.name) //xiaozhang

那我们就手动写一个方法实现深拷贝

1.新生成一个对象,用来拷贝,开辟新的引用地址

2.判断这个对象是否是array,因为array也属于对象,如果是就新建一个数组,如果不是
就新建一个对象

3.遍历循环每一项并拷贝,因为for in 循环的特性,会遍历循环对象上所有的属性包括
原型上的,但是我们只需要自身的,所以就用hasOwnProperty进行判断

4.如果是普通类型就直接复制,如果是对象就需要递归循环
 function deepCopy(obj) {
        let newObj = Array.isArray(obj) ? [] : {}
        for(key in obj) {
            if(obj.hasOwnProperty(key)) {
                if(typeof obj[key] === 'object') {
                    newObj[key] = deepCopy(obj[key])
                }else {
                    newObj[key] = obj[key]
                }
            }
        }
        return newObj
    }

当然,js中还有很多种继承方式,原生的继承方式自身也存在着一些局限,目前由于ES6运用的比较广泛,extends更好的解决了原生的局限性,感兴趣的小伙伴也可以去研究一下哦