JavaScript: Class.method vs. Class.prototype.method
В чем разница между следующими двумя объявлениями?
Class.method = function () { /* code */ }
Class.prototype.method = function () { /* code using this.values */ }
Можно ли считать первый оператор как объявление статического метода, а второй - объявлением метода экземпляра?
Ответы
Ответ 1
Да, первая функция не имеет отношения к экземпляру объекта этой конструкторской функции , вы можете рассматривать ее как "статический метод".
В функциях JavaScript есть объекты first-class, что означает, что вы можете относиться к ним точно так же, как к любому объекту, в этом случае вы добавляете только свойство объекта функции.
Вторая функция, поскольку вы расширяете прототип функции конструктора, будет доступна для всех экземпляров объектов, созданных с помощью new
ключевое слово и контекст внутри этой функции (this
) будет ссылаться на фактический экземпляр объекта, где вы его называете.
Рассмотрим следующий пример:
// constructor function
function MyClass () {
var privateVariable; // private member only available within the constructor fn
this.privilegedMethod = function () { // it can access private members
//..
};
}
// A 'static method', it just like a normal function
// it has no relation with any 'MyClass' object instance
MyClass.staticMethod = function () {};
MyClass.prototype.publicMethod = function () {
// the 'this' keyword refers to the object instance
// you can access only 'privileged' and 'public' members
};
var myObj = new MyClass(); // new object instance
myObj.publicMethod();
MyClass.staticMethod();
Ответ 2
Когда вы создаете несколько экземпляров MyClass, у вас будет только один экземпляр publicMethod в памяти, но в случае privilegedMethod вы создадите множество экземпляров, а staticMethod не будет иметь отношения к экземпляру объекта.
Вот почему прототипы сохраняют память.
Кроме того, если вы измените свойства родительского объекта, дочернее соответствующее свойство не было изменено, оно будет обновлено.
Ответ 3
Для визуальных учащихся при определении функции без .prototype
ExampleClass = function(){};
ExampleClass.method = function(customString){
console.log((customString !== undefined)?
customString :
"called from func def.");}
ExampleClass.method(); // >> output: `called from func def.`
var someInstance = new ExampleClass();
someInstance.method('Called from instance');
// >> error! `someInstance.method is not a function`
С тем же кодом, если добавлен .prototype
,
ExampleClass.prototype.method = function(customString){
console.log((customString !== undefined)?
customString :
"called from func def.");}
ExampleClass.method();
// > error! `ExampleClass.method is not a function.`
var someInstance = new ExampleClass();
someInstance.method('Called from instance');
// > output: `Called from instance`
Чтобы сделать его понятным,
ExampleClass = function(){};
ExampleClass.directM = function(){} //M for method
ExampleClass.prototype.protoM = function(){}
var instanceOfExample = new ExampleClass();
ExampleClass.directM(); ✓ works
instanceOfExample.directM(); x Error!
ExampleClass.protoM(); x Error!
instanceOfExample.protoM(); ✓ works
**** Примечание для примера выше, someInstance.method() не будет выполняться как,
ExampleClass.method() вызывает ошибки и выполнение не может продолжаться.
Но для иллюстрации и легкого понимания, я сохранил эту последовательность. ****
Результаты, полученные из chrome developer console
и JS Bin
Нажмите на ссылку jsbin выше, чтобы перейти через код.
Переключить секцию комментария с помощью ctrl + /