2010-09-16 3 views
6

Существует, по-видимому, много разных способов сделать OO в JavaScript.Javascript OO синтаксис

мне нравится:

function ClassA(){}; 
ClassA.prototype={ 
    someFunc:function(a,b,c){}, 
    otherFunc:function(){} 
} 
var c=new ClassA(); 

и никогда не использовали возможности сверх того, что это обеспечивает (несмотря на то, опытный OOer). Я подозреваю, что это старомодно, потому что каждый раз я вижу новые варианты с блестками, и это заставляет меня задаться вопросом, выбираю ли я наилучший подход. Например, вы можете делать магию в методе конструктора для создания частных переменных и методов доступа, что я полагал (до относительно недавнего времени) быть невозможным. Как насчет подкласса? Я бы не знал, как это сделать, но к настоящему времени у него должна быть какая-то общая картина.

Как вы это делаете и почему?

ответ

6
function foo() { 
    var bar = function() { console.log("i'm a private method"); return 1; }; 
    var iAmAPrivateVariable = 1; 

    return { 
    publicMethod: function() { alert(iAmAPrivateVariable); }, 
    publicVariable: bar() 
    } 
} 

//usage 
var thing = foo() 

Это известно как функциональный appoach, так как вы на самом деле используя затворов для инкапсуляции (что это единственный способ сделать это в JavaScript).

В общем, вы не должны делать OO в javascript, это не тот классный язык для него по многим причинам. Подумайте, схема с короткоугольными скобками и полуколонами, и вы начнете писать язык, как профессионалы. При этом, когда-то OO лучше подходит. В тех случаях, выше, как правило, лучше всего

EDIT: принести наследство в смесь

function parent() { 
    return { parentVariable: 2 }; 
} 

function foo() { 
    var bar = function() { console.log("i'm a private method"); return 1; }; 
    var iAmAPrivateVariable = 1; 

    me = parent(); 
    me.publicMethod = function() { alert(iAmAPrivateVariable); }; 
    me.publicVariable = bar(); 

    return me; 
} 

Это делает вещи немного более complected, но достигает желаемого конечного результата в то же время принимая функциональный подход к концепциям ОО (в этом случае, используя функции декоратора вместо реального наследования). Что мне нравится во всем подходе, так это то, что мы по-прежнему рассматриваем объекты так, как они предназначены, чтобы быть на этом языке - мешок имущества, на который вы можете прикрепить материал по своему усмотрению.

EDIT2:

Просто хотел, чтобы дать кредит, где кредит должен, такой подход очень небольшое упрощение к тому, что Дуг Крокфорд предлагает в Javascript: The Good Parts. Если вы хотите перенести свои навыки js на следующий уровень, я бы очень хотел начать там. Я не думаю, что я так много узнал из такой маленькой книги.

Другое примечание: это дико отличается от того, что вы увидите большую часть времени на большинстве заданий, на которых вы когда-либо будете работать, и часто очень сложно объяснить a), что происходит, и b) почему это это хорошая идея для коллег.

+0

Мне это нравится. Может ли он быть согнутым для обеспечения наследования без использования прототипа? – spender

+0

'bar' станет свойством глобального объекта (' window.bar'), поскольку он не объявлен с помощью оператора 'var' в области функции' foo'. Также в ECMAScript 5 Strict Mode это даст вам «ReferenceError», поэтому всегда используйте 'var' для * declare * переменную;) – CMS

+1

@CMS wow ..., которая была смущающей ... –

5

Simple JavaScript Inheritance

Поскольку Резиг так сказал.

+1

Да, но он также популяризировал $ как переменное имя ... непростительно. – spender

+3

нет, когда $ в значительной степени рассматривается как расширение языка –

2

«подклассы» в JavaScript обычно относятся к прототипу на основе наследования, который в основном следует этому образцу:

function Superclass() { } 
Superclass.prototype.someFunc = function() { }; 

function Subclass() { } 
Subclass.prototype = new Superclass(); 
Subclass.prototype.anotherFunc = function() { }; 

var obj = new Subclass(); 

Это строит «прототип цепь» от obj -> Subclass.prototype -> Superclass.prototype -> Object.prototype.

Практически каждая библиотека ООП для JavaScript опирается на эту технику, предоставляя функции, абстрагирующие большую часть прототипа «магия».

+0

это не очень хорошая идея; он полагается на вызов родительского конструктора для получения прототипа для дочернего конструктора. Лучше сделать что-то подобное (см. Мой ответ): 'function C() {}; function clone (obj) {C.prototype = obj, return new C}; Subclass.prototype = clone (Superclass.prototype); '... таким образом родительский ctor не вызывается, что может создать нежелательные побочные эффекты. –

1

