Ответ 1
Просто, чтобы быть ясным: JS не знает классов, просто объектов и пользовательских, самоопределяемых функций-конструкторов, но кроме того.
Чтобы ответить на ваш вопрос короче: да, есть несколько небольших и даже довольно больших различий между различными способами создания нового объекта, который вы публикуете здесь.
CoffeeScript:
Это на самом деле самый четкий и традиционный способ создания собственного конструктора, но он был "оптимизирован" в том смысле, что он был готов к настройке использования (необязательных) замыкающих переменных.
В основном, что делает этот код, используется IIFE, чтобы обернуть как определение конструктора, так и назначения метода proptotype в их собственной частной области, которая возвращает ссылку на новый конструктор. Это просто чистый, простой JS, ничем не отличающийся от того, что вы могли бы написать себе.
Нокаут:
Теперь это немного меня бросило, потому что для меня, по крайней мере, фрагмент, который вы предоставляете, выглядит либо как часть шаблона модуля, либо конструктор мощности. Но поскольку вы не используете strict mode
, опускание new
будет по-прежнему создавать опасные ситуации, а так как вся функция проходит через проблему создания нового экземпляра DifferentAnimal
, то только для того, чтобы затем построить второй объектный литерал, присваивая всем свойствам DifferentAnimal
этому второстепенному объекту, я бы сказал, что вам что-то не хватает. Потому что, правда, сказать, что здесь отсутствует последнее утверждение return {};
, вероятно, ничего не изменит. Плюс: как вы можете видеть, вы объявляете метод (move
) в том, что по сути является конструктором. Это означает, что каждому экземпляру присваивается свой собственный объект функции move
, а не получение его из прототипа.
Короче говоря, еще раз посмотрим, откуда вы взяли этот фрагмент, и дважды проверьте, является ли это полной версией, потому что, если это так, я могу видеть только аргументы против этого.
Использование переменной, определенной внутри конструктора, просто: замыкание, предположим, что ваши свойства имеют различное начальное состояние, определенное некоторыми аргументами, переданное этому конструктору:
function MyConstructor(param)
{
var paramInit = param/2;//or something
this.p = paramInit;//this property can change later on, so:
this.reInit = function()
{//this method HAS to be inside constructor, every instance needs its own method
this.p = paramInit;//var paramInit can't, it local to this scope
};
}
var foo = new MyConstructor(10);
console.log(foo.p);//5
foo.p = 'hi';
console.log(foo.p);//hi
foo.reInit();
console.log(foo.p);//5
console.log(foo.paramInit);//undefined, not available outside object: it a pseudo-private property
Это все, что есть, действительно. Когда вы видите ppl с помощью var that = this;
или что-то еще, что часто создает ссылку на основной объект, доступный где угодно, без необходимости иметь дело с головными болями this
(что делает this
ссылка? когда применяется к объекту, отличному от того, из которого он изначально предназначался? etcetera...)
Backbone:
Здесь мы имеем дело с другим случаем: расширение объектов (IE: использование методов, свойств существующего "класса" (конструктора) или конкретного экземпляра) - это не то же самое, что просто создать объект.
Как вам хорошо известно, объектам JS можно назначать новые свойства в любой момент времени. Эти свойства также могут быть удалены. Иногда свойства прототипа могут быть переопределены на самом экземпляре (маскирование прототипического поведения) и т.д. Итак, все зависит от того, что вы хотите, чтобы получившийся объект (вновь созданный объект, который расширяет данный экземпляр) выглядел так: хотите ли вы взять все свойства из экземпляра или вы хотите, чтобы оба объекта использовали один и тот же прототип где-то в очереди?
Обе эти вещи могут быть достигнуты с помощью простого JS, но они просто прикладывают немного больше усилий, чтобы написать себя. Однако, если вы пишете, например:
function Animal(name)
{
this.name = name;
}
Animal.prototype.eat= function()
{
console.log(this.name + ' is eating');
};
Это можно было бы считать эквивалентом написания:
var Animal = Object.extend({name:'',eat:function()
{
console.log(this.name + ' is eating');
}});
Гораздо короче, но отсутствует конструктор.
new
vs Object.create
Ну, это просто: Object.create
просто намного мощнее, чем new
: вы можете определить методы прототипа, свойства (в том числе погоду или нет, они перечислимы, могут быть записаны и т.д.) Прямо в то время, когда вам нужно создайте объект, вместо того, чтобы писать конструктор и прототип, или создать объектный литерал и обходиться со всеми этими строками Object.defineProperty
.
Недостатки: некоторые люди по-прежнему не используют ECMA5-совместимые браузеры (IE8 все еще не совсем мертв). По моему опыту: через некоторое время становится довольно сложно отлаживать значимые сценарии: хотя я предпочитаю использовать конструкторы власти больше, чем обычные конструкторы, я все еще определяю их на самой вершине моего script, с четкими, четкие и довольно описательные имена, тогда как объектно-литералы - это вещи, которые я просто создаю "на лету". Используя Object.create
, я заметил, что я склонен создавать объекты, которые на самом деле слишком сложны, чтобы квалифицировать как фактические литералы объектов, как если бы они были объектными литералами:
//fictional example, old:
var createSomething = (function()
{
var internalMethod = function()
{//method for new object
console.log(this.myProperty || '');
};
return function(basedOn)
{
var prop, returnVal= {};
returnVal.myProperty = new Date();
returnVal.getCreated = internalMethod;//<--shared by all instances, thx to closure
if (!basedOn || !(basedOn instanceof Object))
{//no argument, or argument is not an object:
return returnVal;
}
for (prop in basedOn)
{//extend instance, passed as argument
if (basedOn.hasOwnProperty(prop) && prop !== '_extends')
{
returnVal[prop] = basedOn[prop];
}
}
returnVal._extends = basedOn;//<-- ref as sort-of-prototype
return returnVal;
};
}());
Теперь это довольно многословно, но у меня есть базовый конструктор, и я могу использовать его для расширения существующего экземпляра. Может показаться, что менее просто написать:
var createSomething = Object.create(someObject, {getCreated:function()
{
console.log(this.myProperty);
},
myProperty:new Date()});
Но IMO, это усложняет вам отслеживание того, какой объект создается там (в основном потому, что Object.create
является выражением и не будет поднят.
Ах, да, это далеко не окончательный аргумент конечно: у обоих есть свои профи и con: я предпочитаю использовать модульные паттеры, блокировки и конструкторы власти, если вы этого не делаете, просто отлично.
Надеюсь, что это очистило вещь или 2 для вас.