通过开超市的方法浅谈JS的面向对象

2,309 阅读4分钟

【前言】

在Java中,我们通常用关键字class来定义一个类,但JavaScript在ES6之前并没有class关键字,它不通过class来定义一个类,而是用函数代替。JavaScript中的函数不仅能执行普通功能,还能当class使用。

【正文】

在Java中,我们在类里面写入不同的方法,以便于对象去调用它,这是很鲜明的面向对象方式,对象与方法之间可以说存在血缘关系。但JavaScript中是没有血缘关系的,JS是基于原型式的面向对象。首先让我们用构造函数创建一个类:

`function Cat(name,color){//类

    this.name = name
    this.color = color
}`

JavaScript中一般不会在类里面写入方法函数,因为这会让我们在每定义一个新的实例对象时,都执行一遍类里的方法函数,这样会占用过大的内存,带来不必要的负荷。我们一般在类里设置属性,用于接收实例对象创建时传过来的参数。那么,我们的方法函数在JavaScript中的面向对象时,是怎么进行设置与调用的呢?

这里我们引入一个新属性prototype,JS给出的方法是在方法上添加一个prototype属性,挂载在这上面的方法,会在实例化的时候给到实例对象,例如我们想要实现猫说话的功能,就需向Cat.prototype添加说话的方法函数

`Cat.prototype.sayHello=function(){
    console.log("喵喵喵");//对象的方法不是自己的,而是由原型提高的,独立的,

}`

通过new关键字产生的实例对象都有类的prototype上的属性和方法,我们的实例对象此时就能够调用这段方法函数,我们定义一只白猫叫钉钉

> let cat1=new Cat('钉钉','白色');
> cat1.sayHello();//喵喵喵

我们发现,实例对象cat1通过调用方法函数sayHello()可以输出相应的值,那么此时我们是不是就可以说实例对象拥有这个方法了呢?或许你在Java里面可以这么说,但是JavaScript中并不是这样的,JS是基于原型式的面向对象,它的实例对象与方法函数之间并没有血缘关系,在这里我们打印实例对象cat1可知它并没有方法函数:

> cat1
> Cat{name:钉钉,color:白色}
> 

那么大家会很疑惑,我的实例对象cat1上并没有sayHello方法函数啊?为啥可以使用呢?这时让我们引入__proto__,它是每个对象都有的属性。当你访问的当前对象没有的方法时,实例对象会去__proto__中查找,其实__proto__就相当于父类中的prototype,也就是Cat.prototype,我们通过“===”可知

> 
> cat1.__proto__===Cat.prototype
> true
> 

由于我们父类中的prototype中挂载了方法,所以实例对象可以通过__proto__找到方法函数并且调用,如果父类中也没有这个方法,那他会去Object.__proto__中查找,这里就涉及到了原型链的相关知识,恕我还在学习阶段,才疏学浅,在此不作多言,感兴趣的小伙伴可以自行了解。

在这里我简单的画一个图来表明实例对象与它父类之间跟方法函数的联系

QQ图片20210421133814.png

我们可以理解为,图中的Cat构造函数相当于一个大超市,而他的属性prototype就是超市里的货架,那么很容易理解,方法函数就是货架上的商品了,放什么商品放多少商品,这取决于你自己本身。而实例对象cat1可以理解为是员工,它通过__proto__与货架连接,也就是prototype,通过__proto__我们的员工就可以拿到货架中的商品,也就是prototype中挂载的方法函数。员工虽然可以拿到货架上的商品,但你能说货架上的商品是你员工自己的么?那不管从什么逻辑层面来说,那显然都是不可以的。那么也就是说,咱们的实例对象虽然可以拿到方法函数,但方法函数并不属于实例对象本身,它本身并没有方法函数,它只是能够拿到货架上的商品而已。

注:其中思想学习自阮一峰

www.ruanyifeng.com/blog/2010/0…