Производительность: создание классов через __proto__
По производительности Object.create к сожалению не дает больших результатов (в особенности со вторым аргументом — дескрипторами). В отличии от использования __proto__ напрямую, который оказался даже быстрее связки функции–конструктора с оператором new — см. jsPerf. Отмечу также, что использование дескрипторов не особо удобно.
CloneJS nano
По вышеизложенным причинам, создадим функцию clone:
function clone(proto, properties){ properties.__proto__ = proto; return properties; }
Клонирование
В прототип-ориентированных системах предоставляется два метода создания нового объекта: клонирование существующего объекта, либо создание объекта «с нуля». Для создания объекта с нуля программисту предоставляются синтаксические средства добавления свойств и методов в объект. В дальнейшем, с получившегося объекта может быть получена полная копия — клон. В процессе клонирования копия наследует все характеристики своего прототипа, но с этого момента она становится самостоятельной и может быть изменена.
Функция clone()
, как следует из названия, создает клоны объектов. Клон — это lazy shallow copy, то есть это фактически не копия, а просто ссылка на объект, но, если добавить/заменить какие-либо его свойства, это не отразится на объекте-родителе (прототипе).
Все объекты в JavaScript являются клонами Object.prototype (за исключением его самого и объектов, созданных с помощью Object.create(null)
).
/// "Класс" var duck$ = { name: "Unnamed", quack: function(){ console.log( this.name +" Duck: Quack-quack!"); } }; /// Наследование var talkingDuck$ = clone( duck$, { quack: function(){ duck$.quack.call(this); console.log("My name is "+ this.name +"!"); } }); /// Инстанцирование var donald = clone( talkingDuck$, {name: "Donald"});
Как альтернативу, можно использовать объектно-ориентированный вариант:
/// object$ – прототип всех наших объектов var object$ = { clone: function(properties){ properties.__proto__ = this; return properties; }; /// "Класс" var duck$ = object$.clone({ name: "Unnamed", quack: function(){ console.log( this.name +" Duck: Quack-quack!"); } }; /// Наследование var talkingDuck$ = duck$.clone({ quack: function(){ duck$.quack.call(this); console.log("My name is "+ this.name +"!"); } }); /// Инстанцирование var donald = talkingDuck$.clone({name: "Donald"});
Совместимость
Справедливо заметить, что функция clone на самом деле не создает никаких объектов, а просто изменяет объектy properties его прототип. Это можно легко исправить:
function clone(proto, properties){ var newObj = {__proto__: proto}; for(var key in properties) newObj[key] = properties[key]; return newObj; }
Но тогда мы потеряем в производительности. Лучше ввести правило:
Использование второго аргумента после клонирования нежелательно, и возможно при использовании исключительно его собственных свойств.
Это правило также позволит обеспечить совместимость с Internet Explorer 6–10 и ECMA Script 3:
function clone(/** Object */proto, /** ObjLiteral= */ownProperties){ function Clone(ownProperties){ for(var key in ownProperties) this[key] = ownProperties[key]; }; Clone.prototype = proto; return new Clone(ownProperties); }
Вот примерно так был создан фреймворк clone.js.
ссылка на оригинал статьи http://habrahabr.ru/post/192806/
Добавить комментарий