Как создать массив с особым прототипом?
Нужно создать массив со своим кастомным прототипом.
Если в браузере доступно свойство __proto__, то можно сделать так: function MyArray () { var instance = [] instance.__proto__ = arguments.callee.prototype return instance } MyArray.prototype.myFunction = function () {} var myArray = new MyArray() alert( typeof myArray.myFunction ) А как сделать такое же без __proto__ ? |
Мб так:
function MyArray () {} MyArray.prototype = Array.prototype; MyArray.prototype.myFunction = function () { return this[0] + this[1] } var myArray = new MyArray() alert([ typeof myArray.myFunction, myArray instanceof Array, typeof myArray ]) myArray.push(5) myArray.push(3) alert([ myArray.length, myArray.myFunction() ]) ...но зачем? |
Aetae
function MyArray () {} MyArray.prototype = Array.prototype; MyArray.prototype.myFunction = function () { return this[0] + this[1] } var myArray = new MyArray() // во-первых мы изменили прототип Array, но это решаемо alert( typeof [].myFunction ) // во-вторых, мы получили таки объект, а не массив alert( Array.isArray(myArray) ) alert( Object.prototype.toString.call(myArray) ) А должно быть так: function MyArray () { var instance = [] instance.__proto__ = arguments.callee.prototype return instance } MyArray.prototype.myFunction = function () {} var myArray = new MyArray() alert( typeof [].myFunction ) alert( Array.isArray(myArray) ) alert( Object.prototype.toString.call(myArray) ) Зачем это? Пытаюсь заставить библиотеку Zepto работать с IE. А там как раз использется массив, а не объект. Да и вообще интересно - возможно ли так сделать без __proto__ |
var MyArray = function() { var _myPrototype = { joinReverse : function(s) { return this.slice(0).reverse().join(s); } } return function() { var ret = Array.apply( null, arguments ); for( var i in _myPrototype ) // if( typeof _myPrototype[i] == "function" ) ret[i] = _myPrototype[i]; return ret; } }(); var test = MyArray( 1, "bb", 333 ); alert( test.joinReverse( " - " ) ); |
Цитата:
Цитата:
Цитата:
Ну или вручную навешивать на каждый создаваемый массив методы, что, естесно, скажется на производительности и будет вылезать в for in. ...upd: пока писал - последний вариант реализовал rgl.) |
function MEGAArray (){}; MEGAArray.prototype = new Array; MEGAArray.prototype.godOfJavascript = function(){}; Прототипное наследование не, не слышали? |
Цитата:
function MEGAArray (){}; MEGAArray.prototype = new Array; var test = new MEGAArray(); test[0] = "a"; test[1] = "bb"; test[2] = "ccc"; alert( test.length ); |
Цитата:
|
rgl, твой вариант некудышный, ибо методов много, а конструктор вызывается часто. Так что думаю потребление ресурсов возрастет ощутимо. Кроме того, прототипа то и нет получается ). А нужно чтобы был прототип. И добавляя метод в прототип мы автоматом получаем его у уже созданных экземпляров.
megaupload, этот вариант я пробовал. В консоли объект действительно выглядит как [массив], вот только Array.isArray не обманешь. Ну и toString также выдает [object Object] А то, что length не обновляется - это не беда. Работа с коллекцией всеравно идет через методы, а не напрямую. Цитата:
В девятке и уж тем более в десятке есть все, что нужно. Так что отсутствие поддержки IE9-10 - это всего лишь наследие zepto. А корень проблемы в использовании __proto__ . Кстати, кто-то говорил что это свойство добавили в стандарт, это так? Если заглянуть сюда https://github.com/madrobby/zepto/issues/ то видно, что не я один хочу поддержки IE. Цитата:
|
function MyArray() {} MyArray.prototype = []; MyArray.prototype.toString = function(){alert('ну вы нубы')}; var q = new MyArray(); q.push(1); q.push(1); alert(q.length); q+""; |
придётся заставить себя не использовать сеттеры длины массива, а использовать встроенные методы
function ArrayLike () { /* NULL */} // Object.create легко эмулируется //ArrayLike.prototype = Object.create(Array.prototype); // вот так, например var noop = function () {}; noop.prototype = Array.prototype; ArrayLike.prototype = new noop(); ArrayLike.prototype.constructor = ArrayLike; // расширим ArrayLike.prototype.TEST = "Hello World!"; var a = new ArrayLike(); // опробуем новый супер-массив a.push("a"); alert (a.length + '\n' + a); a.push("b"); a.push("c"); alert (a.length + '\n' + a); // повыводим типы alert( "type: " + typeof(a) ); alert( "class: " + Object.prototype.toString.call(a) ); // и проверим, не тронули ли мы пртотип массива alert( "a.test : " + a.TEST ); alert( "[].test : " + ['нету тут такого'].TEST); // и тут тоже alert( "new Array().test : " + new Array().TEST); |
melky,
и зачем в прототип делать Object.create а не просто создать массив? хоть одну причину назови |
Цитата:
|
ты не ответил на мой вопрос)
|
function MyArray() {} MyArray.prototype = []; MyArray.prototype.toString = function(){alert('ну вы нубы')}; var q = new MyArray(); alert(Object.prototype.toString.call(q)); alert('— мы нубы? \n— ' + Array.isArray(q)); q.push(1); q.push(1); alert( 'concat:' + [].concat(q) ); alert( 'а должно быть: ' + [].concat([1,1]) ); |
melky, ключевые моменты:
alert( Array.isArray(myArray) ) // true alert( Object.prototype.toString.call(myArray) ) // [object Array] myArray[0] = 'x' // myArray.length // 1 myArray[1] = 'y', [].concat(myArray) // ['x','y'] |
тогда удачи :) не понимаю, зачем это нужно
|
|
Цитата:
Я так и предполагал что то, что я спросил - невозможно. Хотел удостовериться. Придется переделывать на объектах. В принципе коллекции и должны представлять из себя объекты, а не массивы. Так что это изначально ошибка архитектуры. Проблема в том, что потеряется обратная совместимость. Всем спасибо. |
а я вот так и не понял чо ему надо...
|
Цитата:
Цитата:
var test = {}; test[0] = "a"; test[1] = "bb"; test[2] = "ccc"; test.length = 2; alert( Array.prototype.slice.call( test, 0 ) ); |
Если уж извращаться - то можно эмулировать геттером, они вроде в ие 9+ поддерживаются уже. Примерно так, если не думать об оптимизации):
var test = { get length(){ var j = 0; for(var i in this)if(!isNaN(i) && i > j) j = +i ; return j+1 } }; test[0] = "a"; test[1] = "bb"; test[25] = "ccc"; alert(test.length) alert( Array.prototype.slice.call( test, 0 ) ); |
Aetae,
Только функция должна быть чуть посложнее - нужно отсекать дробные числа, слишком большие числа, и много чего еще: var test = { get length(){ var j = 0; for(var i in this)if(!isNaN(i) && i > j) j = +i ; return j+1 } }; test[0] = "a"; test[1] = "bb"; test[1e100] = "ccc"; var test2 = []; test2[0] = "a"; test2[1] = "bb"; test2[1e100] = "ccc"; alert( test.length + " | " + test2.length ); |
недавно плагин жукверевский к Zepto подключал. Ой намучался :)
по теме: я вижу только такое решение var box = { method: function() { alert( 1 ) } }; var arr = []; arr.method = box.method; arr.method(); В данном случае просто устанавливаются ссылки на функцию. Т.е. функция не создается заново каждый раз. p.s.: тред особо не читал |
Цитата:
могу еще вариант предложить с аппедиксом :D var arr = []; arr.some = {}; // тут твой мега объект, в нем ссылка на родителя (arr) но это все через ж*пу и проще сделать нормальный объект |
nerv_, видимо больше ничего не остается. Тут чел то же самое предлагает: https://github.com/madrobby/zepto/pu...mment-15571557
Цитата:
|
Цитата:
<script> $el = $('.el'); </script> <script src="plugin.js"></script> <script> $el.plugin() // без прототипа - беда! </script> |
Цитата:
я не понял зачем тебе тема с прототипом, т.к. плагины для зепто пишутся также как и для жуквери: $.fn.some = function() { почему намучался. зепто не полностью совместим с жуквери. В частности, когда я подключал плагин-шаблонизатор к зепто, мне пришлось лезть в код этого плагина - раз, два - дописывать для зепто и подключать плагин, эмулирующий метод жуквери, кот. нет в зепто |
Нужно пофиксить коллекции zepto и дописать $.prototype = $.fn. Тогда останутся только проблемы отсутствия методов, которые легко решить и проблема расширенных селекторов, от которых народ нужно отучать.
Хотя есть и другие проблемы.. Тот же data(), который полноценен только через модуль. Есть и другие проблемы.. Тут циклическая зависимость - зепто не используют в качестве замены jQuery => его особенности не принимают во внимание => зепто не используют... |
Цитата:
Цитата:
Цитата:
Цитата:
Цитата:
|
А че из ифрейма достать другой конструктор не вариант?
(function () { var iFrame = document.createElement("iframe"), iFrameDoc; document.body.appendChild(iFrame); iFrameDoc = iFrame.contentDocument || iFrame.contentWindow.document; iFrameDoc.open(); iFrameDoc.write('<script>window.Array = Array</scr' + 'ipt>'); iFrameDoc.close(); window.$Array = (iFrame.contentWindow || iFrameDoc.defaultView).Array; }()); $Array.prototype.test = function () {}; var array = [], $array = new $Array(); alert([ "test" in array, "test" in $array, Array.isArray ? Array.isArray($array) : "", Object.prototype.toString.call($array), new $Array(1, 2, 3).concat(4) ]); |
Цитата:
Но для zepto type = 'array'. Проверка не проходит. И это кривизна zepto. Цитата:
Опять же, для zepto это не сработает. |
Цитата:
Кстати по поводу больших чисел - просто наш псеводомассив круче нативного. )) Цитата:
|
Цитата:
$.zepto.isZ( some ); Цитата:
var x = $( 'div' ); alert( $.type( x ) == 'array' ); // true alert( $.type( x ) === 'array' ); // и так тоже true |
Octane, блин, круто! Это действительно делает то, что мне нужно. Но это конечно очень грязный хак. Я не уверен что его можно использовать.
А есть еще подобные вариации для получения другого Array ? Цитата:
Цитата:
Цитата:
В плагинах бывает проверка через $.type и поведение jquery и zepto тут будет разным. |
могу повторить свою точку зрения: если ты хочешь подключать жуквери плагины к зепто, то вряд ли обойдешься вышеперечисленным. Все равно придется лезть в код.
Цитата:
|
danik.js,
это еще чо , мы тогда пытались функции с другим прототипом получать вот это было весело) |
Цитата:
|
Цитата:
Могу еще пример привести: когда пытался подключить жуквери плагин к зепто, оказалось, что в зепто нет метода pushStack. |
Цитата:
Дописать $.prototype = перед $.fn - это всего 12 символов Ну с коллекциями будет чуть сложнее, но правок будет не так уж и много. На уровне ядра больше ничего править то и не нужно (наверное). С чего ты взял что после этих правок zepto станет jquery? Это не кучи говна ради совместимости с IE6, не миллионы оберток, исправляющие недочеты быдлокодеров, css-анимация никуда не денется. Selector engine не добавится. В общем я знаю две вещи: 1) нужно по возможности использовать Zepto. Ибо работает быстрее, грузится быстрее, и не содержит тонны мертвого кода. А ишак( IE8- ) пускай хавает jQuery. 2) при желании можно писать плагины, совместимые как с jQuery, так и с Zepto. И это не так уж и сложно. |
Часовой пояс GMT +3, время: 08:32. |