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);
Related
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;
}
I want to pass a function reference "go" into another function "redefineFunction", and redefine "go" inside of "redefineFunction". According to Johnathan Snook, functions are passed by reference, so I don't understand why go() does not get redefined when I pass it into redefineFunction(). Is there something that I am missing?
// redefineFunction() will take a function reference and
// reassign it to a new function
function redefineFunction(fn) {
fn = function(x) { return x * 3; };
}
// initial version of go()
function go(x) {
return x;
}
go(5); // returns 5
// redefine go()
go = function(x) {
return x * 2;
}
go(5); // returns 10
// redefine go() using redefineFunction()
redefineFunction(go);
go(5); // still returns 10, I want it to return 15
Or see my fiddle http://jsfiddle.net/q9Kft/
Pedants will tell you that JavaScript is pure pass-by-value, but I think that only clouds the issue since the value passed (when passing objects) is a reference to that object. Thus, when you modify an object's properties, you're modifying the original object, but if you replace the variable altogether, you're essentially giving up your reference to the original object.
If you're trying to redefine a function in the global scope: (which is a bad thing; you generally shouldn't have global functions)
function redefineFunction(fn) {
window[fn] = function() { ... };
}
redefineFunction('go');
Otherwise, you'll have to return the new function and assign on the calling side.
function makeNewFunction() {
return function() { ... };
}
go = makeNewFunction();
Nothing is "passed by reference" in JS. There are times that references are passed, but they're passed by value. The difference is subtle, but important -- for one thing, it means that while you can manipulate a referenced object pretty much at will, you can't reliably replace the object (read: alter the reference itself) in any way the caller will see (because the reference was passed by value, and is thus merely a copy of the original reference; attempting to reassign it breaks in the same way it would if the arg were a number or string).
Some cowboys will assume you're redefining a global function and mess with it by name to get around the limitations of pass-by-value, but that will cause issues the second you decide not to have globals all over the place.
The real solution: return the new function, and let the caller decide what to do with it. (I'd argue that redefining functions right out from under the code that uses them is a pretty bad design decision anyway, but eh. I guess there could be a reason for it...)
Snook is wrong. And I don't think it's pedantic at all (#josh3736 :) to point out that EVERYTHING in JavaScript is pass by value. The article by Snook gets this COMPLETELY wrong. Passing a primitive and passing an object work the exact same way. These are equivalent:
var x = 2;
var y = x;
y = 3; //x is STILL 2.
function stuff(y){
y = 3; //guess what. x is STILL 2
}
stuff(x);
///////////////////
var x = {stuff: 2};
var y = x;
y = {stuff: 3}; //x.stuff is STILL 2
function stuff(y){
y = {stuff: 3}; //guess what. x.stuff is STILL 2
}
stuff(x);
This is important. Java, C#, and MOST languages work this way. That's why C# has a "ref" keyword for when you really do want to pass something by reference.
You can't modify the variable from inside the function, so the quick fix is to return the value and assign it outside the function, like this
// log() just writes a message to the text area
function log(message) {
$('#output').val($('#output').val() + message + "\n");
}
// redefineFunction() will take a function reference and
// reassign it to a new function
function redefineFunction() {
newvalue = function(x) { return x * 3; };
return newvalue;
}
// initial version of go()
function go(x) {
return x;
}
log(go(5)); // returns 5
// redefine go()
go = function(x) {
return x * 2;
}
log(go(5)); // returns 10
// redefine go() using redefineFunction()
go = redefineFunction();
log(go(5)); // returns 10, I want it to return 15
I believe functions are 'passed in by value'. If you put log(f(5)); inside your redefineFunction function it will output 15, but 10 when you call log(go(5)) afterwards.
If you change redefineFunction to return the function and then assign it to go (go = redefineFunction()) it will work as you expect.
This is equivalent to asking if you can redefine any variable by passing it as an argument to some function. No. You can reassign it by, uhh, reassigning it. In this case, if you make redefineFunction return a function, you can simply assign it to go:
function redefineFunction() {
var fn = function(x) { return x * e; };
return fn;
}
function go(x) {
return x;
}
go = redefineFunction();
go(5); // return 15
This is working in firefox:
function redefineFunction(fn) {
window[fn] = function(x) {
return x * 3;
}
};
function go(x) {
return x;
};
alert(go(5));
go=function(x) {
return x * 2;
}
alert(go(5));
redefineFunction('go');
alert(go(5));
The secret is that a global function called go also is called window.go and window["go"].
This can also be used at styles: element.style["overflow"] = "hidden", and in attributes:
element["value"] = "hello there".
This is a very useful knowlege.
Why dont use a object? something like this:
var o = {
go: function( x ) {
return x;
},
redefineFunction: function ( fn ) {
if (typeof fn === 'function') {
this.go = fn;
}
}
}
console.log(o.go(5)); // return 5
var fn = function (x) {
return x * 2;
};
o.redefineFunction(fn);
console.log(o.go(5)); //return 10
Hope it helps!
I've been told that javascript variables should all come before they are used in a function, such that:
function contrived() {
var myA, myB;
myA = 10;
myB = 20;
return myA + myB;
}
Is prefered over:
function furtherContrivance() {
var myA = 10;
var myB = 20;
return myA + myB;
}
Is this the case? And why is that?
I guess some people might prefer the former style because that's how it works inside. All local variables exist for the entire lifetime of the function, even if you use var to declare them in the middle of the function.
There's nothing wrong with declaring variables later in the function, syntax-wise, it might just be confusing as the variables will then exist before the line that declares them. Hence this function:
function bar() {
alert(foo); // Alerts "undefined". Not an error because the variable does exist.
var foo = 10;
alert(foo); // Alerts the value 10.
}
Is equivalent to this:
function bar() {
var foo;
alert(foo);
foo = 10;
alert(foo);
}
Another related fact is that nested function definitions (done using function foo() { ... }) will get moved to the top of the containing function as well, so they will be available even if the code that calls them comes before them.
Yes, the variable declaration should come at the top of the function:
function foo() {
var a, b;
}
However, initializing variables can be part of the declaration:
function foo() {
var a = 10, b = 20;
}
The reasoning behind declaring all variables at the top of the function where they are used is to avoid scope confusion.
Here is an example of bad code:
function foo() {
var b;
for (var i = 0; i < 5; i++) {
var a;
a = b = i;
setTimeout(function(){
console.log(a, b);
}, 1000);
}
}
If you execute the code, it will log 4, 4 5 times, rather than counting up. This is because only functions act as closures and introduce new scope. In JavaScript, any var declaration within a function gets executed at the beginning of the function.
This makes the above error much more visible:
function foo() {
var a, b, i;
for (i = 0; i < 5; i++) {
a = b = i;
setTimeout(function(){
console.log(a, b);
}, 1000);
}
}
There is no difference in this case between this two. I'd go with:
function furtherContrivance() {
var myA = 10,
myB = 20;
return myA + myB;
}
which is knows as single var pattern in javascript.
What you really need to take care of is defining your variables in the beginning of your functions. There is a thing in javascript called variables hoisting which means that variable definitions used in function "raise" on top. It's best described by an example:
var x = 'global'; // global (bounded to a global object which is window in browsers)
function func() {
alert(x); // undefined (you expected 'global', right?)
var x = 'local';
alert(x); // local
}
func();
what really happens is called (as I said) variables hoisting (definition of x raises on top), so the code above is actually the same as:
var x = 'global';
function func() {
var x; // definition of `x` raised on top (variables hoisting)
alert(x); // undefined in a local scope
x = 'local';
alert(x);
}
What a javscript interpreter does is it looks inside a function, gathers locally defined variables and raises them on top - this might be a good reason why you should use single var pattern.
In the example you give this is absolutely not the case. In a language like Javascript, it will be more of a developer preference, but it won't have any impact on the result.
Yes, place them at the top. It adds to code clarity.
Try this example:
var x = 1;
(function() {
x++;
alert( x ); // What will this alert show?
var x = 'done';
alert( x );
})();
Looks like it should alert 2, but it alerts NaN.
This is because the variable declaration is hoisted to the top, but the initialization stays in the same place.
So what is actually happening is:
var x = 1;
(function() {
var x;
x++;
alert( x ); // What will this alert show? NaN
x = 'done';
alert( x );
})();
...which makes the NaN expected.
For readability, it's definitely preferred.
However, Javascript "hoists" declarations. Hoisting means that vars and functions will be automatically moved to the top of their scope. This allows you to do things such as use a function before it's declared:
function myScope()
{
test();
function test()
{
//...
}
}
This can lead to some confusion, especially if variables within block scopes are declared. For example:
for(var i in foo)
{
var e = myFunc();
}
The declaration of e will be hoisted to the top of the closure, and e will be initialized to undefined. This allows for some interesting non-intuitive situations, such as:
if(!foo) //Will not throw reference error because foo is declared already
{
var foo = {};
}
So, regardless of how you declare your variables, they'll all get "moved up" to the top of the function anyway.
Hope this helps!
Is it possible to somehow pass the scope of a function to another?
For example,
function a(){
var x = 5;
var obj = {..};
b(<my-scope>);
}
function b(){
//access x or obj....
}
I would rather access the variables directly, i.e., not using anything like this.a or this.obj, but just use x or obj directly.
The only way to truly get access to function a's private scope is to declare b inside of a so it forms a closure that allows implicit access to a's variables.
Here are some options for you.
Direct Access
Declare b inside of a.
function a() {
var x = 5,
obj = {};
function b(){
// access x or obj...
}
b();
}
a();
If you don't want b inside of a, then you could have them both inside a larger container scope:
function container() {
var x, obj;
function a(){
x = 5;
obj = {..};
b();
}
function b(){
// access x or obj...
}
}
container.a();
These are the only ways you're going to be able to use a's variables directly in b without some extra code to move things around. If you are content with a little bit of "help" and/or indirection, here are a few more ideas.
Indirect Access
You can just pass the variables as parameters, but won't have write access except to properties of objects:
function a() {
var x = 5,
obj = {};
b(x, obj);
}
function b(x, obj){
// access x or obj...
// changing x here won't change x in a, but you can modify properties of obj
}
a();
As a variation on this you could get write access by passing updated values back to a like so:
// in a:
var ret = b(x, obj);
x = ret.x;
obj = ret.obj;
// in b:
return {x : x, obj : obj};
You could pass b an object with getters and setters that can access a's private variables:
function a(){
var x = 5,
obj = {..},
translator = {
getX : function() {return x;},
setX : function(value) {x = value;},
getObj : function() {return obj;},
setObj : function(value) {obj = value;}
};
b(translator);
}
function b(t){
var x = t.getX(),
obj = t.getObj();
// use x or obj...
t.setX(x);
t.setObj(obj);
// or you can just directly modify obj's properties:
obj.key = value;
}
a();
The getters and setters could be public, assigned to the this object of a, but this way they are only accessible if explicitly given out from within a.
And you could put your variables in an object and pass the object around:
function a(){
var v = {
x : 5,
obj : {}
};
b(v);
}
function b(v){
// access v.x or v.obj...
// or set new local x and obj variables to these and use them.
}
a();
As a variation you can construct the object at call time instead:
function a(){
var x = 5,
obj = {};
b({x : x, obj: obj});
}
function b(v){
// access v.x or v.obj...
// or set new local x and obj variables to these and use them.
}
a();
Scope is created by functions, and a scope stays with a function, so the closest thing to what you're asking will be to pass a function out of a() to b(), and that function will continue to have access to the scoped variables from a().
function a(){
var x = 5;
var obj = {..};
b(function() { /* this can access var x and var obj */ });
}
function b( fn ){
fn(); // the function passed still has access to the variables from a()
}
While b() doesn't have direct access to the variables that the function passed does, data types where a reference is passed, like an Object, can be accessed if the function passed returns that object.
function a(){
var x = 5;
var obj = {..};
b(function() { x++; return obj; });
}
function b( fn ){
var obj = fn();
obj.some_prop = 'some value'; // This new property will be updated in the
// same obj referenced in a()
}
what about using bind
function funcA(param) {
var bscoped = funcB.bind(this);
bscoped(param1,param2...)
}
No.
You're accessing the local scope object. The [[Context]].
You cannot publicly access it.
Now since it's node.js you should be able to write a C++ plugin that gives you access to the [[Context]] object. I highly recommend against this as it brings proprietary extensions to the JavaScript language.
You can't "pass the scope"... not that I know of.
You can pass the object that the function is referring to by using apply or call and send the current object (this) as the first parameter instead of just calling the function:
function b(){
alert(this.x);
}
function a(){
this.x = 2;
b.call(this);
}
The only way for a function to access a certain scope is to be declared in that scope.
Kind'a tricky.
That would lead to something like :
function a(){
var x = 1;
function b(){
alert(x);
}
}
But that would kind of defeat the purpose.
As others have said, you cannot pass scope like that. You can however scope variables properly using self executing anonymous functions (or immediately executing if you're pedantic):
(function(){
var x = 5;
var obj = {x:x};
module.a = function(){
module.b();
};
module.b = function(){
alert(obj.x);
};
}());
a();
I think the simplest thing you can do is pass variables from one scope to a function outside that scope. If you pass by reference (like Objects), b has 'access' to it (see obj.someprop in the following):
function a(){
var x = 5;
var obj = {someprop : 1};
b(x, obj);
alert(x); => 5
alert(obj.someprop); //=> 'otherval'
}
function b(aa,obj){
x += 1; //won't affect x in function a, because x is passed by value
obj.someprop = 'otherval'; //change obj in function a, is passed by reference
}
You can really only do this with eval. The following will give function b function a's scope
function a(){
var x = 5;
var obj = {x};
eval('('+b.toString()+'())');
}
function b(){
//access x or obj....
console.log(x);
}
a(); //5
function a(){
this.x = 5;
this.obj = {..};
var self = this;
b(self);
}
function b(scope){
//access x or obj....
}
function a(){
var x = 5;
var obj = {..};
var b = function()
{
document.println(x);
}
b.call();
}
Have you tried something like this:
function a(){
var x = 5;
var obj = {..};
b(this);
}
function b(fnA){
//access x or obj....
fnA.obj = 6;
}
If you can stand function B as a method function A then do this:
function a(){
var x = 5;
var obj = {..};
b(this);
this.b = function (){
// "this" keyword is still === function a
}
}
First question
var obj = function(){
var a = 0;
this.b = 0;
}
Is there any difference in behaviour of a and b?
Second question
var x = 'a';
var f1 = function(x){ alert(x) }
var f2 = new Function('alert('+x+')')
Is there any difference in behaviour of f1 and f2
Question 1
var obj = function() {
var a = 0;
this.b = 0;
}
Within the function, you'll be able to access both variables, but in the case of
var x = new obj();
... you'll be able to access x.b, but not x.a.
Question 2
As your question is written at the moment, it is a syntax error. The following will work:
var x = 'a';
var f1 = function(x){ alert(x) }
var f2 = new Function('alert('+x+')')
... but that would be the same thing as writing:
var x = 'a';
var f1 = function(x){ alert(x) }
var f2 = new Function('alert(a)')
The difference here is obvious. f1 disregards the global variable x and alerts whatever is passed to it, while f2 also disregards the global variable x, and tries to look for a global variable a. This is probably not what you're trying to ask about.
What you probably want is something like this:
var x = 'a';
var f1 = function(){ alert(x) }
var f2 = new Function('alert(x)')
... or this:
var f1 = function(x){ alert(x) }
var f2 = new Function('x', 'alert(x)')
The difference between the two alternatives above is that the first always uses the global variable x, while the second never uses any global variable. The difference between f1 and f2, internally, in both examples, is none at all.
These are two ways of generating the exact same result. The only reason you'd ever want to use the f2 approach would be when generating the code in some dynamic manner that require string input for its definition. In general, try to avoid this practice.
var obj = function() { // function expression, while obj is created before head
// it's only assigned the anonymous function at runtime
var a = 0; // variable local to the scope of this function
this.b = 0; // sets a property on 'this'
}
Now what this is depends on how you're calling the function.
Also note the difference between function statements and expressions.
var x = 'a'; // string a, woah!
var f1 = function(x){ alert(x) } // another anonymous function expression
// Does not work
// 1. it's "Function"
// 2. It gets evaluated in the global scope (since it uses eval)
// 3. It searches for 'a' in the global scope
var f2 = new function('alert('+x+')') // function constructor
In short, never use the Function constructor, it will never inherit local scope and therefore you can't use closures with it etc.
First question:
var obj = function() {
var a = 0;
this.b = 0;
}
instance = new obj();
instance.showA = function() {
alert("this.a = " + this.a);
}
instance.showB = function() {
alert("this.b = " + this.b);
}
instance.showA(); // output undefined - local scope only, not even to methods.
instance.showB(); // output 0 - accessible in method
Paste this in your Firebug console and run to see the output and behavior for yourself.
Second question:
var f2 = new function('alert('+x+')');
This throws a syntax error in Firebug because the f should be capitalized. This is a case where a function is defined inside a string and evaluated. Here is a good example:
var x = 'a=3';
var f2 = new Function('alert('+x+')');
f2(); // outputs 3 because the x passed into the variable is evaluated and becomes nested inside the quotes prior to the alert command being fired.
Here is what the substitution process looks like:
1: x = "a=3";
2: 'alert(' + x + ')');
3: 'alert(' + 'a=3' + ')'); // x replaced with a=3
4: 'alert(a=3)';
5: 'alert(3);'
When function runs, alert(3) is fired. This can be used to execute other JavaScript pulled down from a remote server, although extreme care should be used for security reasons. When evaluating code that is nested in quotes, it helps to start from the inside and work your way up to the top level context. More information on dealing with nested quotes or embedded code can be found here: http://blog.opensourceopportunities.com/2007/10/nested-nested-quotes.html
Question 1: homework on scoping of variables (var b is local to the enclosing {} (local to the function in this case).
Question 2: Instead of using the Function constructor you could use eval? http://www.w3schools.com/jsref/jsref_eval.asp , as in
eval 'alert('+x+')';
Second question is VERY interesting. Only benchmarks can say the truth.
http://jsperf.com/function-vs-function/
http://jsperf.com/function-vs-function/1..8
http://jsperf.com/function-vs-constructor-vs-eval
http://jsperf.com/function-vs-constructor-vs-eval/1..5
It looks they are almost equal? I can see in modern browsers each variant is optimized enough
BUT BE AWARE OF RECREATING THE FUNCTION IN A LOOP!
http://jsperf.com/function-vs-function/2
Any wise comments?