jashkenas / jashkenas/backbone

Backbone and ES6 Classes

Open
#3,560 64 comments 5 reactions 0 assignees View on GitHub
change
Dominant language
JavaScript
Stars
28.1k
Forks
5.3k
PR merge metrics
No merged PRs in 30d

Description

With the final changes to the ES6 class spec (details [here](http://www.2ality.com/2015/02/es6-classes-final.html)), it's no longer possible to use ES6 classes with Backbone without making significant compromises in terms of syntax. I've written a full description of the situation [here](http://benmccormick.org/2015/04/07/es6-classes-and-backbone-js/) (make sure to click through to the comments at the bottom for an additional mitigating option), but essentially there is no way to add properties to an instance of a subclass prior to the subclasses parents constructor being run.

So this:

``` javascript
class DocumentRow extends Backbone.View {

constructor() {
this.tagName = "li";
this.className = "document-row";
this.events = {
"click .icon": "open",
"click .button.edit": "openEditDialog",
"click .button.delete": "destroy"
};
super();
}

initialize() {
this.listenTo(this.model, "change", this.render);
}

render() {
//...
}
}
```

is no longer valid in the final ES6 spec. Instead you effectively have 3 (not very appealing) options if you want to try to make this work:

Attach all properties as functions

Backbone allows this, but it feels dumb to write something like this:

``` javascript
class DocumentRow extends Backbone.View {

tagName() { return "li"; }

className() { return "document-row";}

events() {
return {
"click .icon": "open",
"click .button.edit": "openEditDialog",
"click .button.delete": "destroy"
};
}

initialize() {
this.listenTo(this.model, "change", this.render);
}

render() {
//...
}
}
```

compared to the current extends syntax
## Run the constructor twice

I don't view this as a real option due to the issues it would cause running initialize a second time with different cids, etc.

Pass all properties as default options to the superclass constructor

This was suggested by a commenter on my blog and is probably the most practical current option. It looks something like this:

``` javascript
class MyView extends Backbone.View {
constructor(options) {
_.defaults(options, {
// These options are assigned to the instance by Backbone
tagName: 'li',
className: 'document-row',
events: {
"click .icon": "open",
"click .button.edit": "openEditDialog",
"click .button.delete": "destroy"
},
// This option I'll have to assign to the instance myself
foo: 'bar'
});

super(options);

this.foo = options.foo;
}
}
```

Since all of these current options involve clear compromises relative to the current Backbone extends syntax, it would be wonderful if a better solution could be developed. I'm not totally sure what this should look like, but one idea that came to mind while I did the writeup for my blog was the addition of a "properties" function that would output a hash of properties. The constructor could then run that function and add them to the instance prior to the other processing done by the constructor.

Contributor guide

Open the contributing guide

Research direction

Start with the issue's ES6 class examples and the linked discussion, then inspect Backbone.View's construction behavior. Define an agreed API for assigning subclass properties before superclass processing, including compatibility requirements, before implementation and tests.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript
Domain
frontend
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.