Подтвердить что ты не робот

Использование оператора останова и оператора распространения в javascript

Как использовать параметр rest, который будет добавлен в ECMAScript 6?

Например, в ECMAScript 5 вы можете сделать следующее, чтобы получить массив параметров, начиная со второго элемента:

// ES 5
store('Joe', 'money');
store('Jane', 'letters', 'certificates');
function store(name) {
  var items = [].slice.call(arguments, 1); //['money'] in first case
  items.forEach(function (item) {
    vault.customer[name].push(item);
  });
}

и это будет эквивалентно следующему коду в ECMAScript 6:

// ES 6
store('Joe', 'money');
store('Jane', 'letters', 'certificates');
function store(name, ...items) {
  items.forEach(function (item) {
    vault.customer[name].push(items)
  });
}

Разница между ними - это просто синтаксис или проблема с производительностью?

Также для оператора распространения (...)

//in ecmascript5
var max = Math.max.apply(null, [14, 3, 77]);
//but in ecmascript6
var max = Math.max(...[14, 3, 77]);

Является ли это просто синтаксическим изменением или проблемой производительности?

4b9b3361

Ответ 1

Разница между ними - это просто синтаксис или проблема с производительностью?

Оба и многое другое...

Параметры останова:

  • Являетесь известной идиомой на других языках (Ruby, Python).
  • esier читать и поддерживать (vs. slice).
  • легче понять для начинающих.
  • Может (и, вероятно, будет) привести к лучшей производительности, так как двигатели могут оптимизировать.
  • инструмент более дружелюбный, так как они могут быть проанализированы статически.

Ответ 2

В дополнение к ответу @kangaxs я бы уточнил, что производительность и правильность многократно возникают при вызове объекта arguments. Если вы передаете объект arguments другой функции, вы передадите ему право изменять соответствующие локальные переменные в своей области.

function foo(arg) {
    bar(arguments);
    return arg;
}

function bar(args) {
    args[0] = 20;
}

foo(10) // 20

Существование этой функции делает недействительными локальные аргументы внутри функции, что затрудняет оптимизацию JIT и создает определенные угрозы безопасности. Программы, предназначенные для скорости, должны работать над этой проблемой с гораздо более сложным шаблоном кода, чем идиома Array.prototype.slice.call(arguments), а в контексте безопасности передача arguments должна быть строго запрещена.

Устранение необходимости использования объекта arguments для извлечения вариативных аргументов является одним из многих преимуществ нового синтаксиса.

Ответ 3

В данном примере вы напрямую передаете литерал объекта. Несмотря на то, что он все еще является семантическим, он кажется не аналогичным приложению оператора спредов. IMO, значение оператора спрэда становится очевидным, когда перечисление каждого параметра ухудшает читаемость кода (и ремонтопригодность при замене традиционных методов push, splice, concat).

С оператором распространения

let nums = [1.25,5.44,7.15,4.22,6.18,3.11];   

function add(a, b, ...nums){
  let sum = parseInt(a + b);
  nums.forEach(function(num) {
    sum += num;
  })
  return parseInt(sum);
}

console.log(add(1, 2, ...nums)); //30

ES6Fiddle demo (скомпилировано traceur-compiler)

Без оператора распространения

var nums = [1.25,5.44,7.15,4.22,6.18,3.11];   

function add(a, b, nums){
  var sum = parseInt(a + b);
  nums.forEach(function(num) {
    sum += num;
  })
  return parseInt(sum);
}

console.log(add(1, 2, nums)); //30

JSFiddle demo

В заключение я не думаю, что использование оператора спреда улучшит или затруднит производительность, однако оно обеспечивает улучшенную читаемость кода и, возможно, поддержку. К сожалению, ES6 пока еще не широко внедряется, и я уверенно предполагаю, что потребуется некоторое время для поддержки браузера.

Фантастический факт: PHP 5.6 вводит аналогичные функции с вариативными функциями, которые сделают func_get_args() избыточным.

Ответ 4

Параметр rest собирает отдельные параметры в массив, когда вы используете точки в определении параметра функции, в то время как оператор распространения расширяет массив на отдельные параметры при использовании точек в function call.

Когда бы вы ни захотели собрать отдельные параметры в массив, вы бы использовали оператор rest в определении вашего параметра функции.

let sum = (...numbers) => {
  let result = 0;

  numbers.forEach(function(n){
  result += n;
  });

  return result;
};

console.log(sum(1,2,3));

Работа с объектом arguments внутри вложенной функции становится действительно сложной задачей. Давайте рассмотрим следующую ситуацию, когда нашей внутренней функции необходим доступ к переданному объекту arguments.

Если нашей inner function filterNumbers нужен доступ к аргументам, ее нужно сохранить выше в variable прежде чем передавать ее дальше, поскольку каждая функция имеет свой собственный объект arguments, который является объектом, подобным массиву.

function sumOnlyNumbers() {
  var args = arguments;
  var numbers = filterNumbers();
  return numbers.reduce((sum, element) => sum + element);
    function filterNumbers() {
      return Array.prototype.filter.call(args,
        element => typeof element === 'number'
    );
  }
}
sumOnlyNumbers(1, 'Hello', 5, false);

Подход работает, но он слишком многословен. var args = arguments может быть опущен, а Array.prototype.filter.call(args) может быть преобразован в args.filter() с помощью параметра rest.

function sumOnlyNumbers(...args) {
  var numbers = filterNumbers();
  return numbers.reduce((sum, element) => sum + element);
    function filterNumbers() {
      return args.filter(element => typeof element === 'number');
    }
  }
sumOnlyNumbers(1, 'Hello', 5, false); // => 6

Когда бы вы ни захотели расширить массив на отдельные параметры, вы бы использовали оператор распространения в вызове функции.

let sum = (a,b,c) => {
  return a + b + c;
};

console.log(sum(...[1,2,3]));

В приведенном выше коде оператор распространения будет "spread" массив из трех значений по parameters a, b, and c. Оператор spread также может расширять массив для создания отдельных элементов в литерале array.

var a = [4, 5, 6];
var b = [1, 2, 3, ...a, 7, 8, 9]
console.log(b);

Улучшен вызов функций в ES6

ES5 предоставляет .apply() для объекта функции, чтобы решить эту проблему. К сожалению, эта техника имеет 3 проблемы:

  • Необходимо вручную указать контекст вызова функции
  • Не возможно использовать в вызове конструктора
  • Более короткое решение является более предпочтительным

Кажется неуместным указывать во .apply() второй раз страны контекста, делая его более многословным.

let countries = ['India', 'USA'];
let otherCountries = ['China', 'Japan'];
countries.push.apply(countries, otherCountries);
console.log(countries); // => ['India', 'USA', 'China', 'Japan']

Оператор spread заполняет аргументы вызова function значениями из array. Позвольте улучшить приведенный выше пример с помощью оператора распространения:

let countries = ['India', 'USA'];
let otherCountries = ['China', 'Japan'];
countries.push(...otherCountries);
console.log(countries); // => ['Moldova', 'Ukraine', 'USA', 'Japan']

Оператор Spread настраивает аргументы вызова конструктора из массива, что немного сложно и сложно напрямую при использовании .apply().

class Actor {
  constructor(name, country) {
  this.name = name;
  this.country = country;
  }
  getDescription() {
  return '${this.name} leads ${this.country}';
  }
}
var details = ['RajiniKanth the Great', 'India'];
var Alexander = new Actor(...details);
console.log(Alexander.getDescription()); // => 'RajiniKanth the Great leads India'

Более того, вы можете объединить несколько операторов spread и обычные аргументы в одном вызове. Следующий пример удаляет из массива существующие элементы, затем добавляет другой массив и элемент:

var numbers = [1, 2];
var evenNumbers = [4, 8];
const zero = 0;
numbers.splice(0, 2, ...evenNumbers, zero);
console.log(numbers); // => [4, 8, 0]

Клонировать экземпляр массива:

var words = ['Hi', 'Hello', 'Good day'];
var otherWords = [...words];
console.log(otherWords); // => ['Hi', 'Hello', 'Good day']
console.log(otherWords === words); // => false

otherWords - клонированная версия массива слов. Обратите внимание, что клонирование происходит только для самого массива, но не для содержащихся в нем элементов (т.е. Это не глубокий клон).

Ссылки: https://dmitripavlutin.com/how-three-dots-changed-javascript/

Ответ 5

Я думаю, что главными отличиями в параметре отдыха являются:

  • Аргументы в аргументах ECMA5 похожи на массив, а не массив, поэтому обычные методы массива недоступны, но в аргументах ECMA6 используется массив.
  • Я думаю, что массив объектов в примере кода ECMA5 сделает код немного медленнее, потому что создается новый массив.