11-重点-全面剖析继承和拷贝

原形链继承/经典继承

 输出结果:由图可见,什么叫继承,就是创建的obj2这个对象的__proto__指向了obj的__proto__指向的Object的prototype

 

所以创建的obj2对象因为继承了obj,什么是原形链继承?就是Object的一个实例对象obj作为新创建的obj2对象的原型,那么新创建的对象就可以访问实例对象的私有属性和实例对象指向的原型的公有属性。

因为obj里面的属性值,就其实可以看做是 var obj = new Object() 

var obj = new Object({
    name: 'zs',
    age: 18,
    msg: {
        like: 'eat'
    }
})
因为复杂数据类型字面量创建方式和实例创建是一样的。都会开辟一块堆内存。

 

 跟上面字面量方式结果一样。

所以obj2就可以访问实例对象obj的私有属性,又因为他俩的__proto__都指向Object的原型,所以也就可以Object.prototype上的属性和方法。就如上图所示。

 所以如图所示,我们打印obj2访问了obj的私有属性name、msg下的like,及原型上的方法都能得到对应的结果


我们再用函数的类去再次阐明这个继承:

 输出结果:

所以同上面对象那个子类原型继承了父类的实例一样,整个原形链继承就是这样的:

子类的实例指向子类自己的原型 --> 子类自己的原型又继承了父类的实例  --> 父类的实例又指向父类的原型。

 所以子类的实例可以访问到父类实例的私有属性和父类的原型方法。如下输出确实如此:

 


每一个父类的实例都会自己开辟一个新的内存空间,有__proto__属性,指向父类的prototype,每一个实例的内存空间都会继承父类的私有属性。

子类的原型就是父类的一个实例,也就是子类的prototype原本浏览器会自动给自己开一个__proto__的内存空间,指向自己的prototype,现在子类的原型是父类的一个实例了,

那么原型都变成父类实例了,子类的实例又跟父类的实例一样,可以继承原型上的私有属性:

所以子类的原型上就有父类实例的私有属性,也就是父类的私有属性,也就是相当于子类实例就继承了父类的私有属性。

关键点在于,他们继承归继承,都会开辟一个新的内存空间,就是因为各自有各自的内存空间,只是把父类的私有属性给拿过来了一份放在自己的内存空间里。

所以各自修改各自的私有属性是完全不会对其他实例造成任何影响的。之间都是相互独立的。

我们可以看下面的输出:我们看看子类原型指向父类的实例,继承了父类的私有属性和公有属性。把继承的放在了哪?  不就是子类的原型上么

 输出结果:


 

原形链继承就是这个样子了。下面来说一说深浅拷贝:

深浅拷贝的区别就是:

浅拷贝如果拷贝的对象是一层,里面都是基本的key : value,就可以拷贝他的值。克隆一份。如果里面有复杂数据类型,比如key 对应一个对象,那么只是拷贝的对这个对象的空间地址的引用,指向。而不是值。这样就会造成拷贝的对象修改里面的复杂数据类型的值,被拷贝的对象也会改变,因为他俩公有一个空间地址。

深拷贝就是解决了浅拷贝里面有复杂类型值,可以单独开辟一个内存空间,拷贝一份一模一样的,并且跟原来的毫无关系。

那么问题来了:继承和拷贝放一起,会让人有点蒙圈。比如:

obj2继承了obj,那么obj3拷贝了obj2,能拷贝到obj2继承到的obj的值吗?如果不能,该怎么实现?

 

 输出结果:

 由此可以得出结论,拷贝一个对象,如果这个对象继承了别的对象,那么无论深浅拷贝,都不能拷贝到继承到的私有属性值。

如何解决呢?

再来巩固一下什么叫拷贝?

就是新开了一个内存空间,无论深浅拷贝,都会开辟。

只不过拷贝对象里是复杂数据类型的话,浅拷贝里拷贝的这个复杂数据类型是一个地址,但是基本类型是自己私有的,变化不会影响到被拷贝对象。

深拷贝是无论里面是基本数据类型还是复杂数据类型,都会全部拷贝。跟被拷贝对象完全没关系了以后。


 接着说上面的问题如何解决:

拷贝的对象因为是一个内存空间,自然就有__proto__,obj3,obj4不能拷贝到obj2的继承属性,是因为他不在这个继承链中,怎么会有呢?拷贝的对象的__proto__没有任何指向某个具体的对象,按照原形链往上一步步查找,他只能找到Object基类的原型。但是我们现在并不是要找到基类上的某个属性,我们是要拷贝obj2继承了obj的属性。

所以解决办法自然是,让拷贝的对象的__proto__跟obj2的__proto__一个指向,也就是obj2的prototype,obj2的原型上有obj所有的私有属性和公有方法(向上查找Object原型上的方法)。所以就是让拷贝对象关联上原形链,这样就能按照原形链的查找机制查找了。都找到组织了,那拷贝不就唾手可得了吗?

 先说一下,深拷贝不用关联,也不需要关联,为什么呢?

深拷贝本身就是需要自己独立成一个内存空间,不跟别人有瓜葛,你把他又塞到原型链上,他还是深拷贝吗?这是相悖的。

所以我们这里处理拷贝继承的值就是说的浅拷贝。

 输出结果:

 

 

这样拷贝的对象就能拷贝到obj2继承到obj的私有属性name值了。并且obj obj2 obj3的这些里面的name都是其各自的私有属性,各自改各自的不影响别人,但是改复杂数据类型msg,还是会全部都变一样的,因为他们是一个内存地址。

但是这时候再深拷贝obj3,还是拷贝个寂寞,因为obj3在原型链上了,深拷贝还是拷贝不到继承的值,因为他不在原形链上啊,他如果在原形链上,他还是深拷贝吗?所以这种情况只是浅拷贝来说的。


 for in 循环 

for in 循环遍历可以把对象私有属性和原型上定义的公有属性都遍历出来,我们通常获取一个对象都是获取的私有的,而不需要把原型上的公有的给获取到,所有就用hasOwnProperty去处理,只得到私有的。

for in 循环遍历一个对象,如果对象里有复杂数据类型,去拷贝的话,就是浅拷贝,只不过我们上面那种Object.assign是一种快捷写法。都是浅拷贝。

for in 循环如果做深拷贝的话需要用到递归。

for in 循环为啥又给继承扯一起了呢?比如做混入继承就是用的for in 循环,其实也好理解,因为for in 是浅拷贝,浅拷贝对于复杂类型的对象共享内存空间,共享空间的话就是在原形链上的,在原形链上就可以去继承了呀。

总结:正是因为for in 是遇到复杂类型的不做递归处理就是浅拷贝,浅拷贝共享内存空间,在原形链上,可以玩继承。别人改变了,我跟着变,这不就是继承么?

 

 

 

 

posted @ 2021-03-24 01:06  猎奇游渔  阅读(57)  评论(0编辑  收藏  举报