Как создать массив с особым прототипом?
Нужно создать массив со своим кастомным прототипом.
Если в браузере доступно свойство __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, время: 12:39. |