jashkenas / jashkenas/backbone
Embrace prototypes
- Dominant language
- JavaScript
- Stars
- 28.1k
- Forks
- 5.3k
- PR merge metrics
- No merged PRs in 30d
Description
The ES6 class emulation convention doesn't sit well with Backbone, mostly because it provides no convenient way to set non-function prototype properties. In fact, in my opinion, the ES6 class emulation convention doesn't sit well in general for this same reason. On top of that, classes don't sit well with JavaScript, anyway. I'm not the first to say this; consider [Walker 2014](https://walkercoderanger.com/blog/2014/04/what-coffeescript-should-have-been/#embrace-prototypes) and [Crockford 2008](https://crockford.com/javascript/prototypal.html). I consider #4079 a symptom of classes not sitting well.
Therefore, in Backbone version 2, rather than adapting the library to ES6 classes, I would like to do away with classes entirely and embrace prototypes instead. That would mean that instead of the following in Backbone 1,
```js
import { extend } from 'underscore';
import { Model } from 'backbone';
const CustomModel = Model.extend({
idAttribute: '_id',
// ...
});
// or
class CustomModel extends Model { /*...*/ }
extend(CustomModel.prototype, {
idAttribute: '_id',
};
// in either case:
const aCustomModelInstance = new CustomModel(attributes, options);
```
we would be writing something like the following in Backbone 2:
```js
import { model } from 'backbone';
const customModel = model.extend({
idAttribute: '_id',
// ...
});
const aCustomModelInstance = customModel.construct(attributes, options);
```
where `model` is an object that serves as a prototype, instead of a function that emulates a class.
`model.extend(protoprops)` (and `collection.extend`, etcetera) would default to just being a shorthand for `Object.create(model, protoprops)`. (I would likely use `_.create` instead of `Object.create`, but that is an implementation detail.) This method can still be overridden by plugins in order to enable things like shorthand syntax at prototype extension time.
`model.construct(attributes, options)` would first do `Object.create(model)` and then perform the same logic on the created instance as the current constructor. In fact, we could retain the old constructor and simply implement `model.construct` as `Object.create(model).constructor(attributes, options)`. This would enable people who really want to use class emulation to set `Model = model.constructor` and continue working in the old way.
In summary, the code would not necessarily change that much. It's just that the library exports prototypes instead of constructors, `extend` moves from the constructor to the prototype and there is a new `construct` method that replaces the `new` keyword. As a result, everyone using Backbone can seamlessly and interchangeably write their code in the same way, regardless of what particular flavor of class emulation they are using.
Feedback welcome. I'm not starting on Backbone 2 anytime soon, so there is plenty of time.
Contributor guide
Research direction
Start by reviewing Backbone's current Model and collection APIs, especially extend and construction, against the prototype-based design described in the issue. Because no files or tests are identified and the proposal is for a future Backbone 2 redesign, completion would require an agreed design and implementation scope before coding can begin.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript
- Domain
- frontend, web-dev
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 20/100