参考: js application的作者的作品, stamp, tape, 或许是一条出路.

用stamp的原因
  1. 原型代理, 就是上面工厂函数的原型构造方法.
  2. 实例状态, 可以封装每个实例自己的状态. 可以把属性直接传进去构造新对象. 构造之后也可以混入属性.
  3. 封装性, 函数式闭包, 形成私有属性.

作者原始的方案是构造函数有三个参数, 分别对应上面的内容.

  1. method, 对象的方法, 构造再原型上.
  2. state, 实例状态, 每个实例初始化.
  3. enclose, 私有属性和属性的提取方法. 构造在闭包.

现代的stamp方案有所不同

  1. 扩展的基础概念
    1. 有深度merge的概念了.
    2. 有static的概念, 这个等于类属性. 可以认为是全局属性.
    3. 有引用的概念了: conf.
    4. 有不可变frozen的概念, 只有一次赋值的机会, 赋值之后就不能改了: descriptor
      1. 通过 Property descriptors 实现.
    5. 私有变成了一个单独的模块
  2. 基础数据如下:
    1. 方法method
    2. 属性property
    3. 构造init, 这个比较特殊是一个固定名字的函数
    4. 合并/多重继承composer
init的示例是错的—已经提交修改, 并且修正了.
const { props, methods, init } = stampit;
const DefaultFoo = props({ foo: '能用function不能用=>' });
const PrintFoo = methods({ printFoo() { console.log(this.foo) } });
const PassFoo = init(function({ foo=this.foo }) { this.foo = foo });

const Foo = DefaultFoo.compose(PrintFoo, PassFoo)
const ff= Foo({foo: "xxxx"});
ff.printFoo(); // xxxx
const ff2= Foo();
ff2.printFoo(); // 能用function不能用=>
2019-05-23 后记

碰到了一个奇怪的问题, init的时候返回某个值(也就是说返回的不是默认的this)那么链式调用的methods中的方法不能被调用例如:

function teststampinit() {
  const mckpoint = stampit()
    .statics({
      keymap: {},
    })
    .init(({ lng, lat, info, ...p }) => {
      const t = {};
      t.p = p;
      t.lng = lng;
      return t;
    })
    .methods({
      info() {
        //这个不能被调用.
        return "ooo";
      },
    });

  const xxx = mckpoint();
  xxx.info(); //这里会提示info不是函数.
}
2019-05-25

设计模式:

  • 所有的stamp都应该拥有从自身生成一个新的对象的能力. 写init的时候尤其要注意, 这样能避免很多if判断.
  • 特别要注意的是自身生成时, 要记得赋值所有的属性.
  • 函数尽量返回this, 除非read(0)这种特殊的读取类函数.
  • init的默认值都要定义在参数上, 不要直接在属性里面赋值默认值, 因为这样会导致新建的对象和用作模板参数的对象的属性不一致.