Function bind - garevna/js-course GitHub Wiki

:mortar_board: Биндинг и каррирование


:mortar_board: bind()

По сути, метод bind() является декоратором, поскольку он создает обертку для исходной функции

Функция-wrapper, в которую "заворачивается" исходная функция, вызывает ее в нужном контексте:

function bindContext ( func, context, args ) {
    func.call ( context, args )
}

function sample ( message ) {
    console.log ( `${this.name}: ${message}` )
}

var user = { name: "Фигаро" }

bindContext ( sample, user, "Hello" )

Чтобы функция-wrapper возвращала новый экземпляр, немного изменим код,

а так же обеспечим возможность привязки не только контекста вызова,

но и аргументов ( этот прием программирования называется Currying, или каррирование ):

function bindContext ( func, context, props ) {
    return function ( args ) {
        props ? func.call ( context, props, args ) :
                func.call ( context, args )
    }
}

function sample ( message ) {
    console.log ( `${this.name}: ${message}` )
}

var user = { name: "Фигаро" }

var userSayHello = bindContext ( sample, user, "Hello" )

var userSay = bindContext ( sample, user )

userSayHello()     // Фигаро: Hello
userSay ( "Bye" )  // Фигаро: Bye

Вот и весь механизм работы метода bind()


:coffee: :three:

var test = ( function () {
    var counter = 0
    return function () {
        return ++counter
    }
})()

function func () {
    console.warn ( `Функция func вызвана ${this.test()} раз в контексте объекта ${this.name}` ) 
}

var figure = { name: "figure", test: test }
var sample = { name: "sample", test: test }
var google = { name: "google", test: test }

var figureFunc = func.bind ( figure )
var sampleFunc = func.bind ( sample )
var googleFunc = func.bind ( google )

figureFunc ()
sampleFunc ()
googleFunc ()
Результат в консоли:
⚠️ ► Функция func вызвана 1 раз в контексте объекта figure
⚠️ ► Функция func вызвана 2 раз в контексте объекта sample
⚠️ ► Функция func вызвана 3 раз в контексте объекта google

Теперь контекст вызова экземпляров figureFunc(), sampleFunc() и googleFunc() изменить невозможно, и при вызове этих функций не нужно явно указывать, в каком контексте они вызываются


:coffee: :four:

Добавим еще один объект bloom с методами figure(), sample() и google():

var bloom = { name: "bloom" }
bloom.figure = figureFunc
bloom.sample = sampleFunc
bloom.google = googleFunc

bloom.figure()
bloom.sample()
bloom.google()
Результат в консоли:
⚠️ ► Функция func вызвана 4 раз в контексте объекта figure
⚠️ ► Функция func вызвана 5 раз в контексте объекта sample
⚠️ ► Функция func вызвана 6 раз в контексте объекта google

Несмотря на явное указание контекста при вызове методов:

bloom.figure()
bloom.sample()
bloom.google()

они отрабатывают в том контексте, который мы им "прибиндили" до этого

"Прибиндить" можно не только контекст вызова, но также и аргументы