TS/JS arrow function changing value of `this`? - javascript

Using TypeScript v1.7.5, the context of this appears to be getting confused, or perhaps not transpiled correctly. Or I'm missing something. Inside of an arrow function, this is changing, when I expected it to still refer to the same this as outside the function. I've debugged the situation and the outcome is indicated in comments below.
Source TS
// Debug: "this" is an instance of the class -- good.
FS.exists(dbPath, (exists: boolean) => {
// Debug: "this" is an instance of the global object -- not good.
...
});
Resulting JS (ES5)
FS.exists(dbPath, function (exists) {
...
});
I was expecting the resulting JS to bind the callback as follows:
FS.exists(dbPath, function (exists) {
...
}.bind(this));
I need to preserve the value of this inside the callback, hence I'm using arrow functions throughout my code. But I'm confused as to why this doesn't appear to be working correctly.
Note
If, and only if, I specifically attempt to use this within the arrow function, then TypeScript creates this workaround:
var _this = this;
FS.exists(dbPath, function (exists) {
var _x = this;
});
Okay, fine, but wouldn't it have been better to use bind? This still doesn't fix the problem of me calling functions from within the arrow function. Those function calls will lose the context of this, which is not the appropriate behavior.

This looks like the desired behavior by the Typescript compiler.
ES6 fat arrow functions => don't actually bind this. Instead, this actually falls through to the upper scope. Same with arguments, which you can't use inside a fat arrow function, because they will fall through to the upper scope.
So, binding all the time would be incorrect behavior according to the spec. And it would be an undesired behavior to always reference this from the parent scope inside a function if you aren't using it. This looks like correct optimization on the part of the TypeScript compiler.

Related

Passing event listener a reference to "self";

I just wanted to know if its acceptable to save a reference to "this" as a variable and then use that in an eventListener. If not can someone please inform as to the best practice for passing reference to a different context in javascript.
Example:
someListener(){
let self = this; //referencing this class
someObject.addEventListener("click"), function(){
//some magic applied here
self.someArray.push("something");
}
}
I cant think of another way to reference a different context (that of the class that the event listener belongs to) when dealing with an event.
Thanks
That's fine, and highly idiomatic ES5 (using the name that is also common).
ES6 gives us arrow functions which use a lexical this instead of having their own.
someListener(){
someObject.addEventListener("click"), () => {
//some magic applied here
this.someArray.push("something");
}
}
Before arrow functions were introduced, this was a common way among javascript developers but now you can get around this problem using an arrow function
someListener(){
someObject.addEventListener("click"), () => {
this.someArray.push("something");
}
}
Using an arrow function solves this problem because arrow functions do not get their own binding of this. They get their value from the enclosing scope, which in your case is the local scope of someListener function.

Having trouble understanding the dynamics of this vs self vs nothing.

Consider the following chunk of code:
function Bar() {
var _self = this;
this.addPin = function (param1) {
console.log('addPin');
}
function endPin(param1) {
console.log('endPin');
}
_self.addPin(1);
this.addPin(1);
addPin(1); // failse
endPin(2);
this.endPin(2); // fails
}
var foo = new Bar();
foo.addPin(1); // works
foo.endPin(1); // does not work
From what I understand from playing with this code, the function declaration of endPin effectively makes it a private method to any outside callers. While this.methodHere type of declaration makes it a public method.
What I am not clear on is the usage of this in the class itself. this refer to the instance of the class. Why, in that case, can't I use this.endPin inside the class. Conversely, why do I have to use this.methodHere syntax when referring to addPin (which was declared using this.methodHere syntax).
Finally the difference between this and _self - I've read that _self preserves the original state of the class (or this). How does it do that if it's a reference supposedly pointing to the same memory location? How is this different from _self in this particular example?
You have asked a lots of questions here, so lets try and break them down.
this refer to the instance of the class. Why, in that case, can't I
use this.endPin inside the class.
Because endPin is not part of the class, it a local function inside your constructor.
Conversely, why do I have to use this.methodHere syntax when referring
to addPin (which was declared using this.methodHere syntax).
Because addPin is part of the class, basically the reverse of the first question. Doing func() does not automatically call the function of class.
How is this different from _self in this particular example?
In this case it's not, but if you used _self inside your local function, it would capture scope so it's still pointing to this of the class, instead of the functions scope.
You can't use the this.endPin because the function is not defined in the class itself but inside a function.
If you write:
function Bar() {
// do whatever
this.endPin(2); // now it should work
}
function endPin(param1) {
console.log('endPin');
}

In the following example of React ES6, how is it possible for an object property referenced w/o the 'this.state'?

I pulled this example from a tutorial I was following. I am perplexed with the situation where the selectedGif property is able to refer to "selectedGif" w/o "this.state" as required by other property references such as "this.state.gifs." Is that rule an exception when an arrow function is applied?
The onGifSelect inline event handler is not referencing selectedGif from this.state.
It is being passed an anonymous function written using ES6 arrow function notation.
So:
selectedGif => this.openModal(selectedGif)
is nearly equivalent to:
function(selectedGif) {
return this.openModal(selectedGif);
}
// NB: Using the latter to invoke `openModal` will THROW AN ERROR
// because `onModal` is invoked within the inline event handler
// '`onGifSelect`' and **not** the component scope/context.
// The result is that the `this` within `onModal` refers to the
// inline event and not the component context `this` where `setState` exists.
There are a couple of ways to get around the above issue:
using .bind()
OR
Using the arrow function (=>) syntax remedies this because:
arrow functions do not create their own scope/context so invoking this.setState within openModal will work as expected.
It's not referencing this.state.selectedGif. It kind of looks like it, but it's just referencing a variable in an anonymous function that could have gone by any other name. The above code would behave precisely the same written like
onGifSelect={foo => this.openModal(foo)}
aka
onGifSelect={(function(foo) { this.openModal(foo) }).bind(this)}
But this function isn't making any use of its argument rather than pass it along. It would be better written as
onGifSelect={this.openModal}
without the extra wrapping function that only serves to retain the surrounding context. Would be better to bind the function in the constructor or use class arrow notation if you have stage-2 enabled https://github.com/tc39/proposal-class-public-fields

JavaScript examples, clarify the langue pattern design for functions with-in functions

I am learning JavaScript and becoming confused by the logic of the code examples. From codecademy. Why are there function set-ups in function calls?
I'm quite confused. I am moving from a simplified C-like langue.
The JavaScript example
var main = function(){
$('.article').click(function(){
$('.description').hide();
$(this).children('.description').show();
});
};
My understanding:
- main is a function name with a return type of var.
$('.article') is a element/object/or class object.
.click() is a call to a member function
But:
???:
.click(function(){
$('.description').hide();
$(this).children('.description').show();
});
This seems to be a newly on the spot created function to run When/If click() is activated or run.
The way I used to think is like this:
var *p_obj = $('.article');
var *p_obj = $('.description');
var do_click()
{
p_obj2.hide();
p_obj.children(p_obj2).show();
}
var main(){
p_obj.click(do_click);
}
Function main() looks at p_obj and calls click().
Click() evaluates to true/false and run the pointer_to function do_click().
Function do_click() looks at the p_obj2 and calls hide(), which performs an action of hiding the p_obj2.
Function do_click() also looks at p_obj and uses children to scope focus to p_obj2, then it runs show(), which preforms an action of displaying p_obj2.
I do realize my C-like example is wrong and odd. I realize my terminology is wrong or otherwise used incorrectly.
The way this design looks seems like I must write extended functionality on-the-spot for every call to .click(), so if-then .click() is run on 3 different items, I'm creating different extended functionality for each object. But I would normally create a single function that varies it's internal execution based on the object or condition click() calls it by.
This set-up seems alright if the code a relatively simple or short, but on-the-spot functional seems like overworking for longer code and code where the functionality repeats but the objects change.
Am I thinking about JavaScript functions with-in functions correctly and is this a design goal of the langue to add long repeating extended functions with-in functions?
Here, you should understand 2 things:
passing functions as arguments
anonymous functions
The first concept is particulary important because callbacks are popular in JavaScript, so let me explain it for callbacks. Imagine we have 2 functions getStuffFromWeb and processStuff. You probably expect that they are used like this:
var result = getStuffFromWeb();
processStuff(result);
But the issue here is waiting for getStuffFromWeb may take some time (the server is busy), so instead they are usually used in a "when you finish, call this function" manner, which is:
var getStuffFromWeb = function(params,callback) {
...
callback(result);
};
getStuffFromWeb(someParams,processStuff);
Well, in fact the structure of getStuffFromWeb will be different, most likely something like this:
var getStuffFromWeb = function(params,callback) {
requestObject.make_request(params)
.onSuccess(callback);
};
So when getStuffFromWeb is called, it starts to listen to response while the code after getStuffFromWeb(someParams,processStuff); goes on evaluating. When the response comes, it calls the callback function to process the data further using the procedure we have defined (processStuff).
The second concept is rather simple: you may of'course write smth like
var processStuff = function() {...};
var getStuffFromWeb = function(params,callback) {
requestObject.make_request(params)
.onSuccess(callback);
};
getStuffFromWeb(someParams,processStuff);
but if you use processStuff only once, why define a named function? Instead, you can just put the very same expression inside the onSuccess param like this:
var getStuffFromWeb = function(params) {
requestObject.make_request(params)
.onSuccess(function() {...});
};
getStuffFromWeb(someParams);
This looks exactly like if we took the value of processStuff and put it directly to the onSuccess's argument (and that's called anonymous function). And also we got rid of an extra argument of getStuffFromWeb.
So basically that's it.
Simple answer is that the second argument of click() requires a callback function.
This can be a named function passed as reference as in your p_obj.click(do_click); example or it can be an anonymous function with self contained logic. Anonymous functions are very common in javascript
It's the same thing just with 2 different ways of declaring the callback.
Note that the only time you would return anything from an event handler function would be to return false which effectively prevents the default browser event (url opening from href or form submit for examples) and stops event propagating up the DOM tree
main is a function name with a return type of var.
No. main is a variable which is assigned an anonymous function. The function name would go between the keyword function and the () containing the argument list.
It has no return statement so it returns undefined.
$('.article') is a element/object/or class object.
It is a call to the function $ with one argument. The return value is a jQuery object.
.click() is a call to a member function
Pretty much. In JavaScript we call any function that is the value of a property of an object as method.
This seems to be a newly on the spot created function
function () { } is a function expression. It creates a function, exactly like the one used to assign a value to main earlier. This question is worth reading for more on the subject.
When/If click() is activated or run.
The click function is called immediately. The new function is passed as an argument.
The purpose of the click function is to bind a click event handler so that when a click event hits the element later on, it will trigger the function passed as an argument.
I do realize my c -like example is wrong and odd. I realize my terminology is wrong or otherwise used incorrectly.
Leaving aside vagaries of syntax. The main difference here is that the click event handler function is that the event handler function is stored in an intermediary variable.
You can do that in JavaScript just as easily, and then reuse the function elsewhere in the code.
var main = function(){
function show_specific_description() {
$('.description').hide();
$(this).children('.description').show();
}
$('.article').click(show_specific_description);
show_specific_description.call($(".article").last()[0]);
};
main();
is this a design goal of the langue to add long repeating extended functions with-in functions?
No. Passing a function expression as an argument is a convenient way to be more concise when you don't want to reuse the function. It's not the only way to pass functions about.
main is currently a function.
It is possible to be overwritten (even to a different type). var is not the return type, it's a statement that main is a variable.
All values should be declared as variables, within the highest scope you intend them to be used (in JS, scope typically means functions, not blocks).
You have the right idea, suspecting that the function gets passed in, and called at a later point in time (and this is actually one of the harder parts for people to get, coming from certain other languages). You'll see this behaviour all through JS.
One key thing to keep in mind in this language (you haven't hit it yet, but you will) is that JS is lexically scoped.
function getInnerX () {
var x = 5;
function getX () {
return x;
};
return getX;
}
var x = 10;
var getX = getInnerX();
console.log(getX()); // 5
The function getX inside of getInnerX has access to the references around it, at the point where it's defined (not where it's called), and thus has live access to the inner x, even if its value changes over time.
This will be another important piece of understanding what you see going on in the language, especially in the case of callbacks.

What's the scope of javascript named function, passed as parameter

I've work with some framework & even wrote some libraries for my own purpose. I now working at implementation of an AngularJs router... And looked again at DI of angular:
[...String, Function]
function.$inject
For long I've been using the first syntax. Now while testing my router, I wanted to see the behaviour if it differs for both syntaxes and how to handle this, but...
First Hand
module.controller(function SampleController()
{
});
// Since it's and `invokelater...` function which is called right away,
SampleController.$inject = [/** my component dependencies **/]
See my face when I faced:
ReferenceError: SampleController is not defined
The Other Hand
I consider it unclean to write:
function SampleController()
{
}
SampleController.$inject = [];
moddule.$inject = [];
So Finally
I know it won't work. Why? - That's my question.
Why?
We have been taught that module, class, method/functions, some for loop, if...else create new scope.
Never have I read something like:
function's parameters are evaluated in their own scope
Please Tell Me
Thanks!
Named function expressions only create a matching variable in their own scope (which is useful for calling the function recursively).
They create nothing in the scope of the function that holds them.
When you pass it as a function argument, then the variable you pass it into is scoped to the function call. i.e. function function_you_pass_the_function_to(someFunction) { } scopes the someFunction variable to itself.

Categories