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

Как сдвинуть "аргументы"?

Здесь script:

function runScripts() {
    if (arguments.length === 0) return;
    chrome.tabs.executeScript(null, {
        file: arguments[0]
    }, function() {
        arguments.shift();
        runScripts.apply(null, arguments);
    });
}

Это не работает, потому что arguments на самом деле не массив, он просто похож на массив. Итак, как я могу "сдвинуть" его или взломать первый элемент, чтобы я мог рекурсивно применять эту функцию?

4b9b3361

Ответ 1

Я предполагаю, что вы хотите ссылаться на исходный arguments, а не на обратный вызов, который вы переходите на chrome.tabs.executeScript.

Если это так, вам нужно сначала его кэшировать.

function runScripts() {
    if (arguments.length === 0) return;
    var args = [];
    Array.prototype.push.apply( args, arguments );

    chrome.tabs.executeScript(null, {
        file: args.shift();
    }, function() {
             // using the modified Array based on the original arguments object
        runScripts.apply(null, args);
    });
}

Ответ 2

var params = Array.prototype.slice.call(arguments);
params.shift();

Вы можете проверить этот пост в блоге, который объясняет это более подробно.

Ответ 3

[].shift.call(arguments) также действителен. Я использую это в производственном коде, и он работает как ожидалось.

При таком подходе ваша функция становится немного более кратким:

function executeScripts() {
    if (arguments.length === 0) return;
    chrome.tabs.executeScript(null, {
        file: [].shift.call(arguments)
    }, function() {
        executeScripts.apply(null, arguments);
    });
}

Если вы посмотрите на MDN, они заявляют, что shift() был реализован с учетом этой гибкости.

https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/shift

Ответ 4

Вы можете преобразовать arguments в обычный массив следующим образом:

var args = Array.prototype.slice.call(arguments);

Ответ 5

Просто хочу указать потенциальную проблему с []. shift.call(arguments).

Кажется, что у вас есть, возможно, нечеткое намерение переместить ваши аргументы - даже для ваших параметров с именем - даже если они используются до утверждения shift.

Например,

function testShift (param1, param2) {
    [].shift.call(arguments); 
    if (param1=="ONE") alert("ONE");
}

Если вы выполните следующий вызов, что вы можете ожидать?

testShift("ONE", "TWO");

Если вы ожидали, что param1 останется "ONE", ваше исправление должно установить параметр var для param1 до того, как произойдет смена. Похоже, что javascript не привязывает param1 до тех пор, пока он не будет вызван - не при вызове функции... так что модификации аргументов перед используемым параметром могут иметь неожиданные эффекты.

Надеюсь, теперь вы сможете это ожидать.

Ответ 6

Вам нужно будет преобразовать его в массив и затем сменить. Или, наоборот, удалите первый элемент при преобразовании в массив. Array.prototype.slice.call(arguments, 1) будет работать для этого.

Ответ 7

Вы можете преобразовать аргументы в фактический массив, а затем использовать этот массив в остальной части вашей логики в функции.

function runScripts()
{
  var i=0, l=arguments.length, arr=[];
  while(i<l)
  {
    arr.push(arguments[i++]);
  }
...rest of your function code

Изменить для добавления: у меня были проблемы с prototype и call в более старых версиях IE, поэтому это действительно зависит от того, какую поддержку вам потребуется.

Ответ 8

Вот статья объясняет это очень хорошо. Я скопировал некоторые ключевые моменты ниже. http://www.javascriptkit.com/javatutors/arrayprototypeslice.shtml

Для массива помните, что вы можете вызвать функцию среза, чтобы получить дополнительный массив.

var abc = [1,2,3,4,5];
abc.slice(0); //[1,2,3,4,5]
abc.slice(1,3); //[2,3]

Поскольку объект аргумента - это только массив, а не массив. Функция call()/apply() в основном просто "заимствует" функцию среза из массива и использует его в объекте Argument, и вы даже можете передавать параметры в функцию среза так же, как и на массив.

var myobject ={ // array-like collection
    length: 4,
    '0': 'zero',
    '1': 'one',
    '2': 'two',
    '3': 'three'
}

var myarray = Array.prototype.slice.call(myobject) 
// returns myobject as a true array: ["zero", "one", "two", "three"]

var myarray = Array.prototype.slice.call(myobject, 1) 
// returns ["one", "two", "three"]

Остается вопрос, почему мы вызываем slice() для объекта-прототипа Array вместо экземпляра массива. Причина в том, что это самый прямой путь к доступу к методу slice() массива, когда все это нас интересует; мы могли бы сначала создать экземпляр массива, но это было менее эффективным и, возможно, более заумным:

var myarray = new Array().prototype.slice.call(myobject) // less efficient

Ответ 9

В ES6 теперь вы можете использовать Array.from() MDN ref

например.

const args = Array.from(arguments);
const str = args.shift();

Ответ 10

Я пошел с этим:

function executeScripts() {
    if (arguments.length === 0) return;
    var args = Array.prototype.slice.call(arguments);
    chrome.tabs.executeScript(null, {
        file: args.shift()
    }, function() {
        executeScripts.apply(null, args);
    });
}

Это полезно при написании расширений Google Chrome. Я хотел использовать jQuery в своем контенте script, но тогда вы должны сначала загрузить его. Выключается путем цепочки вызовов chrome.tabs.executeScript, вы можете сделать это:

chrome.browserAction.onClicked.addListener(function(tab) {
    executeScripts('jquery-1.4.4.min.js', 'content.js');
});