Я создаю небольшой плагин кода, который позволяет вам делать некоторые вещи с массивами. Я не хочу добавлять функции к объекту массива, используя конструкцию прототипа, я хочу, чтобы люди могли делать что-то вроде:
arrayFunction( [1, 2, 3] ).someSpecialArrayFunction();
Таким образом, оставляя обычный объект массива неизменным. Поэтому я придумал следующую конструкцию (вдохновленную исходным кодом jQuery):
var arrayFunction = window.arrayFunction = function(array) {
return new arrayFunction.fn.init(array);
}
arrayFunction.fn = arrayFunction.prototype = {
init: function(array){
this.a = array;
//should I return something here?
},
someSpecialArrayFunction: function(){
//Super cool custom stuff here.
}
}
Однако это не работает (очевидно). Что должно произойти в функции init ()?
Ошибка сейчас в том, что когда я пытаюсь:
arrayFunction(array).someSpecialArrayFunction();
там написано, что someSpecialArrayFunction () не является функцией?
Как это сделать?
редактировать
Да, это действительно упрощенный пример. На самом деле методов гораздо больше.
Кроме того, я просто подумал о том, как было бы здорово, если бы он также поддерживал ченинг, как бы вы это сделали?
В Javascript все функции являются объектами - вы фактически объявляете объекты с помощью ключевого слова function, поэтому jQuery $ является одновременно объектом и функцией, возвращающей экземпляры этого объекта. К этому нужно привыкнуть ...
Вы ищете здесь способ сделать свой пример Работа - или общий шаблон для добавления методов к объекту оболочки, добавляя их к прототипу оболочки, например чтобы вы могли управлять большими коллекциями методов расширения?



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Я не уверен, что это лучший синтаксис для получения того, что вы хотите, но я полагаю, что это урезанный пример ... В любом случае, вот быстрый способ заставить его работать
var arrayFunction = window.arrayFunction = function(array) {
return new arrayFunction.fn.init(array);
}
arrayFunction.fn = arrayFunction.prototype = {
init: function(array){
var a = array;
return {
someSpecialArrayFunction: function(){
alert (a.join(' - ') ); //Super cool custom stuff here.
}
};
},
}
arrayFunction( [1, 2, 3] ).someSpecialArrayFunction();
Или просто:
var arrayFunction = function(array) {
var someSpecialArrayFunction = function() {
// do something with array
};
return {
someSpecialArrayFunction: someSpecialArrayFunction
}
};
arrayFunction( [1, 2, 3] ).someSpecialArrayFunction();
Хотя будьте осторожны с этим, если вы получите слишком много методов, вероятно, лучше использовать прототип.
Вам следует откатить редактирование: это не сработает! Переменная массива в вашем закрытии всегда будет привязана к массиву, переданному в качестве аргумента для первого вызова myArrayFunction () ...
отвечатьSktrdie выглядит неплохо.
Еще одна вещь, которую следует учитывать, - это использовать модель наилегчайшего веса вместо возврата нового экземпляра объекта при каждом вызове вашей оболочки. Это делает функция ExtJS Ext.fly; он возвращает глобально разделяемый экземпляр.
Попробуйте что-то вроде этого:
var mathWrapper = function(array) {
return {
mean : function(){
if (array.length == 0) return(0);
var total = 0;
for (var i = 0; i < array.length; i++) total += array[i];
return(total / array.length);
},
};
}
Вызов его через что-то вроде
document.write(mathWrapper([1,2,3,4,5,6]).mean());
должен возвращать среднее значение элементов массива.
Это неэффективно с точки зрения памяти - используйте объект-оболочку и вместо этого добавьте методы в его прототип ...
@Christoph - а ... внезапно множество вещей, которые меня сбивали с толку, обретают смысл! Спасибо.
Если вы не хотите менять Array.prototype, единственное реально возможное решение - добавить методы к конкретному объекту массива:
function doSomething() {}
function doOther() {}
function wrap(array) {
array.doSomething = doSomething;
array.doOther = doOther;
return array;
}
Обратите внимание, что я не определяю doSomething() и doOther() в wrap() - в противном случае мы бы создавали новые объекты функций при каждом вызове, что крайне неэффективно.
Более сложный вариант будет следующим:
function doSomething() {}
function doOther() {}
function wrap(array) {
if (this instanceof arguments.callee) {
this.doSomething = doSomething;
this.doOther = doOther;
}
else {
arguments.callee.prototype = array;
return new arguments.callee;
}
}
Здесь мы создаем новый объект-оболочку (и не добавляем свойства в сам массив). Объект-оболочка по-прежнему будет иметь доступ ко всем свойствам массива. Однако есть небольшая загвоздка:
var foo = wrap([1,2,3]);
document.writeln(foo.length); // writes 3
foo.push(4);
document.writeln(foo.length); // writes 4 in FF, 3 in IE
foo[4] = 5;
foo[5] = 6;
document.writeln(foo.length); // still writes 4?!
Использование foo[4] = приведет к доступу к нашему объекту-оболочке, и свойства 4 и 5 будут установлены там, а не в массиве, поэтому его свойство длины не будет обновлено. В IE вызов push() уже не сможет правильно обновить массив ...
Если вашему объекту-оболочке не нужно «перенаправлять» вызовы объекта массива, существуют другие решения, использующие замыкания - первый пример sktrdie является одним из них. Я бы возражал против них, потому что они также будут создавать новые объекты функций при каждом вызове. Что бы я сделал:
function wrap(array) {
if (this instanceof arguments.callee)
this.array = array;
else return new arguments.callee(array);
}
wrap.prototype.doSomething = function() {};
wrap.prototype.doOther = function() {};
Здесь вы можете получить доступ к массиву в doSomething() и doOther() через this.array.
Просто расширьте объект Array и добавьте к своему объекту свои причудливые методы. Затем вы можете создать функцию моста, которая принимает массив в качестве аргумента и возвращает вашу версию массива. Этот метод намного проще и полезнее.
$ For jquery на самом деле является объектом.