Объекты в JavaScript отличаются от почти всех других громких языков. Вместо на основе классов (например, в Java, C++, PHP и т. Д.), Они основаны на прототипе. Таким образом, основная парадигма объектно-ориентированного программирования должна быть значительно изменена. Люди, которые не могут или не хотят переосмыслить это и настаивают на использовании основанного на классе мышления, должны строить логику на основе классов в JavaScript или использовать код у кого-то еще, кто его уже создал.

+0

полностью согласен.фальсифицирующие классы в JavaScript пытаются обучить звуковой сигнал java во что-то, что только прикрывает его поверхностное сходство. –

0

Я хотел бы сделать что-то вроде

// namespace "My" 
var My = new function { 

    // private methods 
    /** 
    * Create a unique empty function. 
    * @return {Function} function(){} 
    */ 
    function createFn() {return function(){}} 

    /** A reusable empty function. */ 
    function emptyFn() {} 

    /** 
    * Clone an object 
    * @param {Object} obj  Object to clone 
    * @return {Object}   Cloned object 
    */ 
    function clone (obj) { emptyFn.prototype=obj; return new emptyFn() } 

    // public methods 
    /** 
    * Merge two objects 
    * @param {Object} dst  Destination object 
    * @param {Object} src  Source object 
    * @param {Object} [options] Optional settings 
    * @return {Object}   Destination object 
    */ 
    this.merge = function (dst, src, options) { 
    if (!options) options={}; 
    for (var p in src) if (src.hasOwnProperty(p)) { 
     var isDef=dst.hasOwnProperty(p); 
     if ((options.noPrivate && p.charAt(0)=='_') || 
      (options.soft && isDef) || 
      (options.update && !isDef)) continue; 
     dst[p]=src[p]; 
    } 
    return dst; 
    } 

    /** 
    * Extend a constructor with a subtype 
    * @param {Function} superCtor  Constructor of supertype 
    * @param {Function} subCtor  Constructor of subtype 
    * @param {Object} [options]  Optional settings 
    * @return {Function}    Constructor of subtype 
    */ 
    this.extend = function (superCtor, subCtor, options) { 
    if (!subCtor) subCtor=createFn(); 
    if (!options) options={}; 
    if (!options.noStatic) this.merge(subCtor, superCtor, options); 
    var oldProto=subCtor.prototype; 
    subCtor.prototype=clone(superCtor.prototype); 
    this.merge(subCtor.prototype, oldProto); 
    if (!options.noCtor) subCtor.prototype.constructor=subCtor; 
    return subCtor; 
    } 

} 

А потом что-то вроде ...

// namespace "My.CoolApp" 
My.CoolApp = new function(){ 

    // My.CoolApp.ClassA 
    this.ClassA = new function(){ 

    // ClassA private static 
    var count=0; 

    // ClassA constructor 
    function ClassA (arg1) { 
     count++; 
     this.someParam=arg1; 
    } 

    // ClassA public static 
    My.merge(ClassA, { 
     create: function (arg1) { 
     return new ClassA(arg1); 
     } 
    } 

    // ClassA public 
    My.merge(ClassA.prototype, { 
     doStuff : function (arg1) { 
     alert('Doing stuff with ' + arg1); 
     }, 
     doOtherStuff : function (arg1) { 
     alert('Doing other stuff with ' + arg1); 
     } 
    } 

    return ClassA; 
    } 

    // My.CoolApp.ClassB 
    this.ClassB = new function(){ 

    My.extend(My.CoolApp.ClassA, ClassB); 
    // ClassB constructor 
    function ClassB() { 
     ClassA.apply(this, arguments); 
    } 

    return ClassB; 
    } 

} 

... функция clone является ключом к наследованию. Короче говоря:

  • Клонировать объект, создавая его прототипом функции throwaway и вызывая функцию с помощью «нового».
  • Клонировать прототип родительского конструктора и установить его в качестве прототипа дочернего класса.
0

OOP в Javascript для Canvas

Проверьте, насколько полезно ООП в JS может быть в другой ситуации ... Это позволяет рисовать квадраты и круги as objects, так что вы можете вернуться назад и перебираем или манипулировать их, как вам нравится.

function Shape(x,y,color){ 
    this.x = x 
    this.y = y 
    this.color = color 
} 

function Square(height,width,color){ 
    Shape.call(this, event.x, event.y, color) 
    this.height = height 
    this.width = width 
    this.x -= canvas.offsetLeft + (this.height/2) 
    this.y -= canvas.offsetTop + (this.width/2) 
} 

Square.prototype = new Shape(); 
Square.prototype.draw = function(color){ 
    ctx.fillStyle = color 
    ctx.fillRect(this.x,this.y,this.height,this.width) 
} 

function Circle(color, width){ 
    Shape.call(this) 
    this.x = event.x -60 
    this.y = event.y -60 
    this.width = width 
} 

Circle.prototype = new Shape(); 
Circle.prototype.draw = function(color){ 
    ctx.beginPath() 
    ctx.arc(this.x,this.y,this.width,0,2*Math.PI, false); 
    ctx.fillStyle = color 
    ctx.fill() 
}