How do JavaScript runtimes implement binding functions to objects? [duplicate] - javascript

This question already has answers here:
Why parenthesis are ignored in the expression (o.method)()
(2 answers)
How does the "this" keyword work, and when should it be used?
(22 answers)
Closed 25 days ago.
I'm implementing a JavaScript interpreter, and I can't figure out the details of binding functions to objects in JavaScript.
A rudimentary example:
const o = {
x: 1,
getX: function() {
return this.x;
}
};
o.getX(); // returns 1
The tricky part is what happens when you assign getX to a variable:
let gX = o.getX;
gX(); // returns undefined
My question is: how does the runtime know that o.getX() gets bound to o, but gX() should be unbound? I would assume gX and o.getX are pointing to the exact same function!
I first thought that maybe the presence of the . is what makes the difference. So, in the grammar, there's a production like <method-call> ::= <expr> '.' ID '(' <expr>* ')', and this expression is treated differently (the result of evaluating the first <expr> is bound to the function found under ID) than a "regular" call (without a .).
But the following expression seems to disprove this theory, because (o.getX)() also returns 1. However, in some magical way, (gX = o.getX)() returns undefined, even though it's clear to me the assignment expression returns its right-hand size, so o.getX in this case!
Is there a simple explanation of how these semantics are implemented? I can't figure out a way that my runtime is supposed to differentiate that o.getX is bound to o, but gX, even though it's pointing at o.getX, is not bound.

Related

Why do people write js like this? [duplicate]

This question already has answers here:
Why does any JavaScript code want to "cut the binding"?
(1 answer)
JavaScript syntax (0, fn)(args)
(2 answers)
Closed 2 years ago.
var type = (0, _reactIs.isMemo)(nodeOrComponent) ? nodeOrComponent.type.type : nodeOrComponent.type;
(0, _reactIs.isMemo) really confuse me. What's the meaning of this?
ps: I know (0, _reactIs.isMemo) this expression's value is _reactIs.isMemo
The comma operator there ensures that what's inside the parentheses is evaluated as an expression without a calling context.
To take a shorter example, if the code was:
var type = obj.fn(someArg);
then fn would be called with a calling context of obj. But the original untranspiled code, whatever it is, does not have such a calling context, so in order to be faithful to the original code, the calling context has to be removed, which can be done with the comma operator:
var type = (0, obj.fn)(someArg);
Another way of doing the same thing would be:
var fn = obj.fn;
var type = fn(someArg);
(but that takes more characters, so minifiers prefer the comma operator version)
This is a silly-looking minification trick that's often seen with imported modules. Usually, you'd only be looking at the source code, which won't have this sillyness.

Difference between return ("abcd") and return "abcd"? [duplicate]

This question already has answers here:
Why use parentheses when returning in JavaScript?
(9 answers)
Closed 6 years ago.
I'm struggling with some JavaScript code that has examples that return a string in parens. Is there any difference between this:
var x = function() {
return "abcd";
}
And
var x = function() {
return ("abcd");
}
They are the same.
The parenthesis, i.e. grouping operator, here will just work as higher precedence, so that'll be evaluated first, and then the value will be returned.
There's no difference, at least in the way it is written.
Consider,
var x = 1 + 2;
vs
var x = (1 + 2);
Some prefer writing brackets around return statement but it is optional and often unnecessary. But I would advise stick to your existing code style.
In reference to this question the parenthesis do not have a specific meaning as a string is being returned. There is no expression evaluation involved so both the return statements work in the same way. In case we have an expression that needs to be evaluated, the parenthesis will provide a liberty to first evaluate the expression and then return the desired value according to the precedence rules.

Why does calling a method with parenthesis, eg. (obj.func)(), still set `this`? [duplicate]

This question already has answers here:
How does JavaScript determine when to give a function call a "this" context? [duplicate]
(2 answers)
Closed 8 years ago.
What exactly is the parsing rule in JS that results in the following:
Let's say we have this function
getThis = function(){
return this;
}
These all work as expected using the "previous dot" rule:
getThis(); //=> Window
obj = {getThis: getThis};
obj.getThis(); //=> obj
getThisTwo = obj.getThis;
getThisTwo(); //=> Window
However, this surprises me:
(obj.getThis)() //=> obj ...WAT
My intuition would be that it would behave exactly like the 3rd example (getThisTwo). Ie, the part in parentheses is evaluated, which returns an anonymous function, which is then invoked. My expectation then is that this would be Window, not obj.
Is this a special case, or is my understanding of how this is resolved faulty?
(Edited to make the reason for my confusion clearer)
Yes. The value of the this context of a call depends on the type of the function invocation.
In your case, it's a method invocation - a function that is called by a property reference. And yes, parentheses do not evaluate a property reference.
See also Nature of JS bound functions and function invocation operator and this very good answer for details.

There is any different between new F and new F()? [duplicate]

This question already has answers here:
Can we omit parentheses when creating an object using the "new" operator?
(6 answers)
Closed 5 years ago.
Think about the silution
function F(){}; //This is a Constructor function
Who can tell me there is any different between
var myInstance = new F;
and
var myInstance = new F();
? The new keyword execute followed Function immediately anyway whatever that is following by partheses ?
There is no difference. From the Mozilla Docs:
new constructor[([arguments])]
The parentheses are in square brackets, that means they are optional.
There is no practical difference, omitting the paranthesis can be done if no arguments are passed to simplify the grammar.
Note that some validators such as JSLint will report a warning if you leave them out though, as it is considered more consistent to always use the same syntax for invoking constructor functions regardless of arguments.
This similar example would be very bad if you get into this lazy habit:
var one = myFunc;
var two = myFunc();
These are two different variables, one is a function reference and the other is the return value of the function.

Usage of toString in JavaScript [duplicate]

This question already has answers here:
Calling member function of number literal
(3 answers)
Closed 9 years ago.
I'm reading through Douglas Crockford's JavaScript: The Good Parts, and I'm at the point where he defines a fade function. Part of this code boils down to this:
var level = 1;
var hex = level.toString(16);
So I run this in my browser's console to see what I get....
var level = 1;
level.toString(16);
Hey, it returns "1"... Fabuloso! Wunderbar!
Then to be cheeky, I try this to see what I get...
1.toString(16);
And I get
SyntaxError: Unexpected token ILLEGAL
What the what? If level is a variable equal to 1, and running this method on level works fine, then why doesn't running this method on the actual number 1 work? I tried a similar experiment with the toPrecision() method and that worked fine in both cases. What's the issue here? Is this another one of those inherent flaws in the JavaScript implementation, or am I missing something? I am testing in Google Chrome.
Related: Stack Overflow question Why don't number literals have access to Number methods?.
It's just a language grammar limitation.
Since 1. is a legal literal number (and 1.t is not) the tokeniser will split this into the following tokens:
1.
toString
(
)
And that's an illegal sequence of tokens. It's object method, instead of object . method.
In the working versions in #Joey's answer, the braces prevent the tokenizer from treating the dot as part of the number literal instead of as a separate token, as does writing:
1.0.toString()
or
1..toString()
since the tokenizer knows that the second dot must be a token on its own, and not part of the number literal.
You need 1..toString or (1).toString to get the number literal
level is a variable (and thus an object).
1 is a literal. They are not objects and the interpreter thinks about them completely differently.
http://www.cs.brown.edu/courses/bridge/1998/res/javascript/javascript-tutorial.html#4

Categories

Resources