Consider following code:
class Person{
firstname = ko.observable<string>();
lastname: ko.observable<string>();
fullname = ko.computed(()=>{
// Breakpoint here
return this.firstname() + ' ' + this.lastname();
});
when I'm debugging with Visual Studio 2013, if I put a breakpoint and see the value of this
using watch or immediate window, it shows that the value is window
not the person instance. Consequently, it shows undefined
for this.firstname
.
Checking the converted JavaScript code I find out that I should check the value of _this
instead of this
.
Although code runs without an error, but it waste lots of my time to understand that the true value of this
variable is available through _this
.
Question Am I somewhere wrong in using the class properties which causes this misleading value in this
value? or it's just a bug? or maybe it's by design for some reason?
Due to how the "this" keyword works in javascript Typescript creates the "_this" alias for you. This is by design, and is great when you know how it works.
Your example:
class Person {
firstname = ko.observable<string>();
lastname: ko.observable<string>();
fullname = ko.computed(
() => {
// Breakpoint here
return this.firstname() + ' ' + this.lastname();
});
}
Compiles to:
var Person = (function () {
function Person() {
var _this = this;
this.firstname = ko.observable();
this.lastname = ();
this.fullname = ko.computed(function () {
// Breakpoint here
return _this.firstname() + ' ' + _this.lastname();
});
}
return Person;
})();
This shows (as you mentioned) that "this" in your fullname computed function has been compiled to "_this". Your issue with the debugging is that Visual Studio is debugging the compiled javascript. And in javascript "this" inside the function means something else, read more about "this" in javascript here.
Typescript creates a _this reference when you use a lambda function, i.e:
class foo {
something: string = "some string";
foo1 = () => { this.something }
foo2() { this.something }
}
Compiles to:
var foo = (function () {
function foo() {
var _this = this;
this.something = "some string";
this.foo1 = function () { _this.something; };
}
foo.prototype.foo2 = function () { this.something; };
return foo;
})();
If used correctly lambda functions in typescript solves the "this" hell from javascript. In most cases you do not need to think about when to use lambdas or functions, but in some cases you do. More information about lambda functions can be found here.
The short answer for working with this is to inspect _this when working with lambdas until it is fixed. There is an open issue for it: https://typescript.codeplex.com/workitem/1655.
Well, you just stumbled on one of the hassle of JavaScript. "this is driving me crazy, but I have no idea what this is referring to". So this is not a bug, this is by design. Long story short, JavaScript rescopes this
according to the context. This is particularly problematic when using libraries such as d3 (for events callbacks) or angular, or knockout in your case. This problem becomes inherintly more obvious when using TypeScript because you have to use this
everywhere.
You can find more documentation about the use of this
on the mozilla developer network.
To circumvent your problem, the easiest solution is to keep a reference to the original this
before entering your callback, and use the local variable inside, i.e.:
class Person{
firstname = ko.observable<string>();
lastname: ko.observable<string>();
var self = this;
fullname = ko.computed(()=>{
// Breakpoint here
return self.firstname() + ' ' + self.lastname();
});
This is an habit I suggest you adopt to avoid future problems, and is kind of a good practice in JavaScript.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With