Да, я согласен, что прототип можно использовать для значений свойств (переменных) по умолчанию. Функция конструктора не должна объявлять свойство; это может быть сделано условно.
function Person( name, age ) {
this.name = name;
if ( age ) {
this.age = age;
}
}
Person.prototype.sayHello = function() {
console.log( 'My name is ' + this.name + '.' );
};
Person.prototype.sayAge = function() {
if ( this.age ) {
console.log( 'I am ' + this.age + ' yrs old!' );
} else {
console.log( 'I do not know my age!' );
}
};
Person.prototype.age = 0.7;
//-----------
var person = new Person( 'Lucy' );
console.log( 'person.name', person.name ); // Lucy
console.log( 'person.age', person.age ); // 0.7
person.sayAge(); // I am 0.7 yrs old!
Посмотрите, как Люси age
условно объявлен и инициализирован.
Да, я согласен с тем, что циклы do while можно переписать в цикл while, однако я не согласен с тем, что всегда использовать цикл while лучше. do while всегда запускается хотя бы один раз, и это очень полезное свойство (наиболее типичным примером является проверка ввода (с клавиатуры))
#include <stdio.h>
int main() {
char c;
do {
printf("enter a number");
scanf("%c", &c);
} while (c < '0' || c > '9');
}
Это, конечно, можно переписать в цикл while, но обычно это рассматривается как нечто большее элегантное решение.
Цикл do-while всегда можно переписать как цикл while.
Следует ли использовать только циклы while или циклы while, do-while и for (или любую их комбинацию ) во многом зависит от вашего вкуса к эстетике и условностей проекта, над которым вы работаете.
Лично я предпочитаю циклы while, потому что они упрощают рассуждения об инвариантах цикла. ИМХО.
Что касается того, есть ли ситуации, когда вы это делаете нужны циклы do-while: вместо
do
{
loopBody();
} while (condition());
вы всегда можете
loopBody();
while(condition())
{
loopBody();
}
, так что нет, вам никогда не нужно использовать do-while, если вы не можете по какой-то причине. (Конечно, этот пример нарушает DRY, но это только доказательство концепции. По моему опыту, обычно существует способ преобразования цикла do-while в цикл while и не нарушать DRY в любом конкретном случае использования.)
«Находясь в Риме, поступайте, как римляне».
BTW: Цитата, которую вы ищете, может быть следующей ([1], последний абзац раздела 6.3.3):
По моему опыту, оператор do является источником ошибок и путаницы. Причина в том, что его тело всегда выполняется один раз перед проверкой условия. Однако для правильного функционирования тела необходимо, чтобы при первом запуске выполнялось условие, аналогичное конечному. Чаще, чем я ожидал, я обнаруживал, что эти условия не выполняются. Так было как тогда, когда я писал данную программу с нуля и затем тестировал ее, так и после изменения кода. Кроме того, я предпочитаю условие «впереди, где я могу это видеть». Поэтому я стараюсь избегать заявлений о делах.
(Примечание: это мой перевод немецкого издания. Если вам посчастливилось владеть английским изданием, не стесняйтесь редактировать цитату, чтобы она соответствовала его исходной формулировке. К сожалению, Аддисон-Уэсли ненавидит Google.)
[1] B. Страуструп: Язык программирования C ++. 3-е издание. Addison-Wessley, Reading, 1997.
Прочтите теорему о структурированной программе . Do {} while () всегда можно переписать на while () do {}. Последовательность, выбор и итерация - это все, что когда-либо требовалось.
Поскольку все, что содержится в теле цикла, всегда можно инкапсулировать в подпрограмму, необходимость использования while () do {} никогда не будет хуже, чем
LoopBody()
while(cond) {
LoopBody()
}
] В ответ на вопрос / комментарий от unknown (google) к ответу Дэна Олсона:
«do {...} while (0) - важная конструкция для создания макросов ведите себя хорошо. "
#define M do { doOneThing(); doAnother(); } while (0)
...
if (query) M;
...
Вы видите, что происходит без do {...} while (0)
? Он всегда будет выполнять doAnother ().
В наших соглашениях о кодировании
Итак, у нас есть почти никогда не делать {} while (xx)
Потому что:
int main() {
char c;
do {
printf("enter a number");
scanf("%c", &c);
} while (c < '0' || c > '9');
}
переписан на:
int main() {
char c(0);
while (c < '0' || c > '9'); {
printf("enter a number");
scanf("%c", &c);
}
}
, а
Handle handle;
Params params;
if( ( handle = FindFirstFile( params ) ) != Error ) {
do {
process( params ); //process found file
} while( ( handle = FindNextFile( params ) ) != Error ) );
}
переписан на:
Params params(xxx);
Handle handle = FindFirstFile( params );
while( handle!=Error ) {
process( params ); //process found file
handle = FindNextFile( params );
}
Это полезно, когда вы хотите «что-то сделать», пока «условие не будет выполнено.
Это можно исправить в цикле while следующим образом:
while(true)
{
// .... code .....
if(condition_satisfied)
break;
}
На мой взгляд, это только личный выбор.
В большинстве случаев вы можете найти способ переписать цикл do ... while в цикл while; но не обязательно всегда. Также может быть более логичным иногда писать цикл do while, чтобы он соответствовал контексту, в котором вы находитесь.
Если вы посмотрите выше, ответ TimW говорит сам за себя. Второй вариант с Handle, на мой взгляд, особенно запутан.
do {...}, а (0)
- важная конструкция для обеспечения правильного поведения макросов.
Даже если это неважно в реальном коде (с чем я не обязательно согласен), это важно для исправления некоторых недостатков препроцессора.
Редактировать: Я столкнулся с ситуацией, когда do / while сегодня было намного чище. в моем собственном коде. Я делал кроссплатформенную абстракцию парных инструкций LL / SC . Их необходимо использовать в цикле, например:
do
{
oldvalue = LL (address);
newvalue = oldvalue + 1;
} while (!SC (address, newvalue, oldvalue));
(Эксперты могут понять, что старое значение не используется в реализации SC, но оно включено, чтобы эту абстракцию можно было эмулировать с помощью CAS.)
LL и SC являются отличный пример ситуации, когда do / while значительно чище, чем эквивалентная форма while:
Все дело в читабельности .
Более читаемый код снижает головную боль при сопровождении кода и улучшает совместную работу.
Другие соображения (например, оптимизация) в большинстве случаев гораздо менее важны.
Я уточню, так как я получил здесь комментарий:
Если у вас есть фрагмент кода A , в котором используется do {...} while ()
, и он более читабелен, чем его while () {...}
эквивалент B , то я бы проголосовал за A . Если вы предпочитаете B , поскольку вы видите условие цикла «впереди», и считаете его более читаемым (и, следовательно, поддерживаемым и т. Д.) - тогда продолжайте, используйте B .
Моя точка зрения: используйте код, который более читается для ваших глаз (и для ваших коллег). Выбор, конечно, субъективен.
(Предполагая, что вы знаете разницу между ними)
Do / While подходит для начальной загрузки / предварительной инициализации кода перед проверкой вашего условия и запуском цикла while.
Я почти никогда не использую их просто из-за следующего:
Несмотря на то, что цикл проверяет наличие постусловия, вам все равно нужно проверять это условие поста в своем цикле, чтобы вы не не обрабатывает условие публикации.
Возьмем пример псевдокода:
do {
// get data
// process data
} while (data != null);
Теоретически это звучит просто, но в реальных ситуациях это, вероятно, будет выглядеть так:
do {
// get data
if (data != null) {
// process data
}
} while (data != null);
Дополнительная проверка «если» просто не является т стоит ИМО. Я нашел очень мало случаев, когда было бы проще выполнить do-while вместо цикла while. YMMV.
do-while - это цикл с постусловием. Он нужен в случаях, когда тело цикла нужно выполнить хотя бы один раз. Это необходимо для кода, который требует некоторых действий перед тем, как условие цикла может быть разумно оценено. С циклом while вам придется вызывать код инициализации с двух сайтов, с do-while вы можете вызывать его только с одного сайта.
Другой пример - когда у вас уже есть действительный объект, когда должна быть запущена первая итерация, поэтому вы не хотите ничего выполнять (включая оценку условий цикла) до начала первой итерации. Примером являются функции Win32 FindFirstFile / FindNextFile: вы вызываете FindFirstFile, который либо возвращает ошибку, либо дескриптор поиска для первого файла, затем вы вызываете FindNextFile, пока он не вернет ошибку.
Псевдокод:
Handle handle;
Params params;
if( ( handle = FindFirstFile( params ) ) != Error ) {
do {
process( params ); //process found file
} while( ( handle = FindNextFile( params ) ) != Error ) );
}
Моя проблема с do / , а строго связана с его реализацией в C. Из-за повторного использования while ключевое слово, оно часто сбивает людей с толку, потому что выглядит ошибкой.
Если while было зарезервировано только для , а циклы и do / в то время как был изменен на делать / до или повторять / до , я не думаю, что цикл (который, безусловно, удобен и является «правильным» способом кодирования некоторых циклов) вызвал бы столько проблем.
Я уже говорил об этом ранее в отношении JavaScript ,который также унаследовал этот жалкий выбор от C.
рассмотрите что-то вроде этого:
int SumOfString(char* s)
{
int res = 0;
do
{
res += *s;
++s;
} while (*s != '\0');
}
Так получилось, что '\ 0' равно 0, но я надеюсь, что вы поняли.
Следующая распространенная идиома кажется мне очень простой:
do {
preliminary_work();
value = get_value();
} while (not_valid(value));
Переписать, чтобы избежать do
, похоже:
value = make_invalid_value();
while (not_valid(value)) {
preliminary_work();
value = get_value();
}
Эта первая строка используется, чтобы убедиться, что тест всегда оценивается как истина в первый раз. Другими словами, тест всегда бывает лишним с первого раза. Если бы этого лишнего теста не было, можно было бы также опустить начальное задание. Этот код производит впечатление, что он борется сам с собой.
В подобных случаях конструкция do
является очень полезной опцией.