Если у нас есть функция, вызывающая себя, нам нужно поставить точку с запятой перед ней, иначе она станет частью предыдущего оператора присваивания. Учтите следующее:
testClass = function(name) {
document.write ("Instantiating testClass<br />");
this.name = name;
}
testClass.prototype.report = function() {
document.write ("I'm " + this.name + "<br />");
return 1;
}
testClass.prototype.testMethod = function(param) {
document.write ("Running testMethod with parameter value " + param + "<br />");
return 2;
} // notice that there is no semicolon here
(function() {
document.write ("Running self-invoking function<br />");
return 3;
}());
if (typeof(testClass.prototype.testMethod) !== "function") {
document.write ("testMethod type: " + typeof(testClass.prototype.testMethod));
document.write (", value: " + testClass.prototype.testMethod + "<br />");
}
var testOb = new testClass("Bill");
testOb.report();
testOb.testMethod(4);
Это приведет к следующему выводу:
"Запуск функции самовозврата
Запуск метода testMethod с
значение параметра 3
testMethod тип: число, значение: 2
Insttiating testClass
I'm Bill "
... плюс ошибка JavaScript, сообщенная браузером: testOb.testMethod is not a function
Это, конечно, не то, что мы намеревались. Почему testMethod
запускается немедленно, еще до того, как мы создали экземпляр класса? И почему он больше не существует, когда мы хотим вызвать его как метод-член?
То, что происходит, заключается в том, что testMethod
присваивается не определение нашей функции, а возвращаемое значение определения функции. И само определение функции выполняется анонимно. Вот как:
- Конструктор
testClass
и метод-член report
успешно определены / назначены.
- Из-за отсутствия точки с запятой после определения для
testMethod
, ()
, окружающий следующую самопризывающуюся функцию, становится оператором вызова, который вызывает , что мы считаем нашим определением testMethod
стать анонимной функцией, которая вызывается немедленно, а возвращаемое значение следующей анонимной функции становится ее списком параметров. Это объясняет порядок вывода на печать - сначала запускается наша функция, вызывающая себя, поскольку она оценивается как параметр.
- Поскольку определение нашей предполагаемой функции возвращает 2, именно этим 2 присваивается
testMethod
, а не определению функции. Это подтверждается нашей печатью типа и значения testMethod
.
- Теперь
testClass
успешно создан как testOb
, а его метод report
работает как задумано, доказывая, что определение класса в остальном не повреждено.
- Когда мы пытаемся вызвать
testMethod
, интерпретатор говорит нам, что это не функция - и это правильно, потому что это число со значением 2.
Если мы поставим точку с запятой после определения testMethod
, она отделит свое присваивание от вызова функции, вызывающей себя, и мы получим ожидаемый результат:
"Запуск функции самовозврата
Создание класса testClass
Я Билл
Я использую testMethod со значением параметра 4 "
Или мы могли бы даже поместить его непосредственно перед анонимной функцией:
;(function() {...
Но я полагаю, что, поскольку проблема связана с отсутствием точки с запятой в конце оператора присваивания, возможно, следует иметь привычку всегда ставить точку с запятой после определения функций таким образом. т.е. все мои функции выше должны иметь точку с запятой после закрывающей скобки, потому что все они являются назначениями анонимных функций.