In the following code, why can I access the variable x.b? Shouldn't it have a local scope?
CODE
function x() {
var a = 3;
}
x.b = 8;
console.log(x.a);
console.log(x.b);
OUTPUT
undefined
8
When you use var to declare a within x's constructor, a is mark as private, however when you do x.b you are essentially saying - add the property b to the object x.
Hence when you do x.b, technically speaking you are accessing object x's property b, which is 8.
Javascript considers x.b as a global object. so you can access it even inside the function like:
x.b = 8;
function x() {
var a = 3;
alert(x.b)
}
x();
console.log(x.a);
console.log(x.b);
But make sure you specify x.b before function declaration.
whereas object a is specified inside the function x() which makes it private thats why you are getting undefined result for console.log(x.a);
if you write it like this:
a = 5;
function x() {
var a = 3;
}
x.b = 8;
alert(a);
alert(x.b);
you will get results as bellow:
5
8
for javascript a and x.a are two separate objects.
You have defined x.b to 8 and it becomes a global var. Which means you can access it from anywhere.
So the x() is a function which has its own scope. So you can't access the vars inside a function scope in the mentioned way. However you can access the 'a' by doing this and calling the x function.
function x() {
var a = 3;
return a;
}
Related
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;
function emergency() {
var ambulance = 100;
var callAmbulance = function() { alert(ambulance); }
ambulance++;
return callAmbulance;
}
var accident = emergency();
accident(); // alerts 101
I am referring to the variable 'ambulance'.
When I call accident(); it should call emergency() which should use the declared variable 'ambulance' [considering the global scope thing in javascript, still it could set the value to global] but its using old value 101 instead of setting again back to 100 - behaving more like static var.
What's the Explanation?
What you have there is called a closure. It means a function can access variables declared in outer functions (or in the global scope). It retains access even after the 'parent' function has returned. What you need to understand is that you don't get a copy. The changes performed on that variable are visible to your inner function, which in theory means you could have multiple functions sharing access to the same variable.
function f () {
var x = 0;
function a() { x += 1; }
function b() { x += 2; }
function show() { console.log(x); }
return {a:a, b:b, show:show};
}
var funcs = f();
funcs.a();
funcs.b();
funcs.show(); // 3
One thing to be aware of is that a subsequent call to f will create a new scope. This means a new x variable will be created (new a, b, show functions will be created as well).
var newFuncs = f();
newFuncs.a();
newFuncs.show(); // 1
funcs.a();
funcs.show(); // 4
So, how do you get a copy? Create a new scope.
function g () {
var x = 0;
var a;
(function (myLocal) {
a = function () { myLocal += 1; }
}(x));
x += 200;
return a;
}
JS only has pass-by-value so when you call the anonymous function, the xvariable's value will be copied into the myLocal parameter. Since a will always use the myLocal variable, not x, you can be certain that changes performed on the x variable will not affect your a function.
If, by any chance, you're coming from a PHP background you are probably used to do something like
use (&$message)
to allow modifications to be reflected in your function. In JS, this is happening by default.
You are creating a function definition which is not compiled at this time:
var callAmbulance = function() { alert(ambulance); }
And before you are sending it to the called function, you are incrementing the num:
ambulance++;
And then you are sending it to the called function:
return callAmbulance;
But whether you are sending it there or not, it doesn't matter. The below statement executes or compiles the function:
var accident = emergency();
And this takes in the current ambulance value which is 101 after the increment. This is an expected behaviour in creating function but not executing it. Please let me know, if you didn't understand this behaviour. I will explain it more clearly.
I thought any variable defined in a function would be local but I can easily access variable 'e' outside of its function.
function change() {
var d = 6;
e = 7;
}
change();
alert(e); //> alerts 7
Because new variables will enter the global scope by default. var prevents this from happening by constraining a variable's existence to be within the current scope.
Because it was declared without var it becomes part of the global window object.
You've not explicitly declared it as such, so it has taken global scope.
Thats because e is global by default, using var make a scope varible.
You can read more about this in Javascript Garden Scope and Namespaces
I am guessing that you are going under this assumption that
JSLint expects that a var will be
declared only once, and that it will
be declared before it is used.
Problem with your code is you are using one var, but your second line has no var in front of it. That is pushing that varaible e into the global namespace.
Why is it happening? You used a semicolon instead of a comma in the variable declaration.
function change() {
var d = 6, //Change this to a comma
e = 7;
}
change();
alert(e); //will produce an error now
It is surprisingly easy to create global variables, here are some other gotchas I've seen.
// :-( antipattern: implied global variable
function sum(x, y) {
result = x + y; // result is global
return result;
}
// :-) better
function sum(x, y) {
var result = x + y; // result is local
return result;
}
// :-( antipattern: chain assignments as part of a var declaration
function foo() {
var a = b = 0; // b is global
}
// :-) better
function foo() {
var a, b;
a = b = 0; // both local
}
Is there a way to change the root object in JavaScript?
For example, in browsers, the root object is "window". So
X = 5;
console.log(Y);
is the same as:
window.X = 5;
console.log(window.Y);
What I want to do now, is changing this root object, so when I do the following:
X = 6;
Reason why I need this:
In Node.js applications, every part of the program can access the global object. That's a big problem because every script that is executed by a Node.js webserver can add new variables to it. They will be there until the webserver is restarted. I want to avoid this by changing the global object.
Update
I've tested the following code and got a really interesting result.
What did you expect of the following code?
var X = {A:"a",B:"b"};
with(X){
A = 5;
C = 7;
}
for(a in X){
console.log(a+" is "+X[a]);
}
/*
Expected Console Output:
A is 5
B is b
C is 7
Real Console Output:
A is 5;
B is b;
*/
Is there a way to get output as I expected it?
Update
I've now tested the module system with the following code.
//program.js
var t = require("./module.js");
t.Test();
console.log(A);
//module.js
A = 5;
exports.Test = function(){
console.log("hello world!");
}
The output was:
hello world!
5
This tells me, that the variable "A" defined in module.js was added to the global object of program.js. The module does not solve my problem, either.
There is the with statement, but it is not recommended and forbidden in strict mode.
It is better to refer to the variable holding the object explicitly.
In response to updated question:
with will search up the scope chain until it finds an object with a matching property or gets to window. It is no good for defining new properties on an object.
var X = { A: 5, B: 8, C: 7};
with(X){
console.log(A, B, C);
}
If you're talking about variables, JavasScript has function scope.
X = 5; // global variable
console.log( window.X ); // 5
(function() {
var X = 6; // declare a local variable by using the "var" keyword
console.log( X ); // 6
})();
console.log( window.X ); // 5
Otherwise, you can create an Object, and add properties to it.
X = 5;
console.log( window.X ); // 5
var obj = {};
obj.X = 6;
console.log( obj.X ); // 6
console.log( window.X ); // 5
EDIT: Adding another possible solution that could be used.
You could invoke an anonymous function, but set the context of the function to your X object. Then this in the function will refer to X.
var X = {};
(function(){
this.A = 5;
this.B = 8;
this.C = 7;
}).call(X);
for(a in X){
console.log(a+" is "+X[a]);
}
The .call() method (as well as the .apply() method) allow you to explicitly set the thisArgof a calling context. The first argument you pass will be howthis` is defined in the context of the invocation.
Or just pass X in as an argument.
var X = {};
(function(X){
X.A = 5;
X.B = 8;
X.C = 7;
})(X);
for(a in X){
console.log(a+" is "+X[a]);
}
Though the simplest is to simply reference it (as I noted in my answer above).
var X = {};
X.A = 5;
X.B = 8;
X.C = 7;
for(a in X){
console.log(a+" is "+X[a]);
}
or use a module pattern:
/****** I'm guessing at the use of "global" here ********/
global.myNamespace = (function(global,undefined) {
// define the object to be returned
var X = {};
// define private local variables
var a_local = 'some value';
var another_local = 'some other value';
// define private functions
function myFunc() {
// do something with local variables
}
// give the return object public members
X.someProperty = 'some value';
X.anotherProperty = 'another value';
X.publicFunc = function() {
//do something with the local variables
// or public properties
};
X.anotherFunc = function() {
//do something with the local variables
// or public properties
};
// return the object
return X;
})(global);
console.log(myNamespace);
I found a way in EcmaScript 6 to adjust with(context) { ... }, so that any new variables we assign will go into the context object, not the global / window object.
Thanks to this article Metaprogramming in ES6: Part 3 - Proxies for teaching me about the ES6 Proxy feature.
In the proxy:
We override has to return true, so our context appears to have all properties, and when we set any variable it will go to the object.
We override get to get the property from our context, or if it isn't really there, we get the property from an up object (which defaults to the global window).
I know that with is frowned upon, but this technique enables to create mutable extensible modules where we can access members conveniently as foo rather than Module.foo, and I don't think it is unsafe or ambiguous.
function scope(x, up=window) {
return new Proxy(x, {
has: (o, k) => true,
get: (o, k) => k in o ? o[k] : up[k]
});
}
var Test = {};
with (scope(Test)) {
x = 1;
y = 2;
add_x = function(y) {
console.log(x + y);
}
}
Test.add_x(10);
with (scope(Test)) {
x = 3;
add_y = function(x) {
console.log(x + y);
}
}
Test.add_x(20);
Test.y = 5;
Test.add_y(30);
So when I declare a variable outside the scope of any function, it becomes a property of the window object. But what about when I declare a variable inside the scope of a function? For example, in the following code I can treat x as a property of window, i.e., window.x, but what about y? Is it ever the property of an object?
var x = "asdf1";
function test() {
var y = "asdf2";
}
test();
It becomes a property of the Variable object associated with the function call. In practice, this is the same thing as the function call's Activation object.
I don't believe that the Variable object is accessible to running JavaScript code, though; it's more of an implementation detail than something you can take advantage of.
Access all local variables is a related question here on SO.
In order to declare a JS variable a property of an object you need to either use the new Object(); method or the {} syntax.
var variableName = new Object();
var variableName = {myFirstProperty:1,myNextProperty:'hi',etc};
Then you can assign child objects or properties to said variable object
variableName.aPropertyNameIMadeUp = 'hello';
variableName.aChildObjectNameIMadeUp = new Object();
As such the new variable object is associated with a method if it is within the method call.
Cheers
See following example (I have copy from other question-answer) very nice:
// a globally-scoped variable
var a=1;
// global scope
function one(){
alert(a);
}
// local scope
function two(a){
alert(a);
}
// local scope again
function three(){
var a = 3;
alert(a);
}
// Intermediate: no such thing as block scope in javascript
function four(){
if(true){
var a=4;
}
alert(a); // alerts '4', not the global value of '1'
}
// Intermediate: object properties
function Five(){
this.a = 5;
}
// Advanced: closure
var six = function(){
var foo = 6;
return function(){
// javascript "closure" means I have access to foo in here,
// because it is defined in the function in which I was defined.
alert(foo);
}
}()
// Advanced: prototype-based scope resolution
function Seven(){
this.a = 7;
}
// [object].prototype.property loses to [object].property in the scope chain
Seven.prototype.a = -1; // won't get reached, because 'a' is set in the constructor above.
Seven.prototype.b = 8; // Will get reached, even though 'b' is NOT set in the constructor.
// These will print 1-8
one();
two(2);
three();
four();
alert(new Five().a);
six();
alert(new Seven().a);
alert(new Seven().b);