Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Backbone and RequireJS conflicts - instances or constructors?

Could someone explain the fundamental difference between:

define(['backbone'], function(Backbone) {
   MyModel = Backbone.Model.extend({
   });
});

define(['backbone', 'models/mymodel'], function(Backbone){
    var app = Backbone.View.extend({
        initialize: function() {
           var model = new MyModel();
        }
    });
});

and:

define(['backbone'], function(Backbone) {
   var MyModel = Backbone.Model.extend({
   });
   return MyModel;
});

define(['backbone', 'models/mymodel'], function(Backbone, MyModel){
    var app = Backbone.View.extend({
        initialize: function() {
           var model = new MyModel();
        }
    });
});

In the former, the first module simply defines MyModel. In the latter, it's created as a variable and returned, and the second module needs to have it put in the parameters when imported.

RequireJS examples I see around seem to vary between the two, but I don't really understand the difference - does one return an instance and the other a constructor?

In my application I didn't even notice that I was actually using both ways in different places, and I think it was causing problems. I was using a lot of

self = this
self.model.doSomething

inside my views and models, and as my app got bigger, I started getting errors because there were conflicts with definitions of self.

like image 703
user888734 Avatar asked Mar 11 '26 20:03

user888734


1 Answers

Short Version: 1st version == wrong.

Medium Version: The first one bypasses Require entirely by using global variables, while the second one actually uses Require.

Long version:

The way Backbone modules work is that you run "define", pass it a function (and usually an array of dependencies also), and whatever gets returned from that function is defined as that module. So if I do:

// Inside foo.js
define([], function() {
   return 1;
});

I've defined the "foo" module to be 1, so if elsewhere I do:

define(['foo'], function(foo) {
    alert(foo); // alerts 1
});

Your first version doesn't return anything, so it's not actually creating a Require module at all.

How does it work then? Well, in that version you do:

MyModel = Backbone.Model.extend({

NOT:

var MyModel = Backbone.Model.extend({

So that's really the same as doing:

window.MyModel = Backbone.Model.extend({

Then when the second part of the code runs, it access window.MyModel, and works ... but it's completely bypassing Require.js in the process.

I think the most important thing to takeaway is: ALWAYS DECLARE (ie. var) YOUR JAVASCRIPT VARIABLES. I don't agree with everything Crockford says, but he's dead right on this one. You will get lots of bugs (with Require and without) if you don't make this a habit.

Beyond that, the next most important thing is probably: ALWAYS RETURN SOMETHING FROM THE FUNCTION YOU PASS TO define. There are certain special cases where you don't want to return anything, but unless you are deliberately trying to solve one of those cases you should always return something to define the module.

Finally, if you're using Require, every variable in your code should either:

  • Come from the define function (ie. it should be an argument variable from the function that you pass to define), or
  • It should be declared (ie. var-ed ) inside that file

If you use JSLint or 'use strict'; (as Valentin Nemcev suggested), or if you use an editor like Eclipse, your tools can help you ensure this (and in fact make it easy to ensure).

like image 192
machineghost Avatar answered Mar 16 '26 02:03

machineghost



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!