Как добавить функцию как метод в возвращаемый массив?

#javascript #arrays #function #object #methods

#javascript #массивы #функция #объект #методы

Вопрос:

У меня есть функция, предназначенная для использования с new конструктором. Он должен возвращать массив со значением ["Hello World"] и включать функции в качестве методов. Вот пример / демонстрация (извините, если это немного некрасиво):

 var my_object = function () {
  this.foo = function (data) { // alert and add new item
    alert(data);
    this.push(data);
  };

  this.bar = function () { // alert and remove last item
    alert(this.pop());
  };

  this.baz = function (stuff) { // replace last item by running previous methods
    this.bar();
    this.foo(stuff);
  };

  var a = "Hello World";
  return [a];
};

var arr = new my_object(); // ["Hello World"]
  

Как и ожидалось, arr имеет значение ["Hello World"] . Однако следующий код выдает ошибку:

 arr.foo('some-text'); // "TypeError: arr.foo is not a function"
  

Тот же тип ошибки появляется с двумя другими функциями. Что я могу сделать, чтобы это работало, без изменения Array.prototype, создания методов вне функции или удаления возможности инициализации с помощью new my_object() ?

Примечание: По возможности, пожалуйста, не включайте ответы с использованием jQuery или других внешних библиотек.

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

1. this это не то значение, которое вы возвращаете из функции, поэтому любой из объявленных вами методов отбрасывается и не используется.

2. Поскольку вы возвращаете массив, .. у массивов нет методов с именем ‘foo’

3. итак, вы хотите наследовать от массива и добавлять новые методы?

4. Какая дизайнерская идея стоит за этим? Arrays являются типами . Вы используете функцию с объектно-ориентированным подходом, но восстанавливаете из нее массив.

5. Это может помочь OP -> github.com/wesbos/es6-articles/blob/master /…

Ответ №1:

Как упоминалось в комментариях, эта ссылка содержит некоторую ценную информацию -> https://github.com/wesbos/es6-articles/blob/master/54 — Extending Arrays with Classes for Custom Collections.md

Используя это, ваш код может быть изменен следующим образом,. ->

Конечно, это так ES6 , расширение массивов было невозможно в ES5 дни..

В Chrome instanceof при отображении работает так, как ожидалось, но не уверен, что перенесенный код работал бы здесь, если бы это было обязательным требованием. Например, если вы нажмете использовать предустановку Babel в этом фрагменте, вы увидите, что он не работает, поэтому, если вы хотите, чтобы это работало в старых браузерах, даже если они были перенесены, это может быть проблемой.

 class my_object extends Array {
  foo(data) {
    alert(data);
    this.push(data);
  }

  bar() {
    alert(this.pop());
  }

  baz(stuff) {
    this.bar();
    this.foo(stuff);
  }

  constructor () {
    super("Hello World");
  }
};

var arr = new my_object(); // ["Hello World"]
arr.foo("some-text");

console.log(arr);  

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

1. Это может работать даже лучше, чем предыдущий ответ (т.Е. меньше изменений в моем коде). Спасибо!

Ответ №2:

Если вы не используете какой-либо Babel или что-то еще, что может обеспечить безопасность вашего кода, так это использование наследования и цепочки прототипов. JavaScript defaults не является объектно-ориентированным программированием, но претендует на ООП.

В вашем случае при построении вы возвращаете, ["Hello World"] который является массивом, а не экземпляром my_object. Вы можете вернуть this вместо [a].

Кроме того, у вас нет ни одного массива, на который вы могли бы ссылаться. Вы работаете с локальным объектом, когда используете это, и у вас есть, вероятно TypeError: this.push is not a function .

Я улучшил ваш случай. Посмотрите, что такое return, где я использую это и ссылку на массив данных.

Приветствую, слива!

Улучшенный код:

 var my_object = function () {
  this.data = [];
  this.foo = function (data) { // alert and add new item
    alert(data);
    this.data.push(data);
  };

  this.bar = function () { // alert and remove last item
    alert(this.data.pop());
  };

  this.baz = function (stuff) { // replace last item by running previous methods
    this.bar();
    this.foo(stuff);
  };

  var a = "Hello World";
  return this;
};

var arr = new my_object(); // [object Object] - a my_object instance
console.log(arr)
arr.foo('some-text');
  

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

1. Ваше решение должно быть размещено здесь, а не на внешнем сайте. Кроме того, это не работает — он возвращает объект , а не массив.

2. Спасибо! С моей стороны потребуется немного редактирования для работы с остальной частью моего кода, но он будет работать отлично.

3. @VLAZ Я отредактировал свой ответ, я буду помнить об этом в будущем. Вы не можете возвращать массив и работать с методами экземпляра. Или вы возвращаете массив или объект, но какой смысл возвращать массив из конструктора?

4. @plumthedev вы могли бы вернуть массив. Точнее, подкласс массива. Или вы также могли бы просто сделать return [] но тогда функция конструктора — странный выбор. Во всяком случае, я исходил из того, что OP выразил в вопросе, где было желание arr буквально быть массивом. OP никогда не отвечал на комментарии, чтобы указать, должен ли это быть буквальный массив, подкласс array, массивоподобный или … по-видимому, вообще не массив, поскольку это выбранное решение.