开发者

Private and public variables to a backbone view

开发者 https://www.devze.com 2023-04-09 09:07 出处:网络
In a backbone view where would you put your private variables and your public. Right now I have something like this:

In a backbone view where would you put your private variables and your public.

Right now I have something like this:

myView = Backbone.View.extend({

  initialize: function(options){
    this.myPublic = "I'm public";
  }

});

I tried adding a var myPrivate before the initialize method but it threw an error. Where would private variables that are only used within the view go?开发者_运维知识库


I suggest you use the initialize method as a closure around all other methods. I think this will give you behaviour more consistent with what we get in classical inheritance languages like C++ and Java:


myView = Backbone.View.extend({

  initialize: function(options){
    var myPrivate = "I'm private";

    this.myPublic = "I'm public";

    this.getPrivate = function () {
      return myPrivate;
    };

    this.setPrivate = function (value) {
        if (typeof(value) === 'string') {
            myPrivate = value;
            return true;
        } else {
            return false;
        }
    };
  }
});


Wrap it all up in a self-invoking anonymous function:

(function() {
    var myPrivate = 1;

    myView = Backbone.View.extend({  
        initialize: function(options){  
            this.myPublic = "I'm public";
            myPrivate++;
        },
        render: function() {
            alert(myPrivate);
        }
    });

})();

Edit: As pointed out in kaustubh's comment below, the above example creates a private variable that is shared among the instances. You could create a sort of protected variable, that is, an instance level variable that could be read by other instances of the View. Give each instance a unique public id and store instance variables in a "private static" variable. Then access the variables by instance id:

(function() {
    var data = [];

    myView = Backbone.View.extend({  
        initialize: function(options){  
            this.myPublic = "I'm public";
            this.Id = data.length;
            data.push({});
            data[this.Id].myProtected = "abc";
        },
        render: function() {
            alert(data[this.Id].myProtected)
        }
    });
})();

Or, you can do it without using a public id, but it becomes a bit more convoluted:

(function() {
    var data = (function () {
        var dataValues = [];
        return function (instance) {
            for (var i = 0; i < dataValues.length; i++) {
                if (dataValues[i].instance === instance) {
                    return dataValues[i].data;
                }
            }
            var dataObject = { instance: instance, data: {} };
            dataValues.push(dataObject);
            return dataObject.data;
        };
    })();

    myView = Backbone.View.extend({
        initialize: function(options){  
            this.myPublic = "I'm public";
            data(this).myProtected = "abc";
        },
        render: function() {
            alert(data(this).myProtected)
        }
    });
})();

I'm struggling to come up with a way of storing truly private variables. I'll post back if inspiration strikes.


Instead of inserting the object directly into the extend function, how about creating a closure and from that closure return an object to the extend function?

var myView = Backbone.View.extend(function () {

  var _myPrivateOne = 0;

  function _myPrivateStrangeSquareFunction(a) {
    return a * a + 1;
  }

  return {
    initialize: function (options) {
      _myPrivateOne = options.privateOne;
      this.myPublicOne = options.publicOne;
    },
    setPrivateOne: function (value) {
      _myPrivateOne = value;
      return _myPrivateOne;
    },
    getPrivateOne: function () {
      return _myPrivateOne;
    },
    getPrivateOneStrangelySquared: function () {
      return _myPrivateStrangeSquareFunction(_myPrivateOne);
    }
  };

} ());

I haven't tried this, because I have no Backbone install available right now.


gilly3's solution may be the best answer, although it is not technically creating/using a private variable because other instances of the same closure will have access to it (you probably are not as concerned about other members of your development team misusing that privilege, but it could happen).

If you want to use private variables without using gilly3's approach, Near Privman's answer appears to be the only true solution as Douglas Crockford explains how to create private variables here: http://javascript.crockford.com/private.html

This will add additional javascript processing time since it will not be able to make use of prototypal inheritance and will be using resources to recreate the function each time.

However, this may not be a very noticeable issue if the closure you create each time is very small or if the number of times a new instance is created is minimal. In an effort to try and get the best of both worlds, you can delegate the bulk of your method that uses the private variable (via delegation pattern) to a static function that won't get recreated each time. This will leave your publicMethodThatUsesPrivateVariable method shown below smaller, which means that it should take less time to recreate each time.

    var _privateStaticMethod = function(privateVariableValue, methodParameter) {
        var result;

        // Execute the lengthy javascript logic here ...

        result = Math.ceil(privateVariableValue / 108);
        result += 4815162342;
        return result;
    };

    Backbone.View.extend({
        initialize: function() {
            var _privateVariable = 303;

            this.publicMethodThatUsesPrivateVariable = function(methodParameter) {
                // Only place as little logic as you can here outside of the private static method being used below
                _privateVariable += 1;

                return _privateStaticMethod(_privateVariable, methodParameter);
            };
        },

        // ...
    });

Note that the code above should be wrapped in some kind of function as well so that _privateStaticMethod is not a global variable/function.


I was liking Near Privman's answer until I ran into a problem with overriding a "super" method. As initialize() isn't called until some way through the construction of a Backbone object, overriding may not have happened by the time it needs to (if it needs to before initialize() is called).

In particular, this can be a problem with parse(). (Not an issue for Views, but definitely for Collections and Models.) Given this setup:

MyModel = Backbone.Model.extend({
    initialize: function (options) {
        this.parse = function (response, xhr) {
            // parsing logic
        };

        // public & private vars/methods here
        // and also initialize code
    }
});

MySubModel = MyModel.extend({
    initialize: function (options) {
        this.parse = function (response, xhr) {
            // override MyModel with my own parsing logic
        }

        // public & private vars/methods here
        // and initialize code here
    }
});

MySubModel.parse() will never be called.

Instead, I've found that using an IIFE instead of initialize() both clears up this problem and reads cleaner than making a function that already has a specified purpose (initialize()) do double duty as a closure for defining the rest of the class.

var MyModel = {};
(function () {
    this.initialize = function (attributes, options) {
        // initialize me
    }

    this.parse = function (response, xhr) {
        // override at will
    }

    // other public & private vars/methods here
}).call(MyModel);

Backbone.Model.extend(MyModel);

Unfortunately, this has the same problem with "private" variables being shared across all instances of the class as do both gilly3 and Near Privman's answers. Would love to hear a non-awkward way to make private variables possible, but maybe I should just give it up and recognize I'm writing JavaScript now, not Java/AS3/C++.


You can try this:

var Thing = Backbone.Model.extend(
    {
        constructor : function ()
        {
            var _value = "Private data!";

            this.getValue = function ()
            {
                console.log(_value);
            };
            this.setValue = function (value)
            {
                _value = value;
            };
        }
    });


The standard Backbone way of adding "private" variables is to declare them as attributes with an underscore "_" before them. They are not really private, but developers will realize that they are not meant to be publicly used.

This, in fact, is how Backbone stores its own private variables.


In the context of using Broserify.js with Backbone (and really any above medium project) I found the following way to have private vars and functions:

myView.js

'use strict';

var config     = require('../config.js'),

    private_var   = 'private variable',
    my_private_fn = function() {
        ...
    };


module.exports = Backbone.Model.extend({
    initialize: function() {
        this.my_public = 'public variable');

        console.log('This is my' + this.my_public);
        console.log('This is my' + my_private);
    },
});


Using "this"?


    initialize:function () {
        this.viewpointers = {}
    },
    render:function () {
        var self = this
        _.each(this.viewpointers, function(item){
            self.$el.find(".assigned-items").append(item.render().el)
        });
    }

adding them. Then these are protected atleast.


    this.viewpointers[model.id] = new view({model:model})

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号