02-原型继承-可枚举不可枚举属性

1.基本数据类型字面量创建的和实例创建的值不相等

var num1 =1;

var num2 = new Number(1);

num1 不等于num2,因为num1是基本数据类型,num2是对象数据类型

2.对象数据类型字面量创建的和实例创建是一个意思


 

可枚举:私有属性

不可枚举:原型上的属性(自带的和自定义到原型上的属性都是)

 for in 循环可遍历可枚举(私有属性)和自定义在原型上的不可枚举的属性:

 

 

 for in 通过可枚举的检测,只遍历出来可枚举的属性:

 

 

 我们还可以通过hasOwnProperty来进行判断,只让for in 去遍历私有属性

 

 

 


 

 Object.create()  -> 方法创建一个拥有指定原型和若干个指定属性的对象

查看Fn函数的原型,是有constructor属性的(函数和类都会自带一个constructor,并指向当前函数本身)

 

 

 我们把Fn的原型指向obj: 发现fn的原型已经指向obj了,并且已经没有constructor属性了。

 

 

 new 一个fn(fn应该写成Fn,这里不太语义化,不过不影响)的实例f1函数,因为其fn原型指向obj后没有了constrcutor了,所以其实例也没有,没有的话就会往上查找,找到Object的原型上的constructor。

 我们把obj中添加constructor,这样接着上面的输出后,发现Fn的实例f1的constructor就指向了Fn(因为只有浏览器默认开辟的堆内存中才天生自带constructor这个属性,Fn函数,或者类,因为new Fn了他就成类了),所以实例的constructor指向其父类。

 

 

在Fn的原型上增加一个sum方法:因为两者共享一个内存空间,所以在各自的原型上就都有sum方法。

但是我们的初衷是只想Fn去继承obj中的属性和方法,在给Fn自己的原型上去添加方法的时候,不希望obj的原型上也被添加,简单的说,不想让他俩共享一块内存空间。

 

 

 那么我们就想让obj克隆一份,然后给到Fn,这样obj还是原来的obj,但是Fn也实现了去继承了obj的内容(副本):

如何克隆?

插曲:我们本身要通过创建一个obj2(开辟了一个新的内存空间),通过for in 去克隆到obj2,我们发现obj去检测可枚举的,sum方法竟然是obj的可枚举属性

 

 

 你看!!

 

 

 所以,我们要克隆的话必须写在给Fn原型添加sum方法之前,先行克隆。

 

 

 


 

用Object.create()来实现拷贝:创建一个新对象,并且把传入的这个对象作为创建的那个新对象的原型。

 

 

 既然obj作为了副本obj2的原型,如上图输出:

简单总结一下:var obj2 = Object.create(obj)  是创建的obj2对象并且以obj作为obj2的原型,obj2自己没有私有属性,都存储在了obj2的__proto__上,并且这个__proto__就是指向obj,他这个__proto__就是obj的原型,所以__proto__中的__proto__就是obj的原型的__proto__,并且指向Object的原型,利用Object原型上的hasOwnProperty去检测私有属性存不存在。

 

 

如果上面不好理解,我们再看上面这张图:Fn原型继承了obj,或者说obj作为了Fn的原型,那么打印Fn的原型我们发现obj的私有属性getX也在Fn的原型上。是不是跟上面一个道理。

Object.create就相当于把obj作为了obj2的原型,obj2就相当于那个fn,所以打印obj2其实就相当于打印Fn.prototype。Fn的原型打印出来也能看到obj的私有属性。只不过obj是对象,不是函数,不能像是Fn那样去输出prototype。

 


obj在创建自己的一个副本obj2后,obj上添加getY方法,obj2也能拿到,因为obj2的原型是obj,能访问obj的私有属性和公有属性,其实啊。obj={ ~~~},这特么不就是obj 有了一块堆内存么,什么私有公有的?还分啥私有公有,都在这里面存着,又不是函数和类。

 

 

 

 


 

对比for- in 循环去拷贝的和Object.create拷贝的不同:

  --- for in 那种是新建了一个对象,是额外创建了一块内存空间,去进行一次性拷贝,以后这俩内存空间毫无关系。不存在干扰。

  --- Object.create() 是被拷贝的对象作为新创建的对象的原型,那肯定狗皮膏药啊。黏连。


原型继承

其实我们从上面的

var obj ={};

var obj2 =  Object.create(obj); -> 创建了的obj2是以obj作为原型的,obj2指向obj的原型prototype,那么obj原型上只要发生了改变,obj2就会跟着发生改变。这就是原型继承,obj是高于obj2一个维度的。

继承者obj2可以使用父亲obj的属性和方法。

 

换做原生的是这样的: Fn2的原型继承了Fn的实例,也就是说Fn2继承了Fn,那么Fn2就可以用Fn上的私有属性和公共方法(堆内存是个对象,私有公有都在里面的)

 


一句话:上面啰嗦的可以不看,可以记住一句话:

比如有两个元素对象A和B,如果要想让B继承A,B继承A后就可以使用A的所有私有属性和原型上的所有公有属性。只需要把A的实例赋值给B的原型,即可。

var B = Object.create(A);  创建B,并且B继承了A,B就可以使用A的私有属性和原型上的A的公有方法,相当于B是A的影子。A和B相当于一个资源池,但是B如果给自己增加了私有属性,比如B.xxx=xxx。那么A不会受到影响,但是A如果添加了属性,B就会能取到。

 这说明了什么,继承者添加私有属性不会破坏父亲的数据,这就很爽了。我就是单纯想用父亲的数据,我自己怎么燥不会影响“恩人”~  除非去操作原型:比较他俩用的是一块内存

 这说明了啥? 该燥燥你的,如果不想影响大家,别去在原型上躁动,影响你爸爸!

 

原型继承的特点:他是把父类中私有的+公有的都继承到了子类原型(子类公有的)

看图显而易见:B的实例指向B的原型,B的原型又指向A的实例,A的实例可以享受到A的私有属性和公有方法,所以B的原型也就可以享受到A的实例一样的待遇(这就是叫把父类的所有属性都继承在了子类原型上),所以B的实例也就能享受到A的实例一样的待遇获取A的私有属性和公有方法。

但是B的实例有自己的内存地址,他自己想杂玩咋玩,不影响A,只要别操作原型,因为他的原型是指向A的。

 

 

原文地址:https://www.cnblogs.com/haoqiyouyu/p/14466912.html