Я видел пару похожих ответов, но я хотел бы отметить, что этот пост описывает это лучше всего, поэтому я хотел бы поделиться им с вами.
Вот некоторый код, взятый из него, который я модифицировал, чтобы получить полный пример, который, мы надеемся, принесет пользу сообществу, потому что его можно использовать как шаблон дизайна для классов.
Это также отвечает на ваш вопрос:
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
console.log(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
3-го параметра, например 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]"
Вы можете найти более подробную информацию о прототипах здесь . Если вы хотите сделать больше наследства, я предлагаю изучить это .
В серии статей я уже упоминал выше, настоятельно рекомендуется читать, они включают в себя также следующие вопросы:
- функции
- Объекты
- Прототипы
- Внедрение новых функций конструктора
- Подъемно
- Автоматическая вставка точки с запятой
- Статические свойства и методы
Обратите внимание, что автоматическая вставка точки с запятой функция « в JavaScript (как упоминалось в 6.) очень часто вызывает странные проблемы в вашем коде. Следовательно, я бы скорее расценил это как ошибку, чем как особенность.
Если вы хотите прочитать больше, вот довольно интересная статья MSDN на эти темы, некоторые из них, описанные там, предоставляют еще больше деталей.
Также интересно прочитать ( в том числе и по темам, упомянутым выше) статьи из руководства по MDN JavaScript :
Если вы хотите узнать, как эмулировать out
параметры c # (например, в 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» против «let») . Также рекомендуется эта статья о неявных типах (принуждение) .
Удобный способ использовать классы и скомпилировать их в JavaScript - это TypeScript. Вот игровая площадка, где вы можете найти несколько примеров, показывающих, как это работает. Даже если вы не используете TypeScript в данный момент, вы можете посмотреть, потому что вы можете сравнить TypeScript с результатом JavaScript в параллельном представлении. Большинство примеров просты, но есть также пример Raytracer, который вы можете попробовать немедленно. Особенно рекомендую ознакомиться с примерами «Использование классов», «Использование наследования» и «Использование обобщенных элементов», выбрав их в выпадающем списке - это хорошие шаблоны, которые можно мгновенно использовать в JavaScript. Typescript используется с 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
файл; это просто написано, чтобы пример был коротким.
Самовызывающиеся функции (также известные как IIFE = выражение для немедленного вызова функции) описаны более подробно здесь .