stampit-org / stampit

OOP is better with stamps: Composable object factories.
https://stampit.js.org
MIT License
3.02k stars 103 forks source link

Set default of enclosed variable with passed in defaults. #18

Closed dannyfritz closed 10 years ago

dannyfritz commented 10 years ago

What is the best way to default an enclosed var to a passed in value? Currently setting it and deleting it looks kind of janky. Just curious if anyone thought of a better approach.

I am also wondering about how to run some JS on instantiation, I'm currently putting an enclose at the end of my declaration to act as an initialize function. Was wondering if I could put it at the top with a prettier syntax like .init(function() {})

Currently I have something that works like this: http://jsbin.com/josof/2/edit?html,js,console

var label = stampit()
.enclose(function () {
  var label = this.label;
  delete this.label;
  this.getLabel = function () {
    return label;
  }
})
.methods({
  sayLabel: function () {
    console.log(this.getLabel());
  }
})
.enclose(function () {
  this.sayLabel();
})

label({label: 'hello'}); // --> "hello"
dannyfritz commented 10 years ago

I see #11 is already about this. And it uses the same method.

ericelliott commented 10 years ago

My favorite way to handle it is this:

var f = stampit().enclose(function() {
  var name;

  return stampit.mixIn(this, {
    // Getter and setter for name:
    name: function (value) {
      if (value) {
        name = value;
        return this;
      }
      return name;
    }
  });
});

var thing = f().name('foo');
thing.name(); // 'foo'

I like that it separates instantiation from initialization.

dannyfritz commented 10 years ago

Basically, I'm trying to create a controls library: http://jsbin.com/jonuz/8/edit?html,js,output


It seems kind of annoying to pass in each value individually with a setter after instantiation.

var thing = f().name('foo').element($control).label('jellyfish').value(10);

As opposed to using an options object:

var thing = f({
  name: 'foo',
  element: $control,
  label: 'jellyfish',
  value: 10
});

I am passing an $element into the stampit factory to create the control on instantiation. I suppose it wouldn't be the end of the world to write a this.initialize function. But it does require one extra line for the controls developers to write that doesn't seem necessary. But I suppose also adds a little bit more flexibility.


Any feedback appreciated! :smile:

JS really does beg me to use this sort of pattern as opposed to classical inheritance. Thanks for your work on stampit!

EDIT: I found a really interesting article on creating controls with mixins: http://javascriptweblog.wordpress.com/2011/05/31/a-fresh-look-at-javascript-mixins/

EDIT2: Twitter Flight also has an intriguing mixin API: https://github.com/flightjs/flight/blob/master/doc/mixin_api.md

ericelliott commented 10 years ago

For your situation, I think you're probably doing the right thing already. =)

ericelliott commented 10 years ago

Twitter flight's mixins are strictly functional inheritance, which means you don't get the free concatenative state or delegate prototypes. The functional mixin article suggestion has the same shortcomings. Stampit is functional mixins + delegate mixins + state mixins. Without all three, you don't have an API that expresses all of JavaScript's object capabilities explicitly.

You can technically do delegates and state mixins with functional mixins, but without a prescribed pattern built-in to the API, there's no predictable way to compose all three.

dannyfritz commented 10 years ago

Yeah, functional mixins seem to miss out on the flyweight pattern without making them ugly. Thanks for the c+c. :+1: