2016-01-15 4 views
4

Я не спрашиваю, как его использовать. Я знаю, как его использовать.Как работает метод JavaScript .apply?

Но когда apply вызывает функцию, которая его вызвала, как именно она передает массив аргументов в функцию, которая не была записана для принятия массива для аргумента? Сочетает ли он свой массив аргументов с вызываемыми функциями «аргументы»?

Я рассмотрел последние спецификации ECMAscript для .apply и .call, но я ничего не видел о базовой логике.

Любое объяснение было бы добро пожаловать. Я новичок в JavaScript и хочу лучше понять, что происходит под капотом. В настоящее время я пытаюсь воссоздать некоторые из основных функций самостоятельно, и этот вопрос дает мне массу проблем.

+1

Это под капотом. Он реализован вне JavaScript; и интерпретатор JavaScript может делать все, что захочет. Вы не можете реализовать 'apply' без' apply' (запрет 'eval' siness), так как это единственное в JavaScript, которое предоставляет эту функциональность. Вы могли бы также спросить: «Как« console.log »обращается к консоли» или «как« setTimeout »устанавливает тайм-аут»; это то, что он делает. – Amadan

+0

Я думаю, это зависит от каждого двигателя. – DontVoteMeDown

+0

Спасибо @ Амадан, это было именно то, что я хотел знать. Я бы сказал, что это отличается от чего-то вроде console.log. Это основано на API. Окно многих сред имеет консольное пространство имен. Применение не имеет никакого отношения к внешним средам. Хотя, может быть, я не прав. – rPat

ответ

3

От spec.

Мы должны взять argArray и создать то, что будет аргументом object pseudo array.

По существу

Function.prototype.apply = function apply (thisArg, argArray) { 
    var len = argArray.length; 
    var n = ToUint32(len); 
    var argList = []; // where this is a List not an array. 
    var index = 0; 
    var indexName; 
    var nextArg; 
    while (index < len) { 
     indexName = ToString(index); 
     nextArg = argArray[indexName]; 
     argList.push(nextArg); 
     index++; 
    } 
    return this['[[Call]]'](func, thisArg, argList); // ignore the syntax however 
                // This is the line where the function 
                // will be called and provide 
                // the thisArg and thisArray 
} 

я опустил некоторые проверки типов, что происходит, но это, по существу, очень близко к тому, что спецификации диктует о том, как Function.prototype.apply реализуется. Мы создаем свой собственный объект и создаем argList перед вызовом функции.

Важно отметить. что внутренний метод с именем [[Call]] отличается от Function.prototype.call.

+0

И, следуя спецификации, List является конкретным типом реализации, не так ли? Это не часть JS, которую я могу использовать, это тип под капотом, используемый для хранения аргументов? Я думаю, что это ответ. Спецификации действительно говорят, как применяется приложение. Вы тоже очень хорошо их написали, спасибо. – rPat

+0

Да все вещи, завернутые в двойные квадратные скобки '[[]]' являются специфичными для реализации. И в этом случае «Список» также. См. Спецификацию https://es5.github.io/#x8.8 – t3dodson

0

Function.prototype.apply специфичен для реализации: он реализован в самом JavaScript-устройстве. На самом деле нет способа воспроизвести его, поскольку, когда вы его называете, он использует C * API, чтобы заставить движок вызывать функцию, которую вы хотите вызвать. Пользовательский код не может управлять внутренним API, поэтому нет возможности реализовать Function.prototype.apply без собственного кода.

"Source code" of <code>Function.prototype.apply</code>
"Исходный код" из Function.prototype.apply согласно Function.prototype.toString в V8

* Предполагая, что двигатель JS написан на C. Заменить любой язык < вставки JS двигатель здесь > написано в.

2

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

Вы недоразумение, как это работает. apply делает не передает массив аргументов объекту. Он принимает массив, а затем использует его для динамического построения вызова функции, аналогично тому, что вы могли бы сделать с оператором eval (но он делает это изначально).

Например, eval оператор может работать так:

function buildFromArray(funcName, arrayOfArgs) 
{ 
    var functionCall = funcName + "("; 

    for (var i = 0; i < arrayOfArgs.length; i++) 
    { 
     //Very simplified, only allows for string args 
     functionCall += "\"" + arrayOfArgs + "\""; 

     if (i < arrayOfArgs.length - 1) functionCall += ","; 
    } 

    functionCall += ")"; 

    //Now we run the compiled call which will be something like: 
    //myFunction("one","two") 
    eval(functionCall); 
} 

buildFromArray("myFunction", [ "one", "two" ]); 

Это очень упрощенная, но вы можете увидеть, как массив никогда не передается функции myFunction.

Смежные вопросы