Fat arrow function's scope and jQuery callback - javascript

Compare the following syntax:
$(elem).on('mouseenter', () => { console.log(this); })
In this case, this refers to this in parent's scope, where as in
$(elem).on('mouseenter', function() { console.log(this); })
this refers to the DOM's element. I found this article which basically says this is an expected feature. I wonder why? Is it because technically => is not a function and therefore doesn't introduce a new scope? Could someone point me to the place in the spec of the language that talks about this?
Thanks

Could someone point me to the place in the spec of the language that talks about this?
The specification is here:
See:
Let scope be the LexicalEnvironment of the running execution context.
And:
An ArrowFunction does not define local bindings for arguments, super, this, or new.target. Any reference to arguments, super, this, or new.target within an ArrowFunction must resolve to a binding in a lexically enclosing environment. Typically this will be the Function Environment of an immediately enclosing function.

Related

How is this binding resolved for arrow functions?

In an arrow function there is no this binding. So, arrow functions lexically resolve this reference. If we execute a function in different scope from where the function was defined, it remembers this reference. Does this behaviour happens due to closure ?
I know that function can remember its lexical environment by closure but in chrome developer tool this doesnot appear in closure but in local scope. Why does this happens ?
function outerScope(outerVar){
let innerFun = () =>{
console.log(outerVar);
console.log(this);
}
return innerFun;
}
let innerFun = outerScope.call({test: "testing this reference"},"outerVar");
innerFun();
Does this behaviour happens due to closure ?
No
Your statement implies it's a side-effect of other mechanisms. It is deliberately part of the specification.
Section 14.2 Arrow Function Definitions deals with the subject and 14.2.17 Runtime Semantics: Evaluation has the following note attached:
An ArrowFunction does not define local bindings for arguments, super, this, or new.target. Any reference to arguments, super, this, or new.target within an ArrowFunction must resolve to a binding in a lexically enclosing environment. Typically this will be the Function Environment of an immediately enclosing function. [...]
(the rest of the note concerns calls to super and methods)
The note is not the definition but serves as a reminder. The rason is scattered through several different places* in the spec but the most relevant is that functions have an particular internal slot that section 9.2 ECMAScript Function Objects defines as:
Internal Slot
Type
Description
[[ThisMode]]
(lexical, strict, global)
Defines how this references are interpreted within the formal parameters and code body of the function. lexical means that this refers to the this value of a lexically enclosing function. strict means that the this value is used exactly as provided by an invocation of the function. global means that a this value of undefined is interpreted as a reference to the global object.
* the "several different places" are just about arrow functions having the [[ThisMode]] internal slot set to lexical.
This is the reason arrow functions use this from the lexical binding at their definition place rather than closures having an effect.
It might also be worth noting that "closure" is ultimately not a very useful term in many cases - every function definition forms a closure. A lot of the times there the mechanism leads to nothing special, so it's not really worth discussing it. It's only interesting (and worth mentioning) when a function uses variables defined outside of it. The ones it "closes over":
const a = 42; //<--+----+
// | |
function f() {// | |
return a; // --+ |
}// |
// |
function g() { } // ----+
Both f and g will have access to the variable a because they are defined in the same environment - the mechanism for their creation does not change based on their body. This can be easily verified (you need to open the browser developer tools for the breakpoint to trigger):
const a = 42;
function f() {
return a;
}
function g() { debugger; }
g();
With that said, g is simply not worth discussing in the vast majority of cases, as the closure mechanism doesn't have an impact.

Where is the enclosing lexical scope in this code?

I do not understand why calling the logout method logs the window object, when the parent of the method is the object user. The the parent of the logout method is the user.
let user = {
name:'Jess',
age:17,
logout:()=>{
console.log(this);
}
};
user.logout()
You are capturing the this with an arrow function. Compare with this:
let user = {
name: 'Jess',
age: 17,
logout: function() {
console.log(this);
}
};
user.logout()
"the value of this is determined by how a function is called (runtime binding). It can't be set by assignment during execution, and it may be different each time the function is called. ES5 introduced the bind() method to set the value of a function's this regardless of how it's called, and ES2015 introduced arrow functions which don't provide their own this binding (it retains the this value of the enclosing lexical context)." this mdn web docs
"arrow functions don’t bind this to the object that called them. They just use the value of this in the scope in which they were defined. In this case, that’s the global object. So arrow functions are unusable for object methods." Advantages and Pitfalls of Arrow Functions

using bind method with () function javascript

I have one question, when I use bind with arrow function doesn't work so if there 's anyone can explain it to me.
let username={
email:"test#test",
login:()=>{console.log(this.email);}
};`
when i tap username.login()return undefined also if u tap username.login.bind(username) if there's anyone who can help I will be very thankful.
I m all ears for more info.
Have a read of this from MDN to understand how arrow functions deal with this differently from other functions. This, indeed, was the main reason arrow functions were introduced - they are not primarily about a "nicer" syntax, even though this seems to be how many developers today use them. (And there is nothing wrong with using them that way, but you do absolutely have to be aware of how these functions behave differently.)
As the MDN link explains, the fact that arrow functions "inherit" the this of their enclosing scope is a convenience in many common situations. But, as you have discovered, it also causes problems in cases where you rely on the value of this to be a particular object. Here is a simple demonstration of how the difference arises in your case:
let username1={
email:"test#test",
login:()=>{console.log(this.email);}
};
let username2={
email:"test#test",
login:function(){console.log(this.email);}
};
username1.login(); // logs "undefined"
username2.login(); // works as expected
The reason is because in username2, with the "ordinary" function (not an arrow function) follows the normal rules for what this means inside a function. These are too difficult to go into here (although less difficult than are often thought, and I would well advise understanding what they are) - suffice to say though that the value of this inside a function depends on how the function was called, and that usually, when you call a function as a direct property of an object, as you do with username2.login() here, this will be that object (namely username2).
But with username1.login(), the function is an arrow function, which as the MDN article explains, does not follow these standard rules. Instead the this is adopted from the enclosing scope. Here that's the global scope, not a function scope, so there isn't actually a "real" this to use - and that results in the global (window) object being chosen instead. And since window.email doesn't exist, you get undefined. As proof that this is indeed the global object, recall that window.email is one and the same as a global variable called email. So if we amend the snippet to define a global variable of that name, its value is printed instead:
var email = "this is the global email var";
let username1={
email:"test#test",
login:()=>{console.log(this.email);}
};
let username2={
email:"test#test",
login:function(){console.log(this.email);}
};
username1.login(); // logs global email variable
username2.login(); // works as expected
So that's what's happening here. (Also note that, in real code, the enclosing scope will most often not be global. But it's still quite likely that the this value of the function concerned will be the global object, and even if it isn't, you'll still see undefined printed here unless that particular object happens to have an email property defined.)
The moral of the story is not to use arrow functions for object methods - because any reference to this inside them will not behave as you likely expect. In fact my personal reference is not to use arrow functions at all unless you either need their specific modification of the this rules, or if you need a "throwaway" one-line anonymous function (for example as a function argument to an array's map or filter), in which case the arrow function can make the code more readable. But increased readability and brevity is not the main reason arrow functions exist.
Arrow function is always called with the context in which it was defined. Just use a normal function.
let username={
email:"test#test",
login: function() {console.log(this.email);}
};`
Take a look at ECMAScript 2015 Spec:
Any reference to arguments, super, this, or new.target within an ArrowFunction must resolve to a binding in a lexically enclosing environment. Typically this will be the Function Environment of an immediately enclosing function.

What does `Reflect.construct`'s `newTarget` argument do when it is normally impossible? [duplicate]

The ECMAScript 2015 specification mention the keyword (or words?) new.target exactly 3 times - 1 time in 14.2.3:
Normally, Contains does not look inside most function forms However,
Contains is used to detect new.target, this, and super usage within an
ArrowFunction.
and twice in 14.2.16:
An ArrowFunction does not define local bindings for arguments, super,
this, or new.target. Any reference to arguments, super, this, or
new.target within an ArrowFunction must resolve to a binding in a
lexically enclosing environment
MDN mentions it, but is very vague and the page is incomplete.
Babel doesn't seem to support it. I got syntax errors when trying to use new.target in a function (arrow or others).
What is it, and how is it supposed to be used?
You didn't find it in the spec because in the syntax definitions it is written with blanks, as new . target. The name of the expression is NewTarget, and you'll find that term a few times around.
NewTarget is the first of the so-called meta properties and can be found in §12.3.8.
Its sole purpose is to retrieve the current value of the [[NewTarget]] value of the current (non-arrow) function environment. It is a value that is set when a function is called (very much like the this binding), and according to §8.1.1.3 Function Environment Records:
If this Environment Record was created by the [[Construct]] internal method, [[NewTarget]] is the value of the [[Construct]] newTarget parameter. Otherwise, its value is undefined.
So, for one thing, finally enables us to detect whether a function was called as a constructor or not.
But that's not its real purpose. So what is it then? It is part of the way how ES6 classes are not only syntactic sugar, and how they allow us inheriting from builtin objects. When you call a class constructor via new X, the this value is not yet initialised - the object is not yet created when the constructor body is entered. It does get created by the super constructor during the super() call (which is necessary when internal slots are supposed to be created). Still, the instance should inherit from the .prototype of the originally called constructor, and that's where newTarget comes into the play. It does hold the "outermost" constructor that received the new call during super() invocations. You can follow it all the way down in the spec, but basically it always is the newTarget not the currently executed constructor that does get passed into the OrdinaryCreateFromConstructor procedure - for example in step 5 of §9.2.2 [[Construct]] for user-defined functions.
Long text, maybe an example is better suited:
class Parent {
constructor() {
// implicit (from the `super` call)
// new.target = Child;
// implicit (because `Parent` doesn't extend anything):
// this = Object.create(new.target.prototype);
console.log(new.target) // Child!
}
}
class Child extends Parent {
constructor() {
// `this` is uninitialised (and would throw if accessed)
// implicit (from the `new` call):
// new.target = Child
super(); // this = Reflect.construct(Parent, [], new.target);
console.log(this);
}
}
new Child;
It's primarily intended as a better way to detect when a constructor is called without new.
From http://www.2ality.com/2015/02/es6-classes-final.html:
new.target is an implicit parameter that all functions have. It is to constructor calls what this is to method calls.
So I can write:
function Foo() {
if (!new.target) throw "Foo() must be called with new";
...
}
There are more details to how this works, and more contexts in which it is useful, but we'll leave it here.
For some meeting notes regarding new.target, see https://esdiscuss.org/notes/2015-01-27.

The opposite of lexical this

This is a question about terminology.
Considering that there is a method that uses lexical this:
var foo = {
method: function () {
console.log(this, ' is the context');
}
};
foo.method();
What's the conventional term for this when the method is called when being bound to different context or detached?
bazThatAcceptsACallback(foo.method);
foo.method.bind(baz)();
(0, foo.method)();
I often refer to it as 'non-lexical this' or 'contextual this' in such cases, but I never met these or similar terms in official or trusted sources.
The opposite of lexical this is dynamic this.
However, notice that lexical this is not what you have shown in your function snippet, it's the this that arrow functions have.
You don't need different terms to describe the behavior of JS lexical this for what it is referring to. Its always the "context" the function is called in. Let it be the parent object or another binding - you can always say the lexical this represent the context.

Categories

Resources