2010-09-28 2 views
24

Долгое время я бросал идею о том, чтобы сделать JavaScript более ориентированным на объект. Я также рассмотрел несколько различных вариантов этого, но я просто не могу решить, нужно это или нет.Безопасна ли реализация внедрения JavaScript для разработки OO JavaScript Res?

То, что я пытаюсь ответить на следующие вопросы

  • Является John Resig's простая структура наследования безопасно использовать для производства?
  • Есть ли способ узнать, насколько хорошо он был протестирован?
  • Кроме того, Joose какие у меня варианты для этой цели? Мне нужен тот, который прост в использовании, быстро и прочен. Он также должен быть совместим с jQuery.
+22

Я видел Javascript «в производство ", из-за чего кричат ​​кошки-ангелы из детского котенка, поэтому вам действительно нужно решить, какое влияние это повлияет на тестирование вашего устройства/страницы. Это такая простая вещь, что трудно представить, что это вызывает серьезные проблемы. – Pointy

+0

+1 Пояс. Я только что критиковал ниже, но на самом деле 99% сайтов имеют более сомнительный код, чем тот, который у них уже есть ... – bobince

+1

jQuery для начала ... –

ответ

19

Huh. Мне кажется, что это намного сложнее, чем нужно.

На самом деле, более внимательно, я действительно делаю исключение из того, что он делает, предоставляя this._super(), пока в методе, чтобы вызвать метод суперкласса.

код вводит зависимость от typeof==='function' (ненадежной для некоторых объектов), Function#toString (Argh, разложение функции является также ненадежным), и решить, нужно ли завернуть на основе уже ли вы использовали последовательность байт _super в теле функции (даже если вы использовали его только в строке, и если вы попробуете, например, this['_'+'super'], это не удастся).

И если вы сохраняете свойства объектов-объектов (например, MyClass.myFunction.SOME_PRIVATE_CONSTANT, которые вы можете сделать, чтобы сохранить пространства имен чистыми), упаковка не позволит вам получить эти свойства. И если исключение выбрано в методе и поймано в другом методе того же объекта, _super в конечном итоге укажет на неправильную вещь.

Все это только для того, чтобы упростить вызов метода супер-класса. Но я не думаю, что это особенно сложно сделать в JS. Это слишком умно для собственного блага и в процессе делает все менее надежным. (О, и arguments.callee недействителен в строгом режиме, хотя это не его вина, так как это произошло после того, как он разместил его.)

Вот что я использую для занятий в данный момент. Я не утверждаю, что это «лучшая» система JS-класса, потому что есть загружает разных способов сделать это и кучу различных функций, которые вы можете добавить или не добавить. Но он очень легкий и нацелен на то, чтобы быть «JavaScriptic», если это слово. (Это не так.)

Function.prototype.makeSubclass= function() { 
    function Class() { 
     if (!(this instanceof Class)) 
      throw 'Constructor function requires new operator'; 
     if ('_init' in this) 
      this._init.apply(this, arguments); 
    } 
    if (this!==Object) { 
     Function.prototype.makeSubclass.nonconstructor.prototype= this.prototype; 
     Class.prototype= new Function.prototype.makeSubclass.nonconstructor(); 
    } 
    return Class; 
}; 
Function.prototype.makeSubclass.nonconstructor= function() {}; 

Он обеспечивает:

  1. защита от случайного отсутствует new. Альтернативой является тихое перенаправление X() на new X(), так что отсутствует new работ. Это лучший результат; Я пошел на явную ошибку, так что вы не привыкли писать без new и вызывают проблемы с другими объектами, не определенными так. В любом случае лучше, чем неприемлемый JS-дефолт, позволяющий this. свойствам выпадать на window и таинственным образом идет не так позже.

  2. метод наследуемого _init, поэтому вам не нужно писать конструктор-функцию, которая ничего не делает, кроме вызова функции конструктора суперкласса.

и все действительно все.

Вот как вы можете использовать его для реализации примера Resig в:

var Person= Object.makeSubclass(); 
Person.prototype._init= function(isDancing) { 
    this.dancing= isDancing; 
}; 
Person.prototype.dance= function() { 
    return this.dancing; 
}; 

var Ninja = Person.makeSubclass(); 
Ninja.prototype._init= function() { 
    Person.prototype._init.call(this, false); 
}; 
Ninja.prototype.swingSword= function() { 
    return true; 
}; 

var p= new Person(true); 
p.dance(); // => true 

var n = new Ninja(); 
n.dance(); // => false 
n.swingSword(); // => true 

// Should all be true 
p instanceof Person && 
n instanceof Ninja && n instanceof Person 

Superclass-колл делается специально именования метод, который вы хотите и call ИНГ его, немного как в Python. Вы могли бы добавить элемент _super к функции конструктора, если вы хотите избежать именования Person (так что вы скажете Ninja._super.prototype._init.call или, возможно, Ninja._base._init.call).

+0

'typeof' только ненадежна для функций, если вы имеете дело с объектами хоста, и вы не захотите подклассифицировать один из них. Или, по крайней мере, вы не должны этого хотеть. Я, конечно, согласен с тем, что код Реджига чересчур сложный и хрупкий, и ему просто не нужно. –

+0

@Tim: Да, вы не можете прототипировать объект-хост, но то, что делает этот тест функции, это проверка каждого из членов, а не объекта суперкласса. Таким образом, объект-хозяин, являющийся членом вашего класса, может вызвать проблемы. (например, в Firefox 3.0 регулярное выражение появляется как функция, поэтому обертка в Class.extend может помещать элементы регулярного выражения, пытаясь обернуть их как функции). – bobince

+0

О, я всегда забываю о вещи регулярного выражения. И да, вы правы; Я не читал код мистера Ресига так тщательно, как мог, и теперь он выглядит еще более хрупким, чем раньше. Хорошее использование слова «nadger», кстати. Он недоиспользуется на SO. –

5

JavaScript - это прототип, основанный не на основе класса. Моя рекомендация заключается не в том, чтобы бороться с ней, а в том, что касается подтипов JS:

MyDerivedObj.prototype = new MySuperObj(); 
MyDerivedObj.prototype.constructor = MyDerivedObj; 
+3

Проблема в том, что вызов 'new MySuperObj()' вызывает инициализационный код в конструктор для 'MySuperObj()', как если бы вы фактически создавали экземпляр 'MySuperObj'. Как только у вас есть что-то нетривиальное в функции конструктора, это не сработает, так как вам нужно вызывать инициализирующий код 'MySuperObj' при построении экземпляра' MyDerivedObj', а не во время определения. – bobince

+1

Я согласен с тем, что вы можете захотеть отменить свой код инициализации отдельным методом и вызвать его из конструктора MyDerivedObj ... еще лучше подумайте об использовании Injection Dependency. Я обнаружил, что это значительно сокращает код конструктора. –

5

Посмотрите, как далеко вы можете обойтись без использования наследования вообще. Относитесь к нему как к взлому производительности (для неохотно применяемого там, где это действительно необходимо), а не к принципу дизайна.

В очень динамичном языке, таком как JS, редко бывает необходимо знать, является ли объект Person. Вам просто нужно знать, имеет ли он свойствоfirstName или метод eatFood. Вы не часто должны знать, является ли объект массивом; если он имеет свойство длины и некоторые другие свойства, названные после целых чисел, это обычно достаточно хорошо (например, объект Arguments). «Если он ходит, как утка и шарлатанцы, как утка, это утка».

// give back a duck 
return { 
    walk: function() { ... }, 
    quack: function() { ... } 
}; 

Да, если вы делаете очень большое количество мелких объектов, каждый с десятками способов, а затем всеми средствами присваивают эти методы к прототипу, чтобы избежать накладных расходов на создание десятков слотов в каждом конкретном случае. Но относитесь к этому как к способу сокращения накладных расходов памяти - просто оптимизации. И сделайте своим пользователям пользу, скрывая ваше использование new за какой-то заводской функцией, поэтому им даже не нужно знать, как создается объект. Им просто нужно знать, что у него есть метод foo или имущество bar.

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

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