When you take a reference to a method (a property which is a function) in JavaScript, it usually doesn't remember the object it was originally attached to. If the method needs to refer to that object as this
it won't be able to, and calling it will probably cause a crash.
You can use the .bind()
method on a function to create a wrapper that includes the value of this
and any number of leading arguments.
var monitor = {
threshold: 5,
check: function(value) {
if (value > this.threshold) {
this.display("Value is too high!");
}
},
display(message) {
alert(message);
}
};
monitor.check(7); // The value of `this` is implied by the method call syntax.
var badCheck = monitor.check;
badCheck(15); // The value of `this` is window object and this.threshold is undefined, so value > this.threshold is false
var check = monitor.check.bind(monitor);
check(15); // This value of `this` was explicitly bound, the function works.
var check8 = monitor.check.bind(monitor, 8);
check8(); // We also bound the argument to `8` here. It can't be re-specified.
When not in strict mode, a function uses the global object (window
in the browser) as this
, unless the function is called as a method, bound, or called with the method .call
syntax.
window.x = 12;
function example() {
return this.x;
}
console.log(example()); // 12
In strict mode this
is undefined
by default
window.x = 12;
function example() {
"use strict";
return this.x;
}
console.log(example()); // Uncaught TypeError: Cannot read property 'x' of undefined(…)
The double colon bind operator can be used as a shortened syntax for the concept explained above:
var log = console.log.bind(console); // long version
const log = ::console.log; // short version
foo.bar.call(foo); // long version
foo::bar(); // short version
foo.bar.call(foo, arg1, arg2, arg3); // long version
foo::bar(arg1, arg2, arg3); // short version
foo.bar.apply(foo, args); // long version
foo::bar(...args); // short version
This syntax allows you to write normally, without worrying about binding this
everywhere.
var log = console.log.bind(console);
Usage:
log('one', '2', 3, [4], {5: 5});
Output:
one 2 3 [4] Object {5: 5}
Why would you do that?
One use case can be when you have custom logger and you want to decide on runtime which one to use.
var logger = require('appLogger');
var log = logToServer ? logger.log : console.log.bind(console);