Использование Object.DefineProperty и доступ к переменной в частной области

Следующее не работает, из моего геттера я не вижу _nickname, определенного в «классе» Person.

var Person = function (args) {

    var _nickname = '';
    if (args === undefined || args === null) {
        return;
    }
    if (args.nickname !== undefined && args.nickname !== null) {
        _nickname = args.nickname;
    }

}

Object.defineProperty(Person.prototype, "nickname", {
    get : function () {
        return _nickname;
    }
});

var x = new Person({
        nickname : 'bob'
    });

console.log(x.nickname);

Как это сделать? Есть ли способ добавить _nickname к прототипу Person из его функции?


person Matt    schedule 21.08.2013    source источник
comment
Подсказка: args === undefined || args === null то же, что и args == null, потому что null == undefined. То же самое с другим сравнением.   -  person elclanrs    schedule 22.08.2013
comment
Ах да, я был привередлив к JsLint, и ему не нравится ==. Я исправил это. Я не знаю, слишком ли я осторожен, но я надеялся, что закрытие JS позаботится об этом :-)   -  person Matt    schedule 22.08.2013
comment
JSHint — моя чашка чая. У него есть опция только для этого конкретного случая: eqnull   -  person elclanrs    schedule 22.08.2013


Ответы (1)


Есть ли способ добавить _nickname к прототипу Person из его функции?

Если вы имеете в виду конструктор Person, конечно (хотя, на мой взгляд, он выглядит не очень элегантно):

var Person = function (args) {
    var _nickname = '';
    if (args === undefined || args === null) {
        return;
    }
    if (args.nickname !== undefined && args.nickname !== null) {
        _nickname = args.nickname;
    }
    Object.defineProperty(this, "nickname", {
        get : function () {
            return _nickname;
        }
    });
}

var x = new Person({
    nickname : 'bob'
});

console.log(x.nickname);

http://jsfiddle.net/JEbds/

В этом случае ваш геттер — это просто еще одно замыкание, поэтому он имеет доступ к _nickname. И этого больше нет в прототипе, для этого вам нужно собственное свойство.

person bfavaretto    schedule 21.08.2013
comment
Но разве Object.defineProperty не будет запускаться каждый раз, когда я делаю 'new Person()'? Или это не имеет большого значения? Это действительно то, чего я хотел избежать. - person Matt; 22.08.2013
comment
Оно делает. Но если вы не запустите его из конструктора, он никогда не сможет получить доступ к _nickname. - person bfavaretto; 22.08.2013
comment
@Matt Если вы согласны с тем, что это не очень личное, вы можете использовать this._nickname (и вы даже можете установить его writable: false, поэтому значение, установленное в конструкторе, никогда не может быть изменено). jsfiddle.net/669Gb - person bfavaretto; 22.08.2013
comment
@bfavaretto Обратите внимание, что если бы вы использовали defineProperty для определения строкового значения _nickname, оно не было бы доступно для записи (поскольку строка неизменяема), но если бы _nickname было изменяемым объектом, оно было бы доступно для записи (не напрямую, а через функции объекта). Предположим, что _nickname является массивом, и в конструкторе Person мы делаем: Object.defineProperty(this, "_nickname", {value:[]}) с экземпляром person мы делаем p._nickname=22; тогда ничего не произойдет и _nickname по-прежнему будет [], но если мы сделаем: p._nickname.push(22); Тогда p._nickname будет [22]. - person HMR; 22.08.2013
comment
@Matt На самом деле нет хорошего способа иметь свойства значения частного экземпляра (свойства, которые имеют уникальные частные значения для каждого экземпляра). У вас могут быть общие частные функции в прототипе или свойстве общего значения, где значение является общим для всех экземпляров. Частные функции: stackoverflow.com/questions/18320934/ Используя функции конструктора и прототип: stackoverflow.com/questions/16063394/ - person HMR; 22.08.2013
comment
@HMR Да, если [[writable]] имеет значение false, это предотвращает только присваивания (но я не думаю, что это связано с неизменяемостью строк). Если значение является объектом или массивом, я считаю, что вы все равно можете заморозить объект (хотя у меня нет большого опыта в этом). - person bfavaretto; 22.08.2013
comment
@bfavaretto false it only prevents assignments I don't think it has to do with stings being immutable immutable означает, что вы можете изменить значение неизменяемого объекта/примитива только посредством присваивания. Вы устанавливаете для записи значение false, поэтому вы не можете изменить эти свойства. Для изменяемых объектов есть функции, которые будут изменять свои внутренние значения (вставлять в массив), строка является неизменной, потому что все ее функции не будут изменять внутреннее значение строки (.toLowerCase, .toUpperCase вернет значение, но не изменит саму строку) - person HMR; 22.08.2013
comment
@HMR Верно, я неправильно понял ваше предыдущее утверждение. - person bfavaretto; 22.08.2013