Частные и общедоступные переменные в базовом представлении - PullRequest
13 голосов
/ 28 сентября 2011

В базовом представлении, куда бы вы поместили ваши личные переменные и ваши публичные.

Прямо сейчас у меня есть что-то вроде этого:

myView = Backbone.View.extend({

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

});

Я пытался добавить var myPrivate перед методом инициализации, но он выдал ошибку. Куда пойдут приватные переменные, которые используются только в представлении?

Ответы [ 9 ]

19 голосов
/ 04 мая 2012

Я предлагаю вам использовать метод инициализации как замыкание вокруг всех других методов.Я думаю, что это даст вам поведение, более соответствующее тому, что мы получаем в классических языках наследования, таких как C ++ и 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;
        }
    };
  }
});
11 голосов
/ 28 сентября 2011

Оберните все это в вызывающую себя анонимную функцию:

(function() {
    var myPrivate = 1;

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

})();

Редактировать: Как указано в комментариях Каустуба ниже, приведенный выше пример создаетзакрытая переменная, которая используется совместно экземплярами.Вы можете создать своего рода переменную protected , то есть переменную уровня экземпляра, которая может быть прочитана другими экземплярами View.Присвойте каждому экземпляру уникальный открытый идентификатор и сохраните переменные экземпляра в «частной статической» переменной.Затем получите доступ к переменным с помощью идентификатора экземпляра:

(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)
        }
    });
})();

Или, вы можете сделать это без использования открытого идентификатора, но это становится немного более запутанным:

(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)
        }
    });
})();

Я изо всех силпридумать способ хранения действительно частных переменных.Я отправлю обратно, если вдохновение ударит.

1 голос
/ 16 июня 2013

Вместо вставки объекта непосредственно в функцию расширения, как насчет создания замыкания и возврата этого замыкания в функцию расширения?

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);
    }
  };

} ());

Я не пробовал этого, потому что сейчас у меня нет доступной установки Backbone.

0 голосов
/ 28 сентября 2014

В контексте использования Broserify.js с Backbone (и действительно любым проектом выше среднего) я нашел следующий способ иметь частные переменные и функции:

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);
    },
});
0 голосов
/ 08 марта 2014

Стандартный способ Backbone для добавления «приватных» переменных состоит в том, чтобы объявить их как атрибуты с подчеркиванием «_» перед ними. Они на самом деле не являются частными, но разработчики поймут, что они не предназначены для публичного использования.

Фактически именно так Backbone хранит свои собственные закрытые переменные.

0 голосов
/ 14 января 2014

Вы можете попробовать это:

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

            this.getValue = function ()
            {
                console.log(_value);
            };
            this.setValue = function (value)
            {
                _value = value;
            };
        }
    });
0 голосов
/ 08 июля 2013

Мне нравился ответ Near Privman, пока я не столкнулся с проблемой переопределения «супер» метода.Поскольку initialize() не вызывается до тех пор, пока не будет построен объект Backbone, переопределение может не произойти к тому времени, когда это необходимо (если это необходимо до вызова initialize()).

InВ частности, это может быть проблемой с parse().(Не проблема для Представлений, но определенно для Коллекций и Моделей.) Учитывая эту установку:

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() никогда не будет вызываться.

Вместо этого я обнаружил, что используя IIFE вместо initialize () и решает эту проблему, и читает чище, чем заставляя функцию, которая уже имеет указанное назначение (initialize()), выполнять двойную функцию в качестве замыкания для определения остальной части класса.

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);

К сожалению, эта проблема связана с тем, что «частные» переменные распределяются между всеми экземплярами класса, как и ответы gilly3 и Near Privman.Хотелось бы услышать неуклюжий способ сделать частные переменные возможными, но, возможно, я должен просто отказаться от этого и признать, что сейчас пишу JavaScript, а не Java / AS3 / C ++.

0 голосов
/ 08 мая 2013

Решение gilly3 может быть лучшим ответом, хотя технически оно не создает / использует закрытую переменную, потому что другие экземпляры такого же замыкания будут иметь к ней доступ (вы, вероятно, не так обеспокоены тем, что другие члены вашей команды разработчиков злоупотребляют этимпривилегия, но это может произойти).

Если вы хотите использовать закрытые переменные без использования подхода gilly3, ответ Near Privman представляется единственно верным решением, поскольку Дуглас Крокфорд объясняет, как создавать закрытые переменные здесь: http://javascript.crockford.com/private.html

Это добавит дополнительное время обработки javascript, поскольку оно не сможет использовать наследование прототипа и будет использовать ресурсы для воссоздания функции каждый раз.

Однако это может бытьочень заметная проблема, если замыкание, которое вы создаете каждый раз, очень мало или если число созданий нового экземпляра минимально.Чтобы попытаться получить лучшее из обоих миров, вы можете делегировать основную часть вашего метода, который использует закрытую переменную ( через шаблон делегирования ), статической функции, которая не будет воссоздана каждый раз.В результате ваш publicMethodThatUsesPrivateVariable метод, показанный ниже, будет меньше, а это значит, что для его воссоздания каждый раз требуется меньше времени.

    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);
            };
        },

        // ...
    });

Обратите внимание, что приведенный выше код также должен быть заключен в какую-то функцию, поэтомучто _privateStaticMethod не является глобальной переменной / функцией.

0 голосов
/ 05 сентября 2012

Используя "это"?


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

добавляя их. Тогда они защищены по крайней мере.


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

...