Why not Extends?
虽然方法比较简陋,但是效果是不错的,理论性能也在我知识范围里最大优化了。至于你问我为什么不用 extends,我只能说
- 我喜欢 function 作为构造函数
- class 兼容性有点拉
什么破原型链
最近在做在线二进制编辑器,快做完了(80%)感兴趣可以蹲一波;然后遇到了 dataview 和历史记录的孽缘,剪不断理还乱——我必须扩展 dataview 来让 setUint8 这类的函数推送历史记录来正常使用 ctrl+z 功能。正常写法是直接在历史类里绑定 dataview 然后修改 dataview 的 setUint8 函数,但是有 2 个问题-
- 当二进制文件长度变化,dataview 也要随之变化,你在历史里绑定的 dataview 指针就丢了,没法找到更改后的 dataview。再更改一遍也行,但你看第二个问题
- 绑定一个 dataview 就要把所有 set 相关的 function 重写一遍,全部写进了 dataview 的对象里,不仅控制台里看着心痒而且每次绑定都要写 10 来个函数的话理论性能也不过关。(高标准严要求 确信)
最好的想法应该是有一个 prototype 代劳,把修改后的方法放在一个 prototype 里,然后每次 dataview 更新直接连接到这个 prototype 上就不用浪费太多内存在绑定函数上了。想一想,用 extends 的思路怎么做?无非就是
class MyDataView extends DataView{
constructor(buffer) {
super(buffer);
};
setUint8(i,v) {};
setInt8(i,v) {};
}
打开控制台 new 一个看看
看到继承链是 this -> MyDataView -> DataView
这真的能不用 extends 吗
不用 extends 的话是不是就要考虑 DataView.prototype.constructor.call
了?可惜作为高贵的原生对象,并不能用对象来作为这个 this 值,否则 TypeError: calling a builtin DataView constructor without new is forbidden
不用 call
和 extends
的话想要实现这样奇奇怪怪的继承链,而且还要求返回值是个 DataView
(用来传给 DataView
原型上方法的 this
),显然学习成本是巨大而多余的,更何况这样的需求在百度很难找到第二个,因此我把原型链改良一下:this -> MyDataView
,在 this 中创建一个 DataView,在 setUint8 时执行完自己的代码直接把 this 里的 DataView 传给 DataView.prototype.setUint8.call(dataview, ...arguments)
。
你可以理解为 DataView
的实例 new DataView(buffer)
是王子,住在王宫(DataView.prototype
)里,可以自由进出王宫。但你只是个杂鱼百姓,想要进入王宫拿点米 DataView.prototype.getUint8
吃。你可以抓一个人伪装成王子 var dataview = new DataView(buffer)
潜入王宫 DataView.prototype.setUint8.call(dataview, ...arguments)
,然后就能正常拿到你的结果。
真有这么简单我就信了
论性能而说,这些函数都绑定在 prototype
上,不存在一堆 匿名函数声明
乱挤内存,所以理论性能应该是足够优化了(对 js 内存知识储量到此为止了,有错误请提出)。所以实际代码写法如下
function HistoryDataView(buffer, history) {
this.buffer = buffer;
this.history = history;
this.dataview = new DataView(buffer);
}
["Uint8", "Int8", "Uint16", "Int16", "Uint32", "Int32", "BigInt64", "BigUint64", "Float32", "Float64"].forEach((type)=>
HistoryDataView.prototype["set"+type] = function() {
var [i, v, l] = arguments;
this.history.push(...); // 这里写你自己的代码
DataView.prototype["set"+type].call(this.dataview, i, v, l);
});
new
一个看看效果
正常运行。
这么厉害,那我试试另一个
同理啊,可以试一试扩展一个自己的 Date
function MyDate() {
this.date = new Date(...arguments);
}
MyDate.prototype.toChineseDay = function () {
return ["日", "一", "二", "三", "四", "五", "六"][this.date.getDay()]
}
看看表,今天是不是星期四?
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于