function makeProfileTimer() {
    let time1 = performance.now()
    let timeInner = () => {
        let time2 = performance.now()
        return time2 - time1
    }
    return timeInner;
}
// var timer = makeProfileTimer()
// alert('Замеряем время работы этого alert');  //некий код, время выполнения которого мы хотим измерить с высокой точностью
// alert(timer()); //alert должен вывести время в микросекундах от выполнения makeProfileTimer до момента вызова timer(), 
//                // т. е. измерить время выполнения alert

function makeSaver(funk) {

    let savedResult
    let saverInner = () => {
        if (savedResult == undefined) {
         savedResult = funk()
         
        }
        return savedResult

    }
    
    return saverInner
}
var saver = makeSaver(Math.random) //создает функцию-хранилище результата переданной в качестве параметра функции (Math.random 
                                      // в примере). На этом этапе Math.random НЕ вызывается
    var value1 = saver()              //saver вызывает переданную в makeSaver функцию, запоминает результат и возвращает его
    var value2 = saver()              //saver в дальнейшем просто хранит результат функции, и более НЕ вызывает переданную 
                                      //в makeSaver функцию;
    value1 === value2                 // всегда true

    var saver2 = makeSaver(() => console.log('saved function called') || [null, undefined, false, '', 0, Math.random()][Math.ceil(Math.random()*6)])
    var value3 = saver2()
    var value4 = saver2()

    value3 === value4 // тоже должно быть true

    function starter (number) {

        console.log(number)
        number = number - 1
        starterInner()
        function starterInner() {
            setTimeout(() => {         
                if(number > 0){
                    console.log(number)

                    number = number-1

                    return starterInner(number)

                } else {

                    return console.log("done")
                }
            }, 1000)       
        }

    }
    // starter(5)


    ///myBind
    function myBind(funk, context) {

       let arg = [].slice.call(arguments, 2);
       arg = arg[0].filter(index => index != undefined)
       return function ()  {
        debugger
           let newArg = [].slice.call(arguments);
           return funk.apply(context, newArg.concat(arg))
       } 
    }


    var pow5 = myBind(Math.pow, Math, [undefined, 5]) // первый параметр - функция для биндинга значений по умолчанию, 
                                                  // второй - this для этой функции, третий - массив, в котором undefined означает
                                                  // параметры, которые должны передаваться при вызове,
                                                  // а другие значения являются значениями по умолчанию:
    var cube = myBind(Math.pow, Math, [undefined, 3]) // cube возводит число в куб

    console.log(pow5(2)) // => 32, вызывает Math.pow(2,5), соотнесите с [undefined, 5]
    console.log(cube(3)) // => 27


    var chessMin = myBind(Math.min, Math, [undefined, 4, undefined, 5,undefined, 8,undefined, 9])
    console.log(chessMin(-1,-5,3,15)) // вызывает Math.min(-1, 4, -5, 5, 3, 8, 15, 9), результат -5



    var zeroPrompt = myBind(prompt, window, [undefined, "0"]) // аналогично, только теперь задается "0" как текст по умолчанию в prompt, 
                                                          // а текст приглашения пользователя задается при вызове zeroPrompt
    var someNumber = zeroPrompt("Введите число")              // вызывает prompt("Введите число","0")