Можно ли переопределить массив или объект Javascript для возможности вызова?

#javascript #arrays #monkeypatching

#javascript #массивы #monkeypatching

Вопрос:

Я хочу выяснить, можно ли заменить Array[] и Object[] на Array() и Object() . Можно ли вставить прототип функции в цепочку прототипов массивов или объектов, чтобы сделать их вызываемыми. По сути, я ищу что-то вроде этого:

 // some magic with prototypes
????????????????

a = [1, 3, 4]
b = [1, 3, 4]

console.log(a[1]) // prints 3
console.log(b(1)) // prints 3

a[0] = -1
// same as
b(0, -1)

console.log(a[1], b(1)) // prints -1 -1
  

Большое спасибо!

Комментарии:

1. Я думаю, что у меня есть решение для этого, но я все еще занимаюсь исследованиями…

2. НЕТ, это невозможно сделать. Почему вы хотите b(0, -1) ?

3. @ThomBlake я. Невозможно создать массивоподобный объект, который можно вызывать. Конечно, без прокси, используя прокси es: h, вы можете делать практически все.

Ответ №1:

Вы, вероятно, не хотите этого делать, особенно в любом браузере. У этого не так много приятных функций Array, включая эффективность. Тем не менее:

 function ArrayFunction (arr) {
  var f = function s (p, v) {
    if (v !== undefined) {
      s[p] = v
    }
    return s[p]
  }

  for (var i = 0; i < arr.length; i  ) {
    f[i] = arr[i]
  }

  return f
}

var a = new ArrayFunction([1, 3, 4])
var b = new ArrayFunction([1, 3, 4])

b(1, 5)
a[1] //3
b[1] //5
  

Изначально я хотел использовать прототипы, но объекты не наследуют вызываемость от своих прототипов.

РЕДАКТИРОВАТЬ: исправлено выше, чтобы не использовать arguments . Эта версия не позволяет вам устанавливать значение undefined равным , но в любом случае это обычно не считается хорошей практикой.

Комментарии:

1. Вы должны объяснить, что вы имеете в виду, делая движки JavaScript «очень грустными». Я думаю, вы имеете в виду, что используемые функции arguments работают медленнее.

2. @JuanMendes Да, это и заставляет младенца Иисуса плакать.

3. Вау, это какое-то чудовище! Это приближается к тому, что я искал. Интересно, можно ли сделать эту новую функцию ArrayFunction неявной при создании нового массива или объекта?

4. Вы нарушили .length и забыл клонировать Array.prototype методы в

5. @Raynos Я не забыл — я думал, что это уже достаточно плохо. Я бы не доверял клонированию методов Array.prototype, поскольку на самом деле это не массив — если бы я использовал это и хотел эти методы, я бы написал их сам.

Ответ №2:

Хороший вопрос, но ответ отрицательный, потому что объекты не являются функциями.

Самое близкое, что вы можете получить, это:

Array.prototype.set = function(a,b) { this[a] = b; };

Затем вы можете сделать:

b.set(0, -1);

Комментарии:

1. Да, и я бы добавил к этому, что вы не можете переопределить поведение ни вызова функции () , ни доступа к индексированному массиву [] в JS.

2. ну, в любом случае, функции — это объекты.

Ответ №3:

Javascript не поддерживает подобную перегрузку операторов. Я не могу придумать способ, чтобы одна переменная поддерживала как [], так и () доступ, но если вам не нужен [] доступ, вы могли бы попробовать что-то вроде:

 var weird_array = (function() {
    var data = [1,2,3];
    return function(idx, n) {
        if (arguments.length === 1)
            return data[idx];
        else if (arguments.length === 2)
            return (data[idx] = n);
    };   
})();
  

В этом примере weird_array это на самом деле не массив, поэтому вы не можете использовать для него [], но это функция (обернутая вокруг массива данных). Затем вы могли бы сделать:

 weird_array();  // => undefined
weird_array(0); // => 1
weird_array(1); // => 2
weird_array(2); // => 3
weird_array(3); // => undefined
weird_array(1, 5); // => 5
weird_array(1); // => 5
  

Комментарии:

1. Спасибо! Как здорово, вы можете создавать замыкания из объектов и объекты из замыканий, но обычно мне нужны обе формы () и [] .