JavaScript中本没有类,所以凡事也不要强求,强扭的瓜总是不填的嘛。继承也无非就是一个对象拥有另外一个对象的特性,所以完全不需要复杂的去模拟面向对象中的类式继承,而借助JavaScript独特的原型机制就可以实现了。同样,需要创建一个对象时也不再采用模拟类-对象的方式,而是直接使用JavaScript的对象字面量就好了。因为对于对象来说我们关系的无非也就是它具备哪些属性、有哪些行为而已。
1 | var parent = { |
上面的代码目前还不能工作,上一篇文章中谈到过JavaScript中对象属性查找机制,如果child
对象本身没有printName()
这个方法,那我们保证其原型上有这个方法,它就能正常工作了。
1 | /* var parent... */ |
通过一个object()
函数,我们就完全可以实现一个对象从另一个对象继承了。其原理很简单,即在object()
函数内部创建一个临时的构造函数,然后修改这个构造函数的原型,最后再返回这个构造函数的一个实例。
当然,parent
对象也并不一定要使用对象字面量,你可以选择任何你能想到的创建对象的方式,如构造函数等。
1 | function Parent () { |
正如前面所述,我们可能并不想继承原对象自己的属性,如上面的例子我们也并不希望它打印出parent
。
原型式继承的规则就是:对象从对象继承,不管父对象是如何而来。而Parent.prototype
也是一个对象,所以
1 | var child = object(Parent.prototype); |
改写之后,打印child
自己的名字时得到的是undefined
,因为创建child
对象后,还没有给它赋予任何的属性,所以这恰是我们想要的结果。
而在ECMAScript 5
中,原型式继承已经成为了语言特性,为我们增加了Object.create()
方法,也就是说可以不用自己实现上面的object
方法了。而且Object.create()
方法更加强劲、适用。
1 | var parent = { |
最后,再谈谈最开始实现的object()
方法吧,其实还可以做一点点简单的优化。那就是每次调用object()
方法时都要创建一个临时的代理构造函数F
,而事实上仅需要创建一次就足够了。
1 | var object = function () { |
我们把代理构造函数放到一个立即执行的函数中创建,然后这个函数返回一个新的、真正实现继承逻辑的函数。