Below are two code snippets - one in Go and the other in JavaScript - essentially doing the same thing.
// Go
package main
import "fmt"
type Engine struct {
bootTimeInSecs int
}
func (e *Engine) Start() {
fmt.Printf("Engine starting in %s seconds ...", e.bootTimeInSecs)
}
type Start func()
type BenchmarkSuite struct {
workloads []string
start Start
}
func main() {
engine := Engine{10}
benchmarkSuite := BenchmarkSuite{workloads: []string{}, start: engine.Start}
benchmarkSuite.start()
}
Output
Engine starting in 10 seconds ...
// JavaScript
function Engine(bootTimeInSecs) {
this.bootTimeInSecs = bootTimeInSecs
}
Engine.prototype.constructor = Engine
Engine.prototype.Start = function() {
console.log("Engine starting in " + this.bootTimeInSecs + " seconds ...")
}
function BenchmarkSuite(workloads, start) {
this.workloads = workloads
this.start = start
}
BenchmarkSuite.prototype.constructor = BenchmarkSuite
engine = new Engine(10)
benchmarkSuite = new BenchmarkSuite([], engine.Start)
benchmarkSuite.start()
Output
Engine starting in undefined seconds ...
I know the workaround in JavaScript, but that's not the question. Why did JavaScript decide not to retain the original execution context of a function?
Here in javascript the function is not bind to the object engine
when you pass the object to BenchmarkSuite
constructor.
You have to explicitly bind the object to the function. This is what you have to do
benchmarkSuite = new BenchmarkSuite([], engine.Start.bind(engine))
The simplest use of bind() is to make a function that, no matter how it is called, is called with a particular this value. A common mistake for new JavaScript programmers is to extract a method from an object, then to later call that function and expect it to use the original object as its this (e.g. by using that method in callback-based code). Without special care however, the original object is usually lost. Creating a bound function from the function, using the original object, neatly solves this problem
You may refer here for more
function Engine(bootTimeInSecs) {
this.bootTimeInSecs = bootTimeInSecs
}
Engine.prototype.constructor = Engine
Engine.prototype.Start = function() {
console.log("Engine starting in " + this.bootTimeInSecs + " seconds ...")
}
function BenchmarkSuite(workloads, start) {
this.workloads = workloads
this.start = start
}
BenchmarkSuite.prototype.constructor = BenchmarkSuite
engine = new Engine(10)
benchmarkSuite = new BenchmarkSuite([], engine.Start.bind(engine))
benchmarkSuite.start()
</div>