Я видел пару похожих ответов, но я хотел бы отметить, что этот пост описывает его лучше всего, поэтому я хотел бы поделиться им с вами.
Вот некоторый код, взятый из него, который я модифицировал, чтобы получить полный пример, который, мы надеемся, принесет пользу сообществу, потому что его можно использовать как шаблон дизайна для классов.
Он также отвечает на ваш вопрос:
function Podcast() {
// private variables
var _somePrivateVariable = 123;
// object properties (read/write)
this.title = 'Astronomy Cast';
this.description = 'A fact-based journey through the galaxy.';
this.link = 'http://www.astronomycast.com';
// for read access to _somePrivateVariable via immutableProp
this.immutableProp = function() {
return _somePrivateVariable;
}
// object function
this.toString = function() {
return 'Title: ' + this.title;
}
};
// static property
Podcast.FILE_EXTENSION = 'mp3';
// static function
Podcast.download = function(podcast) {
console.log('Downloading ' + podcast + ' ...');
};
Учитывая этот пример, вы можете получить доступ к статическим свойствам / функции следующим образом:
// access static properties/functions
Podcast.FILE_EXTENSION; // 'mp3'
Podcast.download('Astronomy cast'); // 'Downloading Astronomy cast ...'
И свойства / функции объекта просто как:
// access object properties/functions
var podcast = new Podcast();
podcast.title = 'The Simpsons';
console.log(podcast.toString()); // Title: The Simpsons
console.log(podcast.immutableProp()); // 123
Обратите внимание , что в podcast.immutableProp () у нас есть замыкание : Ссылка на _somePrivateVariable сохраняется внутри функции.
Вы даже можете определить геттеры и сеттеры . Взгляните на этот фрагмент кода (где d
- это прототип объекта, для которого вы хотите объявить свойство, y
- закрытая переменная, не видимая за пределами конструктора):
// getters and setters
var d = Date.prototype;
Object.defineProperty(d, "year", {
get: function() {return this.getFullYear() },
set: function(y) { this.setFullYear(y) }
});
Он определяет свойство d.year
с помощью функций get
и set
- если вы не укажете set
, то свойство доступно только для чтения и не может быть изменено (учтите, что вы не получите ошибку если вы пытаетесь установить его, но это не имеет никакого эффекта). Каждое свойство имеет атрибуты writable
, configurable
(позволяют изменять после объявления) и enumerable
(позволяют использовать его в качестве перечислителя), которые по умолчанию false
. Вы можете установить их с помощью defineProperty
в третьем параметре, например, enumerable: true
.
Также допустим синтаксис:
// getters and setters - alternative syntax
var obj = { a: 7,
get b() {return this.a + 1;},
set c(x) {this.a = x / 2}
};
, которая определяет свойство для чтения / записи a
, свойство только для чтения b
и свойство только для записи c
, через которое можно получить доступ к свойству a
.
Использование:
console.log(obj.a); console.log(obj.b); // output: 7, 8
obj.c=40;
console.log(obj.a); console.log(obj.b); // output: 20, 21
Примечания:
Чтобы избежать неожиданного поведения в случае, если вы забыли ключевое слово new
, я предлагаю добавить в функцию Podcast
следующее:
// instantiation helper
function Podcast() {
if(false === (this instanceof Podcast)) {
return new Podcast();
}
// [... same as above ...]
};
Теперь оба следующих экземпляра будут работать как положено:
var podcast = new Podcast(); // normal usage, still allowed
var podcast = Podcast(); // you can omit the new keyword because of the helper
Оператор 'new' создает новый объект и копирует все свойства и методы, т.е.
var a=new Podcast();
var b=new Podcast();
a.title="a"; b.title="An "+b.title;
console.log(a.title); // "a"
console.log(b.title); // "An Astronomy Cast"
Обратите также внимание, , что в некоторых ситуациях может быть полезно использовать оператор return
в функции конструктора Podcast
, чтобы возвращать пользовательский объект, защищающий функции, на которые класс полагается, но которые необходимо быть разоблаченным Это объясняется далее в главе 2 (Объекты) серии статей.
Можно сказать, что a
и b
наследуются от Podcast
. Теперь, что если вы хотите добавить в Podcast метод, который будет применяться ко всем из них после создания экземпляров a
и b
? В этом случае используйте .prototype
следующим образом:
Podcast.prototype.titleAndLink = function() {
return this.title + " [" + this.link + "]";
};
Теперь позвоните a
и b
снова:
console.log(a.titleAndLink()); // "a [http://www.astronomycast.com]"
console.log(b.titleAndLink()); // "An Astronomy Cast [http://www.astronomycast.com]"
Более подробную информацию о прототипах вы можете найти здесь . Если вы хотите больше наследовать, я советую изучить this .
Серия статей , о которой я упоминал выше, настоятельно рекомендуется прочитать , они также включают следующие темы:
- Функции
- Предметы
- Прототипы
- Применение новых функций в конструкторе
- Подъемно
- Автоматическая вставка точек с запятой
- Статические свойства и методы
Обратите внимание , что автоматическая вставка точки с запятой «особенность» JavaScript (как упомянуто в 6.) очень часто является причиной странных проблем в вашем коде , Следовательно, я бы скорее расценил это как ошибку, чем как особенность.
Если вы хотите узнать больше, здесь - довольно интересная MSDN статья об этих темах, некоторые из них, описанные там, предоставляют еще больше деталей.
Что еще интересно читать (также охватывающие упомянутые выше темы) - это статьи из MDN JavaScript Guide :
Если вы хотите узнать, как эмулировать параметры c # out
(как в DateTime.TryParse(str, out result)
) в JavaScript, вы можете найти образец кода здесь.
Те из вас, кто работает с IE (в котором нет консоли для JavaScript, если вы не откроете инструменты разработчика с помощью F12 и не откроете вкладку консоли) может оказаться полезным следующий фрагмент кода. Это позволяет использовать console.log(msg);
, как в примерах выше. Просто вставьте его перед функцией Podcast
.
Для вашего удобства приведенный выше код в одном полном фрагменте кода:
let console = { log: function(msg) {
let canvas = document.getElementById("log"), br = canvas.innerHTML==="" ? "" : "<br/>";
canvas.innerHTML += (br + (msg || "").toString());
}};
console.log('For details, see the explaining text');
function Podcast() {
// with this, you can instantiate without new (see description in text)
if (false === (this instanceof Podcast)) {
return new Podcast();
}
// private variables
var _somePrivateVariable = 123;
// object properties
this.title = 'Astronomy Cast';
this.description = 'A fact-based journey through the galaxy.';
this.link = 'http://www.astronomycast.com';
this.immutableProp = function() {
return _somePrivateVariable;
}
// object function
this.toString = function() {
return 'Title: ' + this.title;
}
};
// static property
Podcast.FILE_EXTENSION = 'mp3';
// static function
Podcast.download = function(podcast) {
console.log('Downloading ' + podcast + ' ...');
};
// access static properties/functions
Podcast.FILE_EXTENSION; // 'mp3'
Podcast.download('Astronomy cast'); // 'Downloading Astronomy cast ...'
// access object properties/functions
var podcast = new Podcast();
podcast.title = 'The Simpsons';
console.log(podcast.toString()); // Title: The Simpsons
console.log(podcast.immutableProp()); // 123
// getters and setters
var d = Date.prototype;
Object.defineProperty(d, "year", {
get: function() {
return this.getFullYear()
},
set: function(y) {
this.setFullYear(y)
}
});
// getters and setters - alternative syntax
var obj = {
a: 7,
get b() {
return this.a + 1;
},
set c(x) {
this.a = x / 2
}
};
// usage:
console.log(obj.a); console.log(obj.b); // output: 7, 8
obj.c=40;
console.log(obj.a); console.log(obj.b); // output: 20, 21
var a=new Podcast();
var b=new Podcast();
a.title="a"; b.title="An "+b.title;
console.log(a.title); // "a"
console.log(b.title); // "An Astronomy Cast"
Podcast.prototype.titleAndLink = function() {
return this.title + " [" + this.link + "]";
};
console.log(a.titleAndLink()); // "a [http://www.astronomycast.com]"
console.log(b.titleAndLink()); // "An Astronomy Cast [http://www.astronomycast.com]"
<div id="log"></div>
Примечания:
Несколько хороших советов, советов и рекомендаций по программированию на JavaScript в целом вы можете найти здесь (лучшие практики JavaScript) и там ('var 'против' пусть ') . Также рекомендуется эта статья о неявных типах (принуждение) .
Удобный способ использовать классы и скомпилировать их в JavaScript: TypeScript. Вот игровая площадка , где вы можете найти несколько примеров, показывающих вам как это устроено.
Даже если вы не используете TypeScript в данный момент, вы можете посмотреть, потому что вы можете сравнить TypeScript с результатом JavaScript в режиме бок о бок. Большинство примеров просты, но есть и пример Raytracer, который вы можете попробовать немедленно.
Особенно рекомендую ознакомиться с примерами «Использование классов», «Использование наследования» и «Использование обобщенных элементов», выбрав их в выпадающем списке - это хорошие шаблоны, которые можно мгновенно использовать в JavaScript. Машинописный текст используется с Angular.
Для достижения инкапсуляции локальных переменных, функций и т. Д. В JavaScript, я предлагаю использовать шаблон, подобный следующему (JQuery использует ту же технику):
<html>
<head></head>
<body><script>
'use strict';
// module pattern (self invoked function)
const myModule = (function(context) {
// to allow replacement of the function, use 'var' otherwise keep 'const'
// put variables and function with local module scope here:
var print = function(str) {
if (str !== undefined) context.document.write(str);
context.document.write("<br/><br/>");
return;
}
// ... more variables ...
// main method
var _main = function(title) {
if (title !== undefined) print(title);
print("<b>last modified: </b>" + context.document.lastModified + "<br/>");
// ... more code ...
}
// public methods
return {
Main: _main
// ... more public methods, properties ...
};
})(this);
// use module
myModule.Main("<b>Module demo</b>");
</script></body>
</html>
Конечно, вы можете - и должны - поместить код скрипта в отдельный файл *.js
; это просто написано, чтобы пример был коротким.