最近在处理时间的时候发现一个问题,不能继承Date
上面的方法,之前使用其它的对象都没出现过问题,我们先看下面这个例子,使用经典的寄生组合继承
1 | /** |
运行之后,可以在控制台里面看到如下输出:
1 | VM2356:17 Uncaught TypeError: this is not a Date object. |
这是什么原因呢,MDN中有提到,JavaScript的日期对象只能通过JavaScript Date
作为构造函数来实例化,那么,是不是就无法使用Date来实现继承来呢?
通过在网上查找,发现了网友给出的很多有趣的答案,现将网上的答案整理如下,不外乎有三种:
- 1、比较暴力的方法
1 | function MyDate(){ |
这种方法使用了方法代理,并不能称之为继承
- 2、使用es5来实现
1 | // 需要考虑polyfill情况 |
可以看到,用的是非常巧妙的一种做法:
正常继承的情况如下:
new MyDate()
返回实例对象date
是由MyDate
构造的
原型链回溯是: date(MyDate对象)->date.__proto__->MyDate.prototype->MyDate.prototype.__proto__->Date.prototype
这种做法的继承的情况如下:
new MyDate()
返回实例对象date是由Date构造的
原型链回溯是: date(Date对象)->date.__proto__->MyDate.prototype->MyDate.prototype.__proto__->Date.prototype
可以看出,关键点在于:
构造函数里返回了一个真正的Date
对象(由Date
构造,所以有这些内部类中的关键[[Class]]
标志),所以它有调用Date
原型上方法的权利
构造函数里的Date
对象的[[ptototype]]
(对外,浏览器中可通过__proto__
访问)指向MyDate.prototype
,然后MyDate.prototype
再指向Date.prototype
。
所以最终的实例对象仍然能进行正常的原型链回溯,回溯到原本Date的所有原型方法
- 3、使用ES6的class来实现
1 | class MyDate extends Date { |
这里的正常输出环境是直接用ES6运行,不经过babel打包,打包后实质上是转化成ES5的,所以效果完全不一样