JavaScript中继承机制的实现并不是明确规定的,而是通过模仿实现的。这意味着所有的继承细节并非完全由解释程序处理。当我们进行开发的时候,可以根据自己的需要去选择最合适的继承方式。
一、对象冒充
原理:构造函数使用this关键字给所有的属性和方法赋值(即采用类声明的构造函数方式)。因为构造函数只是一个函数,所以可使ParentsClass构造函数成为ChildClass的方法,然后调用它。ChildClass就会收到ParentsClass的构造函数中定义的属性和方法。(关键字this引用的是构造函数当前创建的对象,在此方法中,this指向的是所属的对象,这个原理是把 ParentsClass作为常规函数来建立继承机制,而不是作为构造函数)
对象冒充中最重要的是阴影部分的三行代码。在这段代码中,为 ParentsClass赋予了方法 newMethod(请记住,函数名只是指向它的指针)。然后调用该方法,传递给它的是 ChildClass 构造函数的参数 Color。最后一行代码删除了对 ParentsClass 的引用,这样以后就不能再调用它了。所有新属性和新方法都必须在删除了新方法的代码行后定义。否则,可能会覆盖超类的相关属性和方法。
对象冒充的方式是可以实现多继承的,但是弊端是之前被继承的对象中的属性和方法会被之后被继承的对象中的同名的属性和方法覆盖。
二、call()方法
call()方法与对象冒充最相似的继承方式。只需用call()方式替换对象冒充中的最关键的三行代码就可以了。
我们可以不定义ChildClass就可直接用call()来直接实现继承。
call()中的第一个参数是一般都是this(或者对象名),代表的是子对象,这样即实现了继承。
三、apply()方法
apply()方法和call()方法的区别是call()方法可以有很多个参数,除第一个必须是this或对象名外,之后就是所要传递的参数;而apply()方法只有两个参数:第一个参数和call()方法是一样的,第二个参数是一个数组,用来存放需要传递的参数。
--------------------------------------------------------------------------------------------------------
四、原型链方式
通过使用prototype对象,prototype对象的任何属性和方法都能被传递给子类的所有实例。
把 ChildClass的 prototype 属性设置成 ParentsClass的实例。这很有意思,因为想要 ParentsClass 的所有属性和方法,但又不想逐个将它们 ChildClass的 prototype 属性。还有比把 ParentsClass 的实例赋予 prototype 属性更好的方法吗?
注意:1)调用 ParentsClass的构造函数,没有给它传递参数。这在原型链中是标准做法。要确保构造函数没有任何参数。
2)与对象冒充相似,子类的所有属性和方法都必须出现在 prototype 属性被赋值后,因为在它之前赋值的所有方法都会被删除。
3)原型链的弊端是不支持多重继承。记住,原型链会用另一类型的对象重写类的 prototype 属性。
五、混合方式
这种继承方式使用构造函数定义类,并非使用任何原型。对象冒充的主要问题是必须使用构造函数方式,这不是最好的选择。不过如果使用原型链,就无法使用带参数的构造函数了。所以我们可以把它们结合在一起使用。
用对象冒充(call或者apply)来继承对象的属性,用原型链来继承对象的方法。