Лучший подход к переменным-членам в объектно-ориентированном javascript?
Это вопрос, который я только что опубликовал.
Мне интересно, как вы все обрабатываете переменные-члены в javascript-кланах при использовании MyClass.prototype для определения методов.
Если вы определяете все методы в функции конструктора:
function MyClass(){
this.myMethod = function(){}
}
Вы можете очень хорошо объявить переменные-члены и получить доступ к ним из ваших методов:
function MyClass(){
var myVar = "hello";
this.myMethod = function(){
alert(myVar);
}
}
При использовании метода Object.prototype вы теряете эту тонкость и должны делать это следующим образом:
function MyClass(){}
MyClass.prototype.myVar = "hello";
MyClass.prototype.myMethod = function(){alert(this.hello)};
Я не сумасшедший о необходимости писать "this" каждый раз, когда я обращаюсь к переменной-члену. Я хочу использовать подход Object.prototype для соображений памяти и гибкости, но он кажется намного более неудобным по синтаксису. Это как вы, как правило, работаете?
спасибо,
-Morgan
Ответы
Ответ 1
Вы должны преодолеть свое нежелание использовать указатель this
для доступа к переменным-членам.
Назначьте переменные-члены в конструкторе, и вы можете получить к ним доступ с помощью прототипов:
function Cat(){
this.legs = 4;
this.temperament = 'Apathetic';
this.sound = 'Meow';
}
Cat.prototype.speak = function(){alert(this.sound)}
var cat = new Cat();
cat.speak();
Да, эти атрибуты объекта общедоступны, но, как сказал бы Гвидо, мы все взрослые здесь. Javascript - это, в конце концов, простой текстовый, слабо типизированный, интерпретируемый язык. Преимущества переменных "private" в этой среде в лучшем случае шатки.
Я говорю только, чтобы быть явным и очевидным о том, как следует обращаться к вашему объекту, а нарушители будут отклоняться от этого на свой страх и риск.
Ответ 2
Видимость атрибутов объекта зависит от того, как вы их объявляете
function Cat( name ) {
//private variable unique to each instance of Cat
var privateName = 'Cat_'+Math.floor( Math.random() * 100 );
//public variable unique to each instance of Cat
this.givenName = name;
//this method has access to private variables
this.sayPrivateName = function() {
alert( privateName );
}
}
//this variable is shared by all cats
Cat.prototype.generalName = 'tiddles';
//this method is shared by all cats and has no access to private vars
Cat.prototype.sayname = function( type ) {
alert( this[type+'Name'] || 'private!' );
}
var vic = new Cat('Victor');
var ellers = new Cat('Elmore');
vic.sayname('general'); //tiddles
vic.sayname('given'); //Victor
vic.sayname('private'); //private - no access
vic.sayPrivateName(); //cat will say its name
ellers.sayname('general'); //tiddles
ellers.sayname('given'); //Elmore
ellers.sayname('private'); //private - no access
ellers.sayPrivateName(); //cat will say its name
Ответ 3
Вы должны использовать прототип для хранения методов, потому что, когда вы найдете 100 методов, они не копируются между экземплярами, а используют один и тот же прототип.
Я использую что-то в этих строках:
var myClass = function(){};
myClass.prototype = {
method1: function(){}
,method2: function(){}
};
Ответ 4
A (не так) небольшое замечание по переменным 'private' при назначении методам прототипу:
Верно, что вы не можете использовать конструктор для создания замыкания по ним, но вы можете, конечно, объединить прототипы с анонимной функцией и получить частные переменные, разделяемые между экземплярами объекта:
function Foo() {}
(function() {
var sharedPrivateVar;
Foo.prototype.methodWithAccessToSharedPrivateVar = function() {};
})();
С еще одним сглаживанием вы можете реализовать свои собственные механизмы защиты, например переменные, которые могут быть прочитаны, а не написаны с помощью:
function Foo() {
this.registerInstance({ bar : 'baz' });
this.registerInstance = undefined;
}
(function() {
var store = {}, guid = 0;
Foo.prototype.registerInstance = function(protectedProperties) {
this.__guid = ++guid;
store[this.__guid] = protectedProperties;
};
Foo.prototype.getProtectedProperty = function(name) {
return store[this.__guid][name];
};
})();
Этот подход не будет страдать от создания расширенного объекта и закрытия, но увеличивает время поиска на небольшую сумму.
Изменить: Вы также должны указать функцию
Foo.prototype.unregisterInstance = function() {
delete store[this.__guid];
};
В противном случае это хороший способ ввести утечку памяти...
Edit2: Вы также можете обойти необходимость в функции registerInstance()
со следующим шаблоном:
Foo = (function() {
var store = {}, guid = 0;
function Foo() {
this.__guid = ++guid;
store[guid] = { bar : 'baz' };
}
Foo.prototype.getBar = function() {
var privates = store[this.__guid];
return privates.bar;
};
Foo.prototype.destroy = function() {
delete store[this.__guid];
};
return Foo;
})();
Ответ 5
Вы найдете много людей, использующих
function name()
{
var m_var = null;
var privateMethod = function() { }
this.PublicMethod = function() { }
}
Включая меня. Я склонен не писать огромные классы JS, и этот синтаксис довольно легко писать, а также позволяет использовать частные методы/переменные.
ИЗМЕНИТЬ
Итак, вы говорите мне, что использование XML для SOAP-пакетов просто для облегчения отладки на один шаг - это хорошо (хотя XML тратит BUNCH пространства и полосы пропускания и разбора времени), но добавление нескольких байтов на экземпляр объекта javascript не хорошо, даже если это позволяет нам использовать некоторые из фундаментальных концепций ОО, которые должны существовать на языке с самого начала?
Хм...
(для моего комментария XML читайте комментарии для: REST URI и операции над объектом, который можно прокомментировать, помечен, оценен и т.д.)