js图解之-图解静态、私有、公有属性和方法的区别

js图解之-图解静态方法、私有方法、公有方法区别

  • 首先,在方法之前,我们需要先铺垫一下我们的基础知识,从一砖一瓦开始,最终解决我们的问题

一、什么是面向对象

  • 面向对象是一个伟大的编程思想,
  • 本质:创建多个类,然后让类的实例去工作
  • 思想:万事万物皆对象,小到数字、字符串,大到Function、Object内置类,他们的本质都是对象
  • 三个重要概念:对象、实例、类(构造函数),我们需要注意的就是面向对象的这三个重要概念,接下来,我们就聊聊他们。

二、面向对象的三大重要概念

  • (构造函数):用于构造出对象实例。
    • 在我们日常生活中,我们其实经常会提到类这个概念。比如,生物被分为了植物类、动物类,植物类又能够被分为蔬菜类和水果类,动物类又能被分为哺乳类、昆虫类…
    • 而js中的类,也是这样,物以类聚,人以群分,类是复数。
    • 划重点:每个构造函数中都会存在一个prototype属性
  • 实例:类中的每一个成员,都是这个类的实例,每一个实例都具有私有属性和方法,共有属性和方法。
  • 对象:在js中,万事万物皆对象,js中,除了Object.create(null)生成的对象,其他对象都会默认存在一个__proto__属性。
    • 划重点:每个对象的__proto__属性,都会指向构造这个实例的构造函数的prototype属性

image-20211023182824451

  • 且看上图,我们能够得到一些结论

    • 类是复数,狼是一种类,因为狼有很多只,当我说一只狼,你的内心只能刻画出狼的大致特性,但是这只狼是公的还是母的,你能确定吗?
    • 对象是单数,灰太狼属于狼,但是当我说灰太狼时,你的内心能够刻画出这个狼的所有特点,它是公狼,它脸上有颗痣…,这就是对象
    • 划重点:js中用new关键字进行构造函数的实例化

当我们了解了以上的基础概念后,我们再了解一下,类和对象在内存中存储的

三、类和对象在堆内存中的存储

  • 类作为构造函数,在堆内存中存储时分为了三部分:[[scope]]、函数字符串、键值对
    • 复习重点:构造函数中会默认存在prototype属性,prototype属性是一个对象(箭头函数、对象里面用ES6写法写的函数不能作为构造函数,这里不展开说明)
  • 对象在栈内存中存储,会存放私有属性和方法
    • 复习重点:只要是对象,就默认存在__proto__属性,这个属性默认指向构造它的构造函数的prototype属性

根据以上的重点,上图:

image-20211023191903808

  • 因为prototype是对象,所以它就要开辟一个新内存
  • 因为f1是Fn的实例,所以f1的__proto__指向Fn的prototype属性,所以他们两个指向同一个内存0x111
  • 新问题:Fn.prototype也是对象,所以它也存在默认的属性__proto__,而它指向哪呢?
    • 划重点:默认情况下,任何函数的原型属性 __proto__ 都是 window.Object.prototype. ,因为构造函数的prototpe是一个对象,它是Object构造函数的实例。

image-20211023195416715

---------------------------------------------------------了解了这些后,我们步入正题---------------------------------------------------

四、静态属性

  • 先看代码:请问 fnName属性被放到了哪?

  •        function Fn(){
          
            }
            Fn.fnName="sjh";
            let f1=new Fn();
    
  • 看图:它被存到了Fn构造函数的键值对中对吧

  • image-20211023200115707

五、私有属性

  • 再看代码:slname,被存放到了哪里

  •  function Fn(){
                this.slname="xiaoming";
            }
            Fn.fnName="sjh";
            let f1=new Fn();
    
  • 看图:只要是this.xxx的代码,都是在new这个构造函数是给它实例的私有属性,所以slname属性放到了f1实例里面

  • image-20211023200513189

六、公有属性

  • 再再看代码:请问prName属性被放到了哪里?

  •         function Fn(){
                this.fname="siyou";
            }
            Fn.fnName="jingtai";
            Fn.prototype.prName="gongyou";
            let f1=new Fn();
    
  • 上图片:我们就找到Fn.prototype对应的堆内存,把它放到哪里就好了

image-20211023202419421

七、说区别

  • 我们想找到fnname怎么找?:console.log(Fn.fnName),对吧
  • 我们想找到slname怎么找?:console.log(f1.fnName),对吧
  • 我们想找到prname怎么找?:看图片
    • console.log(Fn.Prototype.prname)能不能拿到,
    • console.log(f1.prname),也能拿到对吧

fnName就是Fn构造函数的静态属性


slname就是f1实例的私有属性

prname就是f1的公有属性

总结:

  • 静态、私有、公有属性和方法他们最本质的区别是什么?
    • 最本质的区别他们在堆内存中的存取位置不同。
    • 存储方式:
      • 静态属性和方法:被存放在Fn构造函数中,与prototype同级
      • 私有属性和方法:被存放在实例化对象中
      • 公有属性和方法:被存放在Fn的prototype属性中
    • 调用方式:
      • 静态属性和方法:构造函数.xxx
      • 私有属性和方法:实例对象.xxx
      • 公有属性和方法:
        • 方式一:构造函数.prototype.xxx
        • 方式二:实例对象.xxx

再举个例子:

   var arr=[1,2,3,4];
        arr.push(6);
        Array.isArray(arr);

  • .push()和.isArray()都是数组常用的方法,那么请问大家,为什么一个用arr调用,一个用Array调用呢。
  • 这就是静态方法和公有方法的区别
  • 因为.isArray()方法是被定义在Array内存中,与prototype平级的。
  • 而.push()方法是被定义在Array.protoype对象属性中的,所有的Array类型的实例,都可以通过__proto__原型链找到它,而arr就是Array的实例,所以就能调用它。

补充:

  • 图片中存在的constructor等属性方法,由于与主要问题关系不大,没有展开分析
  • 对于所有对象都存在__proto__属性这句话,其实是不严谨的,因为当用Object.create(null)生成对象时,它不存在任何属性,包括__proto__属性,这一特例大家记住就可以

——————以上仅代表我个人对问题的独特见解,可能有不严谨地方,也希望大家能指出,有问题也可以随时在评论中留言—————

——————————————————————实现共同富裕是我们最崇高的目标———————————————————————

  • 11
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值