2013-03-07 3 views
7

Объекты JavaScript имеют элемент «прототип» для облегчения наследования. Но, похоже, мы можем жить отлично, даже без него, и я подумал, в чем преимущества его использования. Я задавался вопросом, какие плюсы и минусы.Зачем использовать «прототип» для наследования javascript?

Для примера рассмотрим следующее (здесь jsfiddle):

function Base (name) { 

    this.name = name; 
    this.modules = []; 
    return this; 
} 

Base.prototype = 
{ 
    initModule: function() { 
     // init on all the modules. 
     for (var i = 0; i < this.modules.length; i++) 
      this.modules[i].initModule(); 
     console.log("base initModule"); 
    } 
}; 

function Derived(name) { 
     Base.call(this,name); // call base constructor with Derived context 
} 

Derived.prototype = Object.create(Base.prototype); 

Derived.prototype.initModule = function() { 
     console.log("d init module"); 
     // calling base class functionality 
     Base.prototype.initModule.call(this); 
    } 

var derived = new Derived("dname"); 
console.log(derived.name); 
derived.initModule(); 

Возникает вопрос, зачем использовать 'прототип' вообще? Мы также можем сделать что-то вроде Derived = Object.create(Base);

, например (jsfiddle):

Base = 
{ 
    initModule: function() { 
     // init on all the modules. 
     for (var i = 0; i < this.modules.length; i++) 
      this.modules[i].initModule(); 
     console.log("base initModule",this.name); 
    }, 
    init: function(name) { 
     this.name = name; 
     this.modules = []; 
    } 
}; 

Derived = Object.create(Base); 

Derived.initModule = function() { 
     console.log("d init module"); 
     // calling base class functionality 
     Base.initModule.call(this); 
    } 
Derived.init("dname"); 
console.log(Derived.name); 
Derived.initModule(); 
+3

Один про - скорость: http://jsperf.com/prototype-vs-non-prototype/11 – StuR

+0

Что делать, если у вас есть 4 уровня наследования? вы объявите метод newnewnewInitModule? – mpm

+0

@mpm, вы правы, была ошибкой, я отредактировал это. – Lior

ответ

3

Если вы не используете прототип, методы переопределяются с каждым классом. То есть new Base; new Base; new Base создаст шесть функции во втором примере. Это занимает больше времени и пространства. Derived также создаст свои собственные функции.

Кроме того, вы не можете использовать прототип для изменения методов для каждого экземпляра «на лету» (или добавления новых методов), что может быть потенциально полезно - особенно для модулей.

Однако это не означает, что вы всегда должны использовать прототип для каждого метода. Каждая ситуация другая.

prototype также позволяет вызывать методы в другом контексте, не создавая экземпляр (как в случае Array.prototype.forEach.call для объекта, подобного массиву).

+0

спасибо! производительность, по-видимому, является основной проблемой. Но не могли бы вы уточнить: «Вы не можете использовать прототип для изменения методов для каждого экземпляра« на лету »? не знаю, я понимаю – Lior

+0

@Lior, я имею в виду, что если вы определите метод 'Base.init', вы не сможете переопределить его с помощью Base.prototype.init' (включая любые« его »). Он будет использовать один метод Base.init, который вы изначально определили, если вы явно не вызываете другой из цепи прототипа –

1

В основном это довольно просто, Object.create является частью ECMAScript 5, которая является совершенно новым. Прототип существует с самого начала javascript и поддерживается всеми браузерами.

До тех пор, пока вам нужна поддержка Internet Explorer 7 или 8, вы не должны полагаться на Create. Также см https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/create

(В статье также предлагает polyfill, который использует прототип ;-))

-2

Вам не нужно прототип (который IMHO является мошенником) для ОО.

Рассмотрим это для наследования:

function SubClass() 
{ 
    var object = {}; 
    object.publicVar = 2; 
    object.publicMethod = function SubClassPubMeth() 
     { 
     return this.publicVar + 2; 
     }; 
    object.poly = function SubClassPoly() 
     { 
     return 'SubClassPoly'; 
     }; 
    return object; 
} 

function Class() 
{ 
    var object = new SubClass(); 
    object.classPublicVar = 3; 
    object.classPublicMethod = 
     function ClassMethod() 
     { 
      return this.publicVar + this.classPublicVar; 
     }; 
    object.poly = function ClassPoly() 
     { 
     return 'ClassPoly'; 
     }; 
    return object; 
} 

Кажется, чтобы соответствовать всем требованиям для наследования.

Также рассмотреть это для сокрытия информации:

класса функций() { объекта переменных = {}; object.x = 3; var privateVar = 3; функция privateFunction (объект) { возвращение объект.x + privateVar; }

object.publicFunction = function() 
    { 
    var priv = privateFunction(this); 
    priv += privateVar; 
    privateVar = privateVar + 3; 
    return priv; 
    }; 
return object; 

}

кажется также сделать трюк для сокрытия информации (AKA инкапсуляция)

Нужно ли говорить больше.

+0

Если вас беспокоит производительность, вам понадобятся прототипы, когда вы подклассифицированы, или когда вы создаете новые экземпляры одного и того же объекта. – mpm

+0

То, что вы делаете с Javascript, не требует такой большой вычислительной мощности. Если вас это касается, вы пишете код, используя Java (например). –

Смежные вопросы