这篇文章主要讲一下JS中面向对象以及 __ proto __,ptototype和construcator,这几个概念都是相关的,所以一起讲了。
在讲这个之前我们先来说说类,了解面向对象的朋友应该都知道,如果我要定义一个通用的类型我可以使用类(class)。比如在java中我们可以这样定义一个类:
public class Puppy{
int puppyAge;
public Puppy(age){
puppyAge = age;
}
public void say() {
System.out.println("汪汪汪");
}
}
上述代码我们定义了一个Puppy类,这个类有一个属性是puppyAge,也就是小狗的年龄,然后有一个构造函数Puppy(),这个构造函数接收一个参数,可以设置小狗的年龄,另外还有一个说话的函数say。这是一个通用的类,当我们需要一个两岁的小狗实例是直接这样写,这个实例同时具有父类的方法:
Puppy myPuppy = new Puppy( 2 );
myPuppy.say(); // 汪汪汪
但是早期的JS没有class关键字啊(以下说JS没有class关键字都是指ES6之前的JS,主要帮助大家理解概念,本文不涉及ES6的class),JS为了支持面向对象,使用了一种比较曲折的方式,这也是导致大家迷惑的地方,其实我们将这种方式跟一般的面向对象类比起来就很清晰了。下面我们来看看JS为了支持面向对象需要解决哪些问题,都用了什么曲折的方式来解决。
没有class,用函数代替
首先JS连class关键字都没有,怎么办呢?用函数代替,JS中最不缺的就是函数,函数不仅能够执行普通功能,还能当class使用。比如我们要用JS建一个小狗的类怎么写呢?直接写一个函数就行:
function Puppy() {
}
这个函数可以直接用new关键字生成实例:
const myPuppy = new Puppy();
这样我们也有了一个小狗实例,但是我们没有构造函数,不能设置小狗年龄啊。
函数本身就是构造函数
当做类用的函数本身也是一个函数,而且他就是默认的构造函数。我们想让Puppy函数能够设置实例的年龄,只要让他接收参数就行了。
function Puppy(age) {
this.puppyAge = age;
}
// 实例化时可以传年龄参数了
const myPuppy = new Puppy(2);
注意上面代码的this,被作为类使用的函数里面this总是指向实例化对象,也就是myPuppy。这么设计的目的就是让使用者可以通过构造函数给实例对象设置属性,这时候console出来看
myPuppy.puppyAge就是2。console.log(myPuppy.puppyAge); // 输出是 2
实例方法用prototype
上面我们实现了类和构造函数,但是类方法呢?Java版小狗还可以“汪汪汪”叫呢,JS版怎么办呢?JS给出的解决方案是给方法添加一个prototype属性,挂载在这上面的方法,在实例化的时候会给到实例对象。我们想要myPuppy能说话,就需要往Puppy.prototype添加说话的方法。
Puppy.prototype.say = function() {
console.log<