zoukankan      html  css  js  c++  java
  • 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的。

     

     

  • 相关阅读:
    最近我总结的常用mate标签-常用mate标签
    同一个世界(erlang解题答案)
    ranch 源码分析(完)
    ranch 源码分析(三)
    ranch 源码分析(二)
    ranch 源码分析(一)
    port 执行命令的封装和参数详解
    erlang 笔记(06/03/02)
    recon工具解读
    erlang调试方法
  • 原文地址:https://www.cnblogs.com/haoqiyouyu/p/14466912.html
Copyright © 2011-2022 走看看