I've found folloing sample in which As if Service class has prototype property.
①Service is not instansiated, why Service = new Service() didn't need ?
②console.log(Service.prototype returned {},what is this object ? What is the merit to manipulate this?
beforeEach(async ()=>{
jest.spyOn(Service.prototype, 'execute')
})
I am totally novice to this concept, if someone has opinion will you please let me know. Thanks
CodePudding user response:
What this does is that whenever .execute(...) is called on any Service instance, your spying thingy would fire.
It doesn't need new Service() because it's not working on a single service instance, it is working on the class itself.
It works by replacing Service.prototype.execute with a wrapper function that logs the call and then calls the original function, something like this:
const oldExecute = Service.prototype.execute
Service.prototype.execute = function (...args) {
console.log('execute called!', args)
return oldExecute.call(this, ...args)
}
Class methods are nothing other than properties on the class' prototype, so if you have class Test { hello (x) { return x * 2 } } and you do console.log(Test.prototype.hello), it will log the method hello (x) { return x * 2 }, and if you do testInstance.hello(123) it essentially then calls Test.prototype.hello.call(testInstance, 123), i.e. it calls the function Test.prototype.hello with testInstance as this.
And the {} that you see is not everything there is, because the methods are by default non-enumerable. You should look at it in a debugger that also shows non-enumerable properties. Then you will see the class' methods there:
This is also the reason why when referring to the "full name" of a class method, often ClassName.prototype.methodName is used, because that's actually how you would get that method itself without referring to a particular class instance (to make use of it, you would have to call it with its this set to some instance, though, like what I did with .call above). For example, the slice function that exists on Array (when you write [1, 2, 3].slice(1) for instance) is referred to as Array.prototype.slice (in other languages this would be called Array::slice, Array#slice or the like). Sometimes you will also see people talking about Array.slice but that's technically not correct because slice is not a static method and doesn't exists on Array itself (unlike, for example, Array.from).
Further reading:
- MDN: Object prototypes
- MDN: Classes in JavaScript
- MDN: Docs for
Function.prototype.call(to understand the examples) - Jest docs for
spyOn

