Обращение к приватной переменной из прототипной функции
Доброго времени суток! Подскажите, никак не могу найти решение касательно js. Давайте сразу к простому примеру:
var human = (function () {
var prototype = {}
prototype.getName
prototype.getName = function (str) {
if (str) this.name = str
return this.name
}
function constructor(data) {
this.name
}
constructor.prototype = prototype
return constructor
}())
var h1 = new human
h1.getName('Vasia')
var h2 = new human
h2.getName('Petia')
Условие тут таково, что должны быть прототипные функции, которые будут обращаться в приватным переменным экземпляра конструктора. В данном случае this.name — это публичное свойство, но что если я не хочу чтобы можно было напрямую менять name в духе:
var h1 = new human
h1.getName('Vasia')
h1.name = 'Petia'
Как мне это преградить? Иными словами: как работать с приватными переменными из функции в прототипе? Вроде как банальная потребность. Единственное что пришло в голову: это хранить массив id экземпляров с объектами данных выше уровнем, чем конструктор, а в this.id хранить уже сам идентификатор конкретного экземпляра. Но, согласитесь, это маразм, да и к тому же поменять id многого ли стоит? |
Цитата:
Цитата:
var human = (function () {
var prototype = {}
prototype.getName
+function(){
var name;
prototype.getName = function (str) {
if (str) name = str
return name
}
function constructor(data) {
name
}
}()
constructor.prototype = prototype
return constructor
}())
var h1 = new human
h1.getName('Vasia')
var h2 = new human
h2.getName('Petia')
|
Цитата:
Если бы всё было так просто, я бы не спрашивал, после выполнения этого кода, стало так: h1.getName() // Petia h2.getName() // Petia Мне нужно чтобы name был уникальным для каждого экземпляра. |
Цитата:
Цитата:
var human = (function () {
var prototype = {}
prototype.getName
+function(){
var name;
prototype.getName = function (str) {
if (str) name = str
return name
}
function constructor(data) {
name
}
}()
constructor.prototype = prototype
return constructor
}())
var h1 = new human
h1.getName('Vasia')
var h2 = new human
h2.getName('Petia')
|
Исправил вашь код:
function log(a){document.body.innerHTML+=a+'<br>'}
//функция хуман это не конструктор, она возвращает конструктор которы надо потом инициализировать с помощью new
var human = (function () {
var prototype = {}
//prototype.getName
var _data, _name;
prototype.setName = function (str)
{
if (str) _name = str
}
prototype.getName = function ()
{
return _name
}
function constructor(data) {
//this.name
_data=data
}
constructor.prototype = prototype
return constructor
})
var Alfa = new (human())() //столько скобок нужно что бы new относилось к constructor а не к human,
Alfa.setName('Vasia')
log('Alfa: '+ Alfa.getName() )
var Beta = new (human())()
Beta.setName('Petia')
Beta._name='Евгений Ваганыч'; //создаться публичное свойство _name но приватное _name не изменится
log('Beta: '+ Beta.getName() );
log('Alfa: '+ Alfa.getName() )
Раед, Вашь код не работает в IE9 и Опере (в других не тестил) опера ругается Uncaught exception: TypeError: 'h1.getName' is not a function И я не понимаю что за синтаксис такой +function |
Цитата:
var human = (function () {
var prototype = {}
prototype.getName
+function(){
var name;
prototype.getName = function (str) {
if (str) name = str
return name
}
function constructor(data) {
name
}
}()
constructor.prototype = prototype
return constructor
}())
var h1 = new (human())();
h1.getName('Vasia')
var h2 = new (human())();
h2.getName('Petia')
Цитата:
|
Просто назовите свойство
_name. Такое соглашение о именование свойств, которые не должны использоваться снаружи, давно устоялось, известно и используется множеством js-программистов. |
Цитата:
Цитата:
Опера например ругается Цитата:
Цитата:
|
Цитата:
|
Ну городите замыкания, раз вас веселит соглашение об именовании свойств, которое, как UpperCamelCase для конструкторов и lowerCamelCase для всего остального, присутствует в guidеline'ах к стилю JavaScript-кода.
|
Кроме огорода замыканий не вижу вариантов. Можно, например, создавать в конструкторе одноимённое прототипному свойство, которое будет вызывать функцию с тем же именем. из прототипа, передавая ей приватную переменную. Саму процедуру обёртывания и замыкания можно тоже в прототип переместить. Так в конструкторе повторы будут, конечно, но меньше, чем если просто там размещать все функции. Получается как-то так:
function Human(name) {
this.makeWrap("getName", [name]);
}
Human.prototype = {
makeWrap: function (propertyName, args) {
this[propertyName] = (
function(args) {
return function() {
return Human.prototype[propertyName](args);
}
}
)(args)
},
getName: function(name) {
return name[0];
},
constructor: Human
}
h1 = new Human("Василий Иванович");
h2 = new Human("Иван Васильевич");
alert(h1.getName())
alert(h2.getName())
. Как-то костыльно, nein? Вариант с соглашением проще. и лучше, на мой взгляд. |
Цитата:
|
Цитата:
В таком случае решение с символом «_» — лучший вариант, когда нужны тру-прототипы. |
GuardCat,
Посмотрел вашь код понял что вы предлагаете запоминать name в массиве который зависнет как параметр анонимной функции внутри нового метода getName который переопределит makeWrap. Надо сказать это весьма и весьма хиро%опо :D setName можно реализовать также как в конструкторе:
...
setName: function(newName)
{
this.makeWrap('getName',[newName])
},
...
Но ведь это ужасно :( получается прямого доступа к полю нейм нету даже внутри методов объекта. Во что у меня получилось из вашего кода (массивы убрал так как тут они не нужны):
function log(a){alert(a)}
function Human(name)
{
this.makeWrap("getName", name);
}
Human.prototype =
{
makeWrap: function (propertyName, args)
{
this[propertyName] =
(
function(args)
{
return function()
{
return Human.prototype[propertyName](args);
}
}
)(args)
},
setName: function(newName)
{
this.makeWrap('getName',newName)
},
getName: function(name)
{
return name;
},
setLastName: function(LName)
{
this.makeWrap('getLastName',LName)
},
getLastName: function(LName)
{
return LName
},
getFullName: function()
{
return this.getName()+' '+this.getLastName();
}
// ,constructor: Human
}
h1 = new Human("Владимир");
h2 = new Human("Дмитрий");
h1.setLastName('Путин');
log(h1.getFullName())
h2.setLastName('Медведев');
log(h2.getFullName())
h2.setName('Александр')
log(h2.getFullName())
log('Протипы равны? '+(h1.__proto__ === h2.__proto__))
|
Mixxx, массивы будут удобны, если возникнет необходимость передавать больше одного параметра. Можно и в этом случае обойтись без массивов, но с ними проще.
|
Maxmaxmахimus, спасибо за ссылку, есть кое что полезное на заметку.
|
Приваты, судя по ECMA будут, и как я понял это будет private и объект x.
private key x.key // x для приватов вместо this |
| Часовой пояс GMT +3, время: 22:48. |