What is going on with JavaScript scope here? [duplicate] - javascript

This question already has answers here:
Why does shadowed variable evaluate to undefined when defined in outside scope?
(6 answers)
Closed 9 years ago.
I've written the following snippet of code:
var f = function() { document.write("a"); };
function foo() {
f();
var f = function() { document.write("b"); };
}
foo();
I expected the function that prints a to be called, but it instead gives a runtime error about calling an undefined value. Why does this happen?

It's about variables hoisting http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html , http://net.tutsplus.com/tutorials/javascript-ajax/quick-tip-javascript-hoisting-explained/
You code is eqvivalent to the next one;
var f = function() { document.write("a"); };
function foo() {
//all var statements are analyzed when we enter the function
var f;
//at this step of execution f is undefined;
f();
f = function() { document.write("b"); };
}
foo();

Since (just like in java) you don't have to worry about the order you define things in in a file a certain situation occurs. When you redefine the variable f it blanks out the other version of f but it is not defined until after so when f is called you get an error.

Related

What reason is there to give a JS function a name if you can't use it? [duplicate]

This question already has answers here:
Why use named function expressions?
(5 answers)
Closed 4 years ago.
Consider the following snippet:
let myFunc = function foo() {
console.log('whatever');
}
myFunc(); // 'whatever'
foo(); // ReferenceError
What reason is there to give this function a name if you can't use it?
A named function is to call itself with this given name. The name can not changed later.
For example this function is calling itself only two times.
let myFunc = function foo() {
console.log('whatever');
foo.count = (foo.count || 0) + 1;
if (foo.count < 3) foo();
}
myFunc();

TDZ in undeclared variables of function parameters [duplicate]

This question already has an answer here:
Scope of Default function parameters in javascript
(1 answer)
Closed 4 years ago.
When I try to run the foo function defined in this snippet I get a ReferenceError since b is not defined.
var b = 3;
function foo( a = 42, b = a + b + 5 ) {
// ..
}
foo()
This looks like a TDZ error because b has been defined in the outer scope but it's not yet usable in the function signature as a right-hand-side value.
This is what I think the compiler should do:
var b;
function foo(..) { .. }
// hoist all functions and variables declarations to the top
// then perform assignments operations
b = 3;
foo();
//create a new execution environment for `foo`
// add `foo` on top of the callstack
// look for variable a, can't find one, hence automatically create a
`var a` in the local execution environment and assign to it the
value `42`
// look for a `var b` in the global execution context, find one, use
the value in it (`3`) as a right-hand-side value.
This shouldn't raise a ReferenceError. Looks like this is not what happens here.
Can someone explain in what actually does the compiler do and how it processes this code?
On every function call, the engine evaluates some prologue code, which contains formal parameters, declared as let vars and initialized with their actual values or default expressions, if provided:
var b = 3;
function foo( ) {
let a = <actual param for a> OR 42;
let b = <actual param for b> OR a + b + 5;
// ..
}
Since b in a function is lexical (let), it's not possible to access its value before initialization. Hence the ReferenceError.
Note that this is a call-time error, so the following compiles fine:
var b = 1
function foo(b=b) {
console.log(b)
}
The error happens when you actually call the function:
var b = 1
function foo(b=b) {
console.log(b)
}
foo()
and only when the engine actually evaluates the faulty default expression:
var b = 1
function foo(b=b) {
console.log(b)
}
foo(7)
ECMA standard reference: FunctionDeclarationInstantiation, p.21:
For each String paramName in parameterNames, do
...Perform ! envRec.CreateMutableBinding(paramName, false).
The function arguments somewhat works like 'let'.
We cannot access variable created using 'let' before they are declared .i.e variables created using 'let' are not hoisted.
This happens because if the we are declaring the variable in local scope , it cannot access the global scope variable(Unless 'this' is used )
Your code can be fixed by this -
var b = 3;
function foo( a = 42, b = a + this.b + 5 ) {
// default binding. In this case this.b = global var
}
foo()
you can also see this error if you do this.
let variable = variable;

Typescript method doesnt work well with event handler [duplicate]

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
How does the "this" keyword work, and when should it be used?
(22 answers)
Closed 4 years ago.
Consider this simple TS script
class foo {
v: number = 1;
public bar() {
console.log(this.v);
}
}
var a = new foo();
var b = new foo();
document.getElementById('test').addEventListener("click", a.bar);
document.getElementById('test').addEventListener("click", b.bar);
and the HTML
<html lang="en">
<body>
<button id="test">Test</button>
</body>
</html>
I would expect to get 2 lines console output of number "1".
But NO! I get one undefined output
Lets take a look at the generated js file
var foo = (function () {
function foo() {
this.v = 1;
}
foo.prototype.bar = function () {
console.log(this.v);
};
return foo;
}());
var a = new foo();
var b = new foo();
document.getElementById('test').addEventListener("click", a.bar);
document.getElementById('test').addEventListener("click", b.bar);
//# sourceMappingURL=Test.js.map
For performance consideration TS decided to put the function on the prototype! so the addEventListener call was actually adding the prototype (static) function twice and its the same instance. That's why I'm only getting one output instead of two.
And the biggest issue is that the this inside the prototype function refers to the button and button doesn't contain a property called v!
If we do this in native js
var foo = function () {
this.v = 1;
var that = this;
this.bar = function () {
console.log(that.v);
}
}
var a = new foo();
var b = new foo();
document.getElementById('test').addEventListener("click", a.bar);
document.getElementById('test').addEventListener("click", b.bar);
we would get the desire result!
Is this a known issue for TS where you can't use the class method as event handler?
And how can I remove that handler after I added it?
You can. Just do:
document.getElementById('test').addEventListener("click", () => a.bar());

When does a function get terminated with }; [duplicate]

This question already has answers here:
Why should I use a semicolon after every function in javascript?
(9 answers)
Closed 7 years ago.
Ok, I asked a question, and someone smarter than me said the question was an "exact" duplicate of mine. Well it wasn't, and the answers did not answer the guy's question. He wanted to know how to call another procedure, I want to know how to call a function within the class. That being said when I was trying to find an answer to my problem and I was looking at answers to similar questions sometimes function were terminated with }; other times with } and still other times with }, (this one I think I understand). However I cannot see in rhyme or reason why or when the brace with a semicolon is to be used and when just the brace should be used:
Here was the first answer
var ExampleClass = function(){
this._m_a = null;
};
ExampleClass.prototype.get_m_a = function(){
return this._m_a;
};
ExampleClass.prototype.set_m_a = function(value){
this._m_a = value;
};
notice this answer doesn't even address the calling of another routine! However the functions are terminated with a }; (Why?)
Here is another answer:
var M_A = function()
{
var m_a; //private variable
this.get = function()
{
return m_a;
}
this.set = function(value)
{
m_a = value;
RunFunction(); //run some global or private function
this.runPublic(); // run a public function
}
}
This guy kinda answers the question but all of the functions are terminated with a } with no semicolon following (Why?)
Finally the answer is unsatisfactory, What is a global or private function? and what is a public function? Why does the public function refer to "this". Anyhow I am probably the village idiot but I still do not know how to call a function I have defined in the class from within the class, and I don't know whether the termination of functions inside a class should be with a }; or just a }. So I have now spent almost 12 hours trying to get one little class to work in javascript to no avail.
Two things are tripping you up.
The first one is the difference between function declarations and function values.
This is a function declaration:
function foo() {
// ...
}
These are function values:
var bar = function() {
// ...
};
var bar = function foo() {
// ...
};
baz(function() {
// ...
});
Function declarations do not need semicolons. Function values are not full statements; full statements do need them (sometimes). It is important to note that in these last three examples, the semicolon does not terminate the function, it terminates the var statement and the function evaluation statement.
This "(sometimes)" is the second point where you have a problem: in JavaScript, a semicolon will be automatically inserted at newline if it is obvious to the interpreter that it should be there.
So,
x = 5
y = 6
is identical to
x = 5;
y = 6;
Thus,
var bar = function() {
// ...
}
is identical to
var bar = function() {
// ...
};
But look at this:
var bar = function() { /* ... */ }; console.log(bar);
is okay (all needed semicolons are there);
function bar() { /* ... */ } console.log(bar);
is also okay, since the function declaration statement does not need a semicolon. However,
var bar = function() { /* ... */ } console.log(bar);
is an error, as the variable assignment statement cannot be separated properly from the function invocation statement. Note that due to automatic semicolon insertion, this works:
var bar = function() { /* ... */ }
console.log(bar);
EDIT: There is a semantic difference between a function declaration statement and assigning a function value to a variable: function declaration statements are executed first (this is called "function hoisting"), while assignments are, as all assignments, executed in order:
function pre_fn() {}
var pre_var = function() {};
pre_fn(); // works
pre_var(); // works
post_fn(); // works
post_var(); // error (not defined yet)
function post_fn() {}
var post_var = function() {};
EDIT2:
I suspect that the class that you were unable to create (as said in comments, code in the question would have been better than speculation) had an object literal form:
var Foo = {
bar: function() {
// ...
},
baz: function() {
// ...
}
};
Here, the semicolon terminates the var Foo = { /* ... */ } statement. You can't have semicolons inside it, for the same reason you can't write
var foo = { a = 6; b = 7 }
because the syntax of the object literal mandates that you separate the key-value pairs with commas. There is no difference here between the numeric value 6, and the function value function() { /* ... */ }; neither "terminates" with a semicolon.

Expression contains parentheses only. Function argument after } [duplicate]

This question already has answers here:
What is the (function() { } )() construct in JavaScript?
(28 answers)
Closed 9 years ago.
I got so confused here. Can someone help me peel the layers off the function definition here? What are the out-most parentheses for? Why argument (p) can be after }, and which function is it for? Where is q required at all? Why can p directly call publish() later?
var p = {};
(function(q) {
q.publish = function(topic, data){
...
};
}(p));
...
p.publish("inbox", "hello");
It simply creates the function and executes it immediately.
For example:
var foo = function() {
return 5;
}();
console.log(foo);
will print 5.
If you want to learn more about it, please read this excellent article http://benalman.com/news/2010/11/immediately-invoked-function-expression/
I would like to quote module pattern example from the link I shared.
var counter = (function(){
var i = 0;
return {
get: function(){
return i;
},
set: function( val ){
i = val;
},
increment: function() {
return ++i;
}
};
}());
console.log(counter.get());
counter.set(3);
console.log(counter.increment());
console.log(counter.i);
Output
0
4
undefined
Here we are dynamically creating an Object at the same time we are making i private. This is called closure property.
Putting the function in parentheses means the JS interpreter takes it as a function expression, so it can be anonymous (i.e., not have a declared name). Adding () at the end means the function is called immediately. So, e.g.:
(function() {
alert('Hi');
}());
...declares a really simple function with no arguments, and calls it immediately. A slightly more complicated one with an argument might look like this:
(function(someArgument) {
alert(someArgument);
}('Hi'));
That would alert 'Hi', because the string 'Hi' is passed to the anonymous function when it is called.
So with that as background, here's what your code is doing line by line:
var p = {}; // declare variable p, referencing an empty object
(function(q) { // make an anonymous function expression that takes one argument, q
q.publish = function(topic, data){ // add a property 'publish' to whatever q is,
... // where 'publish' is a function that takes
}; // two arguments
}(p)); // call the anonymous function, passing p in
...
p.publish("inbox", "hello"); // call the method 'publish' that was added to p
The q argument that you asked about takes the value from p, so it refers to the same empty object, but then it adds the .publish() method to that object.
This general concept is called an "Immediated invoked function expression", or IIFE.
Usually if an IIFE is just sitting there by itself like that (i.e., another variable is not assigned equal to it) it is done so that working variables/functions can be created temporarily without adding them to the global scope, because in JavaScript the scope options are basically global or function. The code you show doesn't do that, but here's a simple example:
(function() {
var x = 0;
for (var i = 0; i < 100; i++)
x += i;
alert (x);
}());
// here x and i are not accessible because they're local to the function above.
It's a self executing function. Using q is useless here since q === p.
var p = 'hello';
function f(q){ return q; }; f(p); // "hello"
(function(q){ return q; }(p)); // "hello"
(function(){ return p; }()); // "hello"
/*(*/function(){ return p; }()/*)*/; // SyntaxError: Unexpected token (
This pattern is usually used to create a private context for variables. Here is a well known example :
var counter = function(){
var i = 0;
return function(){
return ++i;
};
}();
counter(); // 1
counter(); // 2
i; // undefined
Have a look at this great article : http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html.

Categories