文章结构
- prototype正常的定义方式
- 构造函数中定义prototype的异常现象
- (benz instanceof Car) 为false 问题
- benz.printHistory is not a function 问题
- 总结
- 练习
prototype正常的定义方式
JavaScript一般构造函数与prototype的定义是分离的,正常的实现方式如下:
|
|
以上代码正常输出:
|
|
构造函数中定义prototype的异常现象
但如果在构造函数中定义prototype,如下代码二所示,则会出现意外的情况:
|
|
运行如上代码,会发生如下异常:
|
|
由上控制台打印可见异常现象有两处:
- 为什么benz和bmw都不是Car的子类?
- 为什么benz.printHistory() is not a function??
(benz instanceof Car) 为false 问题
先来解决为什么benz和bmw不是Car子类的问题吧。
需要先了解 instanceof 关键字的工作原理,当调用 benz instanceof Car 时,解释器是判断benz.__proto__是否为Car.prototype属性所指向的对象。
在代码一中,两者的关系如下图,是相同的。
也就是说如果benz.__proto__ == Car.prototype就认为benz是Car的对象,当然在判断时并不是只判断benz的原型,而是判断benz的原型链中的每个对象,例如:
|
|
上面的两条语句都会返回true,因为str的原型链中包含这两个对象。
既然benz instanceof Car 值为false,即表明benz.__proto__与Car.prototype不相等,或者说是Car.prototype的值前后发生了变化。
看代码,很明显发现未执行new操作前,与执行new操作后,Car.prototype在代码二的第3行处被重新赋值给了一个新对象。
而且构造函数每执行一次,Car.prototype都会被重新赋值一次,虽然赋值的对象是完全相同的结构。
但解释器判断两个对象是否相等的条件为两个对象是否引用同一个地址块。
通过以下代码三可以判断构造函数被执行后,Car.prototype的值每次都被改变了..
|
|
所以benz的原型链中已经与运行后的Car.prototype没有任何关系了,自然benz instanceof Car值为false。
benz.printHistory is not a function 问题
benz是最先执行Car构造函数的,然后是bmw,但bmw.printHistory()正常执行,说明benz的类方法中并未声明printHistory()函数。
原因是解释器的构造对象时,是先将最开始的Car.prototype设置为benz的原型,然后再执行构造函数,而构造函数中对Car.prototype的篡改并不会反映到benz的原型中去。
所以benz的原型是个名为Car的空函数而已。
而bmw在初始化时,Car.prototype已经被赋值为一个新的匿名的Object对象,并带有printHistory()的函数声明,所以bmw.printHistory()可以正常执行。
两者的区别如下图所示:
总结
在构造函数中对prototype重新定义是一个非常严重的错误。
练习
代码一连同以下两种方式,都能正常执行printHistory()方法,但这三种实现方式各有什么区别呢?
|
|
|
|
代码一和代码五的功能及效果是一致的,没有区别;只是代码五的实现方式在代码结构上更加紧凑,易于维护。
代码四的区别在于printHistory()并不具备可继承性,因为this.printHistory()指定了该方法为Car私有。
参考链接更严格的继承。
本文探讨了JavaScript中构造函数和prototype的正确使用方法,解析了构造函数内部定义prototype导致的异常现象,包括实例与构造函数关系断裂及方法不可访问等问题。
3746

被折叠的 条评论
为什么被折叠?



