js图解之-图解静态方法、私有方法、公有方法区别
首先,在方法之前,我们需要先铺垫一下我们的基础知识,从一砖一瓦开始,最终解决我们的问题一、什么是面向对象
面向对象是一个伟大的编程思想,本质:创建多个类,然后让类的实例去工作思想:万事万物皆对象,小到数字、字符串,大到Function、Object内置类,他们的本质都是对象三个重要概念:对象、实例、类(构造函数),我们需要注意的就是面向对象的这三个重要概念,接下来,我们就聊聊他们。二、面向对象的三大重要概念
类(构造函数):用于构造出对象实例。 在我们日常生活中,我们其实经常会提到类这个概念。比如,生物被分为了植物类、动物类,植物类又能够被分为蔬菜类和水果类,动物类又能被分为哺乳类、昆虫类…。而js中的类,也是这样,物以类聚,人以群分,类是复数。划重点:每个构造函数中都会存在一个prototype
属性实例:类中的每一个成员,都是这个类的实例,每一个实例都具有私有属性和方法,共有属性和方法。对象:在js中,万事万物皆对象,js中,除了Object.create(null)生成的对象,其他对象都会默认存在一个__proto__
属性。划重点:每个对象的__proto__
属性,都会指向构造这个实例的构造函数的prototype
属性且看上图,我们能够得到一些结论
类是复数,狼是一种类,因为狼有很多只,当我说一只狼,你的内心只能刻画出狼的大致特性,但是这只狼是公的还是母的,你能确定吗?对象是单数,灰太狼属于狼,但是当我说灰太狼时,你的内心能够刻画出这个狼的所有特点,它是公狼,它脸上有颗痣…,这就是对象划重点:js中用new关键字进行构造函数的实例化
当我们了解了以上的基础概念后,我们再了解一下,类和对象在内存中存储的
三、类和对象在堆内存中的存储
类作为构造函数,在堆内存中存储时分为了三部分:[[scope]]、函数字符串、键值对复习重点:构造函数中会默认存在prototype属性,prototype属性是一个对象(箭头函数、对象里面用ES6写法写的函数不能作为构造函数,这里不展开说明)对象在栈内存中存储,会存放私有属性和方法复习重点:只要是对象,就默认存在__proto__
属性,这个属性默认指向构造它的构造函数的prototype属性根据以上的重点,上图:
因为prototype是对象,所以它就要开辟一个新内存因为f1是Fn的实例,所以f1的__proto__
指向Fn的prototype属性,所以他们两个指向同一个内存0x111
新问题:Fn.prototype也是对象,所以它也存在默认的属性__proto__
,而它指向哪呢?划重点:默认情况下,任何函数的原型属性__proto__
都是window.Object.prototype.
,因为构造函数的prototpe是一个对象,它是Object构造函数的实例。
---------------------------------------------------------了解了这些后,我们步入正题---------------------------------------------------
四、静态属性
先看代码:请问 fnName属性被放到了哪?
function Fn(){}Fn.fnName="sjh";let f1=new Fn();
看图:它被存到了Fn构造函数的键值对中对吧
五、私有属性
再看代码:slname,被存放到了哪里
function Fn(){this.slname="xiaoming";}Fn.fnName="sjh";let f1=new Fn();
看图:只要是this.xxx的代码,都是在new这个构造函数是给它实例的私有属性,所以slname属性放到了f1实例里面
六、公有属性
再再看代码:请问prName属性被放到了哪里?
function Fn(){this.fname="siyou";}Fn.fnName="jingtai";Fn.prototype.prName="gongyou";let f1=new Fn();
上图片:我们就找到Fn.prototype对应的堆内存,把它放到哪里就好了
七、说区别
我们想找到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__
属性,这一特例大家记住就可以
——————以上仅代表我个人对问题的独特见解,可能有不严谨地方,也希望大家能指出,有问题也可以随时在评论中留言—————
——————————————————————实现共同富裕是我们最崇高的目标———————————————————————