Общедоступные/частные переменные Javascript

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

var foo = (function() {
    //Private vars
    var a = 1;

    return {
        //Public vars/methods
        a: a,
        changeVar: function () {
            a = 2;
        }
    }
})();
alert(foo.a);  //result: 1
foo.changeVar();
alert(foo.a);  //result: 1, I want it to be 2 though

Теперь я знаю, что если я изменю строку в changeVar на this.a = 2;, она сработает, но не обновит приватную переменную. Я хочу одновременно обновить как частные, так и общедоступные переменные. Это возможно?

JsFiddle показывает проблему


person Michael    schedule 08.10.2011    source источник
comment
как насчет этого подхода? marcelorjava.wordpress.com/2014 /06/07/   -  person the_marcelo_r    schedule 07.06.2014


Ответы (4)


Когда вы устанавливаете ключ a в возвращаемом объекте, это создает копию "частной" переменной a.

Вы можете использовать функцию получения:

return {
    //Public vars/methods
    a: function() { return a; },
    changeVar: function () {
        a = 2;
    }
};

Или вы можете использовать встроенные функции доступа Javascript:

obj = {
    //Public vars/methods
    changeVar: function () {
        a = 2;
    }
};
Object.defineProperty(obj, "a", { get: function() { return a; } });
return obj;
person anonymous coward    schedule 08.10.2011
comment
почему a = 1; b = {a:a}; b.a++ не влияет на a, а a=[]; b= {a:a}; b.a.push(1) влияет на a? - person lostyzd; 08.10.2011
comment
@lostyzd stackoverflow.com/questions/6605640/ - person anonymous coward; 08.10.2011

Да, если вы используете более новый браузер:

var foo = (function() {
    var a = 1;
    return {
        get a() { return a; },
        changeVar: function () {
            a = 2;
        }
    }
})();

Посмотрите демонстрацию JSFiddle.

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

var foo = (function() {
    var a = 1;
    return {
        getA: function() { return a; },
        changeVar: function () {
            a = 2;
        }
    }
})();
alert(foo.getA()); // rather than foo.a

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

person icktoofay    schedule 08.10.2011

Я обычно использую этот шаблон, который я не видел, чтобы многие делали. Я делаю это, чтобы избежать необходимости упорядочивать мои методы каким-либо особым способом. Если все общедоступно, то обычно необходимо убедиться, что вызываемые методы объявлены до вызова метода

var person = new Person("Mohamed", "Seifeddine");
person.getFullname();
person.getFirstname();
person.getLastname();           

function Person(firstname, lastname) {
    var firstname, lastname;

    (function constructor(){
        setFirstname(firstname);
        setLastname(lastname)
    })();

    this.getFullname = getFullname;   // Makes getFullName() public 
    function getFullname() {
        // Will allow you to order method in whatever order you want. 
        // If we where to have it as just this.getFullname = function () {...} and same for firstname 
        // as it is normally done, then this.getFirstname would have to be placed before this method. 
        // A common pain in the ass, that you cannot order methods as you want!    
        return getFirstname() + ", " + getLastname();   
    }               

    this.getFirstname = getFirstname;
    function getFirstname() {
        return firstname;
    }

    function setFirstname(name){
        firstname = name;
    }

    this.getLastname = getLastname;
    function getLastname() {
        return lastname;
    }
    function setLastname(name) {
        lastname = name;
    }    
}
person mmm    schedule 14.12.2012

Другие дали вам ответ на получение, но ваш вопрос больше касался установки значения.

var foo = (function() {
    //Private vars
    var a = 1;

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

    return {
        //Public vars/methods
        a: a,

Это также однократное присвоение значения a свойству a объекта, на который будет ссылаться foo. Последующие изменения переменной a не повлияют на значение этого свойства.

        changeVar: function () {
            a = 2;

Здесь a преобразуется в ссылку на «внешнюю» a, поэтому она изменит значение переменной, но не изменит значение foo.а. Если вы знаете, что он всегда будет вызываться как метод foo, вместо этого вы можете написать:

        changeVar: function () {
            this.a = 2;

так что он разрешает a как свойство foo, а не цепочку областей действия (и, следовательно, переменную a).

        }
    }
})();
person RobG    schedule 08.10.2011
comment
Я заявил в ОП, что this.a ссылается на общедоступный «а», а не на частный «а», но я хотел изменить оба, это неверно? Я изменил первое решение принятого ответа, чтобы сделать его также сеттером. a: function(value) {if(arguments.length > 0) a = value; else return a; - person Michael; 08.10.2011
comment
Да, вы можете изменить оба. Получите доступ к одному как к свойству объекта, а к другому — как к переменной в цепочке областей видимости, например. changeValue: function(value){this.a = value; a = value;}. - person RobG; 09.10.2011
comment
Это то, что вы спросили, не так ли? Вы не можете использовать одно выражение для изменения обоих, для этого требуется два выражения. - person RobG; 10.10.2011
comment
Ну, объединение их вместе через геттер/сеттер кажется лучше. - person Michael; 10.10.2011