объяснить, как работает эта функция javascript (в статье Дугласа Крокфорда «Как работает Javascript») - PullRequest
1 голос
/ 27 апреля 2019

Я хотел бы понять, как работает функция make_binary_op().Он принимает два различных параметра

  1. параметр функции addop или mulop
  2. параметр массива (my_little_stack / my_little_array)

Я использовал отладчик firefox для наблюдения за выполнением, но до сих пор не понимаю, как работает функция make_binary_op().Я получаю все хлопки и толчки и т. Д.

function make_binary_op(func) {
  return function(my_little_array) {
    let wunth = my_little_array.pop();
    let zeroth = my_little_array.pop();
    my_little_array.push(func(zeroth, wunth));
    return my_little_array;
  };
};

let addop = make_binary_op(function(zeroth, wunth) {
  return zeroth + wunth;
});

let mulop = make_binary_op(function(zeroth, wunth) {
  return zeroth * wunth;
});

let my_little_stack = [];
my_little_stack.push(3);
my_little_stack.push(5);
my_little_stack.push(7);
mulop(my_little_stack); //  my_little_stack is  [3, 35]
addop(my_little_stack); //  my_little_stack is  [38]
let answer = my_little_stack.pop(); //  my_little_stack is  []
console.log(answer);

Код работает, как указано.Значение answer равно 38, а my_little_stack равно [] в конце.

1 Ответ

1 голос
/ 27 апреля 2019

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

function binary_op(func, my_little_array) { // Two arguments
    let wunth = my_little_array.pop();
    let zeroth = my_little_array.pop();
    my_little_array.push(func(zeroth, wunth));
    return my_little_array;
};

let add = function(zeroth, wunth) { // No call to make_binary_op
  return zeroth + wunth;
};

let mul = function(zeroth, wunth) {
  return zeroth * wunth;
};

let my_little_stack = [];
my_little_stack.push(3);
my_little_stack.push(5);
my_little_stack.push(7);
binary_op(mul, my_little_stack); // we need to pass two arguments
binary_op(add, my_little_stack);
let answer = my_little_stack.pop();
console.log(answer);

Я думаю, вы сможете понять, как это работает: новая функция binary_op принимает обе функции обратного вызова (которая выполняет операцию с двумя аргументами) и стек.Затем он извлекает два значения из стека, передает их в функцию обратного вызова, получает из нее результат и помещает этот результат (возможно, сумму или произведение) в стек.Таким образом, размер стека уменьшился на 1: два операнда были заменены результатом func.

Предполагая, что вы следите за тем, как это работает, теперь посмотрим, как мы могли бы сделать это вместо этого:

binary_op(mul, my_little_stack);

... мы могли бы написать это:

mulop(my_litte_stack);

mulop должна быть функцией, которая может объединять то, что mul делает и то, что вышеупомянутый binary_op делает, за один раз.

Вот где приходит функция make_binary_op: она создает (и возвращает) функцию, которая специально предназначена для оператора, которого вы имеете в виду (икоторый вы передаете в качестве аргумента).Если вы передадите mul в make_binary_op, он создаст функцию, которая реализует вышеуказанную функцию binary_op, специально адаптированную для mul: когда эта созданная функция вызывается, она вызовет mul.Но обратите внимание, что для этой динамически создаваемой функции нужен только один аргумент (стек), потому что другой аргумент (func) ей уже известен.Он присутствует в «замыкании», в котором эта функция была возвращена.

Приложение

Одним из критических замечаний по этому шаблону может быть следующее наблюдение: пока элементы добавляются в my_little_array с помощью точкинотации (my_little_array.push), операции mul / add должны быть выражены как вызовы функций, где my_little_array передается в качестве аргумента.Почему его нельзя заставить работать с точечной нотацией, чтобы вы могли написать my_little_array.mul()?

В текущем состоянии языка JS вы можете сделать это с помощью класса (конструктора), который расширяетсяArray, так что кроме push и pop он также может поддерживать add и mul:

class PolishCalc extends Array {
    static registerBinaryOp(func) {
        this.prototype[func.name] = function () {
            let wunth = this.pop();
            let zeroth = this.pop();
            this.push(func(zeroth, wunth));
            return this;
        }
    }
}

// Extend the prototype with add and mul methods:
PolishCalc.registerBinaryOp(function add(zeroth, wunth) {
    return zeroth + wunth;
});

PolishCalc.registerBinaryOp(function mul(zeroth, wunth) {
    return zeroth * wunth;
});

let polishCalc = new PolishCalc;
polishCalc.push(3, 5, 7);
let answer = polishCalc.mul().add().pop(); // the method calls can be chained...
console.log(answer);
...