比如我们现在的需求如下。

有一个函数MyObj,支持如下功能:

  • 可以通过MyObj()的方式返回一个对象,这个对象和new MyObj()是等价的
  • MyObj本身是一个对象,可以通过MyObj.doit()的方式调用其上的方法或属性为了实现需求,第一反应是:

    var MyObj=function(){
      return new MyObj();
    };

    然后在MyObj上挂载静态方法,在MyObj.prototype上挂载对象方法。

看起来稳的很,其实这明显是一个死循环:

// VM160:2 Uncaught RangeError: Maximum call stack size exceeded
MyObj();

为了解决这个问题,我们在MyObj的原型上定义了一个方法:

MyObj.prototype.init=function(){
    return this;
};

执行下面的方法:

var temp=MyObj.prototype.init();

上面返回的temp很明显就是MyObj.prototype,其实就是MyObj对象(例如:new A(),其实就是取A.prototype,这样对比就很好理解了)。

因此可以改造代码如下:

var MyObj = function (param) {
    return MyObj.prototype.init();
};

这样MyObj和new MyObj()就分别表示类和对象。

问:看起来是不是实现了?
答:是的,实现了。
问:可是总感觉有点不好,说不出为什么。
答:是不是感觉MyObj()打印出来的东西有点多?
问:是的。

事实上,因为直接取MyObj.prototype作为new MyObj(),理论上说,使用上区别不大,唯一不足的是,挂载在MyObj.prototype上的方法会在打印MyObj对象的时候看见,不舒服。

为了看起来好看些,代码再次改造:

var MyObj = function () {
    return new MyObj.prototype.init();
};

// 为了让MyObj()返回的是MyObj对象,需要修改MyObj.prototype.init的原型
MyObj.prototype.init.prototype = MyObj.prototype;

此刻的原型关系变成了:

MyObj() ==
return new MyObj.prototype.init() ==
MyObj.prototype.init.prototype ==
MyObj.prototype ==
new MyObj()

此时需求就实现了,而且打印MyObj()的时候,对象上的方法都在原型上,看起来就比较舒服了。

作者:|zxl20070701|,原文链接: https://segmentfault.com/a/1190000043528209

文章推荐

STM32低功耗配置

秒杀系统常见问题—库存超卖

Redis内存兜底策略——内存淘汰及回收机制

Java 20 新功能介绍

【过滤器设计模式详解】C/Java/JS/Go/Python/TS不同语言实现

Java的运行时数据区域

初识Kafka

ReactQuery系列文章- 2. 数据转换

Java零基础学习的点点建议

Vue—关于实例中为什么只能有一个根元素?

弄懂 Websocket 你得知道的这 3 点

Seata源码分析(一). AT模式底层实现