2

why do I need setTimeout.bind(window) in javascript? I saw code pieces like this, why do I need this? I can use directly setTimeout.

setTimerFunctions: SetTimerFunctions = {
    setInterval: setInterval.bind(window),
    setTimeout: setTimeout.bind(window),
  }
dany
  • 37
  • 1
  • Greetings and welcome to StackOverflow! With the niceties aside I have some bad news; we are not here to answer questions about technicalities; what we are here for is to help you to fix your code that is broken and provide an answer as to why the code you have does not work, we can't provide the "why does this do that", or "why do I need this", that's what Google is for :) – Can O' Spam Aug 16 '19 at 16:05
  • backwards compatibility, as some browsers didn't bind it for you, just like you _used_ to have to pass `console.log.bind(console)` instead of just `console.log` before they "stuck" the context for you. – dandavis Aug 16 '19 at 16:12
  • 1
    Possible duplicate of [Use of the JavaScript 'bind' method](https://stackoverflow.com/questions/2236747/use-of-the-javascript-bind-method) – Reza Saadati Aug 16 '19 at 16:12
  • 3
    @SamSwift웃 No, such questions are entirely on topic. This is _not_ a "debug my code for me" service. – Lightness Races in Orbit Aug 16 '19 at 16:18
  • @dandavis If you have an answer please post it as such – Lightness Races in Orbit Aug 16 '19 at 16:28

2 Answers2

1

.bind

The first parameter for bind is the value of this inside the binded function. Passing window (or null, that would be equivalent) is a way to attach this to the global scope.

setTimeout

setTimeout is a method of window (window.setTimeout), then this inside that function should be window, but it is not needed in current browsers.

Remember that setTimeout(...) is equivalent to call window.setTimeout(...) because window is the global context.

Who is this?

An example:

var foobar = window.setTimeout;

This code could not work the way you would expect, it depends on the context, that we do not know.

For window.setTimeout, this would be the contextual this of this assignment. To force the reference to another this, you have to set the reference with bind:

var foobar = window.setTimeout.bind(window);

Except when assigning it from the global context, in that case the function will have this as window.

Your code without binding

In your exact case, if you do do not bind and just assign:

setTimerFunctions: SetTimerFunctions = {
    setInterval: setInterval,
    setTimeout: setTimeout,
  }

then this, from the setTimeout/setInterval point of view, will be every instance of the class where this code is declared (as it seems to be part of a class declaration in TypeScript).

Extra: function vs arrow function

Take a look at the documentation and differences between function and arrow functions =>, this issue is one of the reasons why arrow functions were added.

Community
  • 1
  • 1
Ignacio Lago
  • 2,432
  • 1
  • 27
  • 33
  • you are right, then I do not have to use this way, I can use only ```setTimeout()```. I mean it is already bound, am I wrong? – dany Aug 16 '19 at 16:23
  • 1
    Just doing `var foobar = window.setTimout;` will not work the way you could expect, because you referenced the function without a binded `this`, then `this` would be the context of that assignment, not necessarily the global/window scope, unless it is assigned there or statically binded. – Ignacio Lago Aug 16 '19 at 16:29
  • you are right, if I want to assign setTimeout() into a property in an object, I should use .bind(window). Otherwise I could not call object's property somewhere else. I was looking if there was any other reason to use setTimeout like this. Because to assign setTimeout() in an object and call the object when you need does not make sense to me instead I can call directly setTimeout when I need. (by the way this is not my code, I am trying to understand for maintaining) – dany Aug 16 '19 at 16:48
  • You are right, your code, without more context, does not seem to solve anything, just reference those global methods to internal methods. – Ignacio Lago Aug 16 '19 at 16:58
  • it's just called an [_arrow function_](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions). "fat-arrow" comes from languages like CoffeeScript where arrow functions `x -> ...` are differentiated from fat arrows `x => ...`. JavaScript makes no such distinction. – Mulan Aug 16 '19 at 17:33
  • @user633183 Thanks for the correction, I have edited the answer. – Ignacio Lago Aug 16 '19 at 17:43
0

When method is called on obj, the context (this) for method is bound to obj. This is known as a dynamic call because the context changes (is dynamic) based on the object calling the method -

const obj = {
  method: function() {
    console.log('self?', this === obj)
    console.log('window?', this === window)
  }
}

obj.method() // <-- [obj] becomes [this] inside [method]
// self? true
// window? false

When a function is not called dynamically, it has no context, and instead this is bound to the global object, window -

const obj = {
  method: function() {
    console.log('self?', this === obj)
    console.log('window?', this === window)
  }
}

const fn = obj.method

fn() // <-- non-dynamic call, [this] binds to [window] as default context
// self? false
// window? true

To answer your question, in the case of window.setTimeout, binding doesn't really matter. Maybe window context was needed in the past, but it doesn't seem to be a requirement in modern browsers -

const test = function() {
  console.log(this === window)
}

window.setTimeout(test, 1000) // true
window.setTimeout.bind(window)(test, 1000) // true
window.setTimeout.bind(null)(test, 1000) // true

setTimeout(test, 1000) // true
setTimeout.bind(window)(test, 1000) // true
setTimeout.bind(null)(test, 1000) // true

Binding of the "callback" does matter. Notice a null context binds this to the global object, window -

const test = function () {
  console.log(this === window)
}

setTimeout(test, 1000) // true
setTimeout(test.bind(null), 1000) // true
setTimeout(test.bind({ a: 1 }), 1000) // false

Note however you cannot bind context of arrow functions; they always have a lexical this -

const test = () => console.log(this === window)

setTimeout(test, 1000) // true
setTimeout(test.bind({ a: 1 }), 1000) // true
Mulan
  • 129,518
  • 31
  • 228
  • 259