Set the scope of an eval - javascript

Is there a way to set the global of an eval? I would like to set the global of an eval so I don't have to prefix everything with obj.
If I do the following, I get an error
ReferenceError: MyClass is not defined
let obj = {
MyClass: class MyClass {
static CallMe() {}
}
}
eval(`
'use strict';
global = obj;
result = MyClass.CallMe();
`)
However, If I do this:
result = obj.MyClass.CallMe();
It works, but I would like to make it so I don't have to prefix the call with obj. Is there any why that this can be done?

I can't imagine why you need to use eval here, but if you do, you can use with (obj) in your evaluated code:
eval(`
'use strict';
with (obj) {
result = MyClass.CallMe();
}
`);
I still feel like you shouldn't be using eval here (what use is it?), as it's easy to accidentally open yourself to injection vulnerabilities if you're not careful. What are you using eval for here? Maybe we can point out a better way.

Others have warned you already about the risks of using evalso I won't be doing that myself.
I certainly found some legitimate use cases for eval in a controlled environment. I am assuming that you know what you're doing.
This may or may not be useful:
let obj1 = {
foo: () => console.log('scope: obj1')
};
let obj2 = {
foo: () => console.log('scope: obj2')
};
const scopedEval = (context, code) =>
new Function('global', code)(context, code);
scopedEval(obj1, `
global.foo();
`)
scopedEval(obj2, `
global.foo();
`)

Have no idea why you'd like to use eval, especially in such weird way but this might be something that you are looking for:
class MyClass {
static CallMe() {
return 'sample';
}
}
eval(`
'use strict';
let result = MyClass.CallMe();
console.log(result);
`)

Related

Use of const in a Javascript class

In my JS component class, I have the following code at the top;
const {
getOwner
} = Ember;
What exactly does it mean ? Is the purpose to avoid code repetition ?
This is a new feature of JS present in ES6.
This is known as object destructure.
If you have an object like this.
const obj = { name: 'Stack Overflow' };
const { name } = obj;
console.log(name);
You can take a reference ->
Here for Destructure
And yeah about the const keyword.
The const keyword is used to declare a constant variable which is going to be same for the whole
and for const -> Here
try{
const a = 10;
a =12;
}catch(e){
console.log(e);
}
Is the purpose to avoid code repetition.
I don't really think so.
It is just a destructing assignment to assign Ember object's getOwner property to variable getOwner in your code. And const is there to make sure it is not overwritten by some other assignment

How to check that ES6 "variable" is constant?

Does anyone know some tricks how to do it? I tried to use try-catch:
"use strict";
const a = 20;
var isConst = false;
try {
var temp = a; a = a+1; a = temp;
} catch (e) {
isConst = true;
}
But unfortunately it works only in "strict" mode. Without "use strict" it perform all statements silently, without modification of a. Also I cannot wrap this code into some handy function (isConstant(someConst) for example) as any argument I'll pass to that function will be a new variable. So anyone know how to create isConstant() function?
I don't think there is, but I also don't think this is a big issue. I think it might be useful to have the ability to know if a variable is const, and this exists in some other languages, but in reality since you (or someone on a team) will be defining these variables, you'd know the scope and the type of the variables. In other words, no you can't, but it's also not an issue.
The only case where it might be useful is if you could change the mutable property during runtime, and if changing this property had actual performance benefits; let, const, and var are treated roughly equally to the compiler, the only difference is that the compiler keeps track of const and will check assignments before it even compiles.
Another thing to note is that just like let, const is scoped to the current scope, so if you have something like this:
'use strict';
const a = 12;
// another scope
{
const a = 13;
}
it's valid. Just be careful that it will look up in higher scopes if you don't explicitly state const a = 13 in that new scope, and it will give a Read Only or Assignment error:
'use strict';
const a = 12;
{
a = 13; // will result in error
}
Based on some of the answers here I wrote this code snippet (for client side JS) that will tell you how a "variable" was last declared--I hope it's useful.
Use the following to find out what x was last declared as (uncomment the declarations of x to test it):
// x = 0
// var x = 0
// let x = 0
// const x = 0
const varName = "x"
console.log(`Declaration of ${varName} was...`)
try {
eval(`${varName}`)
try {
eval(`var ${varName}`);
console.log("... last made with var")
} catch (error) {
try {
eval(`${varName} = ${varName}`)
console.log("... last made with let")
} catch (error) {
console.log("... last made with const")
}
}
} catch (error) {
console.log("... not found. Undeclared.")
}
Interestingly, declaring without var, let or const, i.e x = 0, results in var getting used by default. Also, function arguments are re-declared in the function scope using var.
Just check if your reassignment actually did something:
var isConst = function(name, context) {
// does this thing even exist in context?
context = context || this;
if(typeof context[name] === "undefined") return false;
// if it does exist, a reassignment should fail, either
// because of a throw, or because reassignment does nothing.
try {
var _a = context[name];
context[name] = !context[name];
if (context[name] === _a) return true;
// make sure to restore after testing!
context[name] = _a;
} catch(e) { return true; }
return false;
}.bind(this);
You need the try/catch because reassign Could throw an exception (like in Firefox), but when it doesn't (like in Chrome), you just check whether your "this always changes the value" reassignment actually did anything.
A simple test:
const a = 4;
var b = "lol";
isConst('a'); // -> true
isConst('b'); // -> false
And if you declare the consts in different context, pass that context in to force resolution on the correct object.
downside: this won't work on vars declared outside of object scopes. upside: it makes absolutely no sense to declare them anywhere else. For instance, declaring them in function scope makes the const keyword mostly useless:
function add(a) {
return ++a;
}
function test() {
const a = 4;
console.log(add(a));
}
test(); // -> 5
Even though a is constant inside test(), if you pass it to anything else, it's passed as a regular mutable value because it's now just "a thing" in the arguments list.
In addition, the only reason to have a const is because it does not change. As such, constantly recreating it because you're calling a function that makes use of it more than once, means your const should live outside the function instead, so again, we're forced to put the variable in an object scope.
The question refers to incompliant behaviour in earlier ES6 implementations, notably V8 (Node.js 4 and legacy Chrome versions). The problem doesn't exist in modern ES6 implementations, both in strict and sloppy modes. const reassignment should always result in TypeError, it can be caught with try..catch.
There can't be isConstant function because const variable cannot be identified as such by its value.
It's preferable to run a script in strict mode and thus avoid problems that are specific to sloppy mode.
Even if a variable was defined in sloppy mode, it's possible to enable strict mode in nested function scope:
const foo = 1;
// ...
let isConst = false;
(() => {
'use strict';
try {
const oldValue = foo;
foo = 'new value';
foo = oldValue;
} catch (err) {
isConst = true;
}
})();
It's beneficial to use UPPERCASE_CONSTANT convention which is used in JavaScript and other languages. It allows to unambiguously identify a variable as a constant without aid from IDE and avoid most problems with accidental reassignments.

replacing eval in privately scoped variables

I'm trying to remove the eval statement in this function. I'm used to the this[whatever] style replacement but it doesn't work out in this instance.
Have a look:
var App = (function(fw) {
var somevar1 = "hello";
var somevar2 = "world";
this.get = function(what) {
return eval(what);
}
});
var app = new App({some: "thing"});
// now for the use:
console.log(app.get("somevar1"),app);​
In the function, all my normal "eval scrubbing" options are not working for instance, I cant use:
return this[what]
return [what]
return app[what]
return new Function(what);
surely this isn't an odd case where eval is necessary? .. ps I have to note that I CANNOT rescope the variables inside App as it's part of a huge codebase.
Here's something to fiddle with:
http://jsfiddle.net/xAVYa/
Unfortunately, you're out of luck; eval is the only thing that can access variables like that. Next time, don't do things that way :)
You can start a migration by keeping a data object:
var App = (function(fw) {
var data = {
somevar1: "hello",
somevar2: "world"
};
this.get = function(what) {
return data[what];
};
});
And just gradually do this across the entire codebase where you see it. It shouldn't break anything.
You cannot access an arbitrary local variable by string name without eval. So, unless you're willing to change how those variables are accessed by other code inside of the app function, you will have to stick with eval (as ugly as it seems).
If, on the other hand, you're willing to change the code inside of the app() function that accesses somevar1 and somevar2, then you have options. Note, you shouldn't have to change anything outside the app() function because you can keep the same contract for the .get() function so this isn't one of those arbitrarily hard to find all possible places everywhere in the project that might be accessing these variables. Because of the way they are currently declared, they can only be accessed directly from inside the app() function so your search/replace would be limited to that scope.
If it's OK for the variables to be properties of your object, you could do this:
var app = function(fw) {
this.somevar1 = "hello";
this.somevar2 = "world";
this.get = function(what) {
return this[what];
}
};
var app = new App({some: "thing"});
// now for the use:
console.log(app.get("somevar1"));​
console.log(app.somevar1);
console.log(app["somevar1"]);
There isn’t a dynamic way to do this without eval. If the variables aren’t changing, though, you could try something like this:
var App = (function(fw) {
var somevar1 = "hello";
var somevar2 = "world";
this.get = function(what) {
switch (what) {
case "somevar1":
return somevar1;
case "somevar2":
return somevar2;
}
}
});

Where to declare class constants?

I'm using class members to hold constants. E.g.:
function Foo() {
}
Foo.CONSTANT1 = 1;
Foo.CONSTANT2 = 2;
This works fine, except that it seems a bit unorganized, with all the code that is specific to Foo laying around in global scope. So I thought about moving the constant declaration to inside the Foo() declaration, but then wouldn't that code execute everytime Foo is constructed?
I'm coming from Java where everything is enclosed in a class body, so I'm thinking JavaScript might have something similar to that or some work around that mimics it.
All you're doing in your code is adding a property named CONSTANT with the value 1 to the Function object named Foo, then overwriting it immediately with the value 2.
I'm not too familiar with other languages, but I don't believe javascript is able to do what you seem to be attempting.
None of the properties you're adding to Foo will ever execute. They're just stored in that namespace.
Maybe you wanted to prototype some property onto Foo?
function Foo() {
}
Foo.prototype.CONSTANT1 = 1;
Foo.prototype.CONSTANT2 = 2;
Not quite what you're after though.
You must make your constants like you said :
function Foo() {
}
Foo.CONSTANT1 = 1;
Foo.CONSTANT2 = 2;
And you access like that :
Foo.CONSTANT1;
or
anInstanceOfFoo.__proto__.constructor.CONSTANT1;
All other solutions alloc an other part of memory when you create an other object, so it's not a constant. You should not do that :
Foo.prototype.CONSTANT1 = 1;
IF the constants are to be used inside of the object only:
function Foo() {
var CONSTANT1 = 1,CONSTANT2 = 2;
}
If not, do it like this:
function Foo(){
this.CONSTANT1=1;
this.CONSTANT2=2;
}
It's much more readable and easier to work out what the function does.
If you're using jQuery, you can use $.extend function to categorize everything.
var MyClass = $.extend(function() {
$.extend(this, {
parameter: 'param',
func: function() {
console.log(this.parameter);
}
});
// some code to do at construction time
}, {
CONST: 'const'
}
);
var a = new MyClass();
var b = new MyClass();
b.parameter = MyClass.CONST;
a.func(); // console: param
b.func(); // console: const
First, I recommend moving your class declaration inside of an IIFE. This cleans up the code, making it more self-contained, and allows you to use local variables without polluting the global namespace. Your code becomes:
var Foo = (function() {
function Foo() {
}
Foo.CONSTANT1 = 1;
Foo.CONSTANT2 = 2;
return Foo;
})();
The problem with assigning constants directly to the class as attributes is that those are writable. See this snippet:
var output = document.getElementById("output");
var Foo = (function() {
function Foo() {
}
Foo.CONSTANT1 = 1;
Foo.CONSTANT2 = 2;
return Foo;
})();
Foo.CONSTANT1 = "I'm not very constant";
output.innerHTML = Foo.CONSTANT1;
<div id="output"></div>
The best solution I have found is to define read-only properties for accessing the constants outside of the class.
var output = document.getElementById("output");
var Foo = (function() {
const CONSTANT1 = "I'm very constant";
function Foo() {
}
Object.defineProperty(Foo, "CONSTANT1", {
get: function() {
return CONSTANT1;
},
});
return Foo;
})();
Foo.CONSTANT1 = "some other value";
output.innerHTML = Foo.CONSTANT1;
<div id="output"></div>
(Technically you could ditch the const CONSTANT1 statement and just return the value from the property definition, but I prefer this because it makes it easier to see all the constants at a glance.)
what you are doing is fine (assuming you realize that your example is just setting the same property twice); it is the equivalent of a static variable in Java (as close as you can get, at least without doing a lot of work). Also, its not entirely global, since its on the constructor function, it is effectively namespaced to your 'class'.
Your constants are just variables, and you won't know if you try and inadvertently overwrite them. Also note that Javascript lacks the notion of "class".
I'd suggest you create functions that return values that you need constant.
To get the taste of Javascript, find Javascript: the Good Parts and learn the idiomatic ways. Javascript is very different from Java.
Also with namespaces
var Constants = {
Const1: function () {
Const1.prototype.CONSTANT1 = 1;
Const1.prototype.CONSTANT2 = 2;
},
Const2: function () {
Const2.prototype.CONSTANT3 = 4;
Const2.prototype.CONSTANT4 = 3;
}
};
You said your coming from Java - why don't you store that class in 1 file then and constants at the end of the file. This is what I use:
filename: PopupWindow.js
function PopupWindow() {
//private class memebers
var popup, lightbox;
//public class memeber or method (it is the same in JS if I am right)
this.myfuncOrmyMemeber = function() {};
}
//static variable
PopupWindow._instance = null;
//same thing again with constant-like name (you can't have "final" in JS if I am right, so it is not immutable constant but its close enough ;) - just remember not to set varibales with BIG_LETTERS :D)
PopupWindow.MY_CONSTANT = 1;
//yea, and same thing with static methods again
PopupWindow._getInstance = function() {};
So only difference is the position of static stuff. It is not nicly aligned inside class curly braces, but who cares, its always ctrl+click in IDE (or I use ctr+l to show all class methods - IntellijIdea can do that in JS dunno how about other IDEs) so your not gonna search it by your eye ;)
Yea and I use _ before static method - it is not needed, I don't know why I started to do that :)

Writing a Javascript library that is code-completion and code-inspection friendly

I recently made my own Javascript library and I initially used the following pattern:
var myLibrary = (function () {
var someProp = "...";
function someFunc() {
...
}
function someFunc2() {
...
}
return {
func: someFunc,
fun2: someFunc2,
prop: someProp;
}
}());
The problem with this is that I can't really use code completion because the IDE doesn't know about the properties that the function literal is returning (I'm using IntelliJ IDEA 9 by the way).
I've looked at jQuery code and tried to do this:
(function(window, undefined) {
var myLibrary = (function () {
var someProp = "...";
function someFunc() {
...
}
function someFunc2() {
...
}
return {
func: someFunc,
fun2: someFunc2,
prop: someProp;
}
}());
window.myLibrary = myLibrary;
}(window));
I tried this, but now I have a different problem. The IDE doesn't really pick up on myLibrary either.
The way I'm solving the problem now is this way:
var myLibrary = {
func: function() { },
func2: function() { },
prop: ""
};
myLibrary = (function () {
var someProp = "...";
function someFunc() {
...
}
function someFunc2() {
...
}
return {
func: someFunc,
fun2: someFunc2,
prop: someProp;
}
}());
But that seems kinda clunky, and I can't exactly figure out how jQuery is doing it. Another question I have is how to handle functions with arbitrary numbers of parameters.
For example, jQuery.bind can take 2 or 3 parameters, and the IDE doesn't seem to complain. I tried to do the same thing with my library, where a function could take 0 arguments or 1 argument. However, the IDE complains and warns that the correct number of parameters aren't being sent in. How do I handle this?
EDIT
I'm starting to wonder if this is an Idea9 issue because jQuery has the same problem. I don't seem to have this problem in other projects though.
I'm using IDEA with yahoo module pattern and my autocomplete works. Google for yahoo module pattern.
http://www.yuiblog.com/blog/2007/06/12/module-pattern/
http://ajaxian.com/archives/a-javascript-module-pattern
TEST = function() {
var SOME_CONSTANT='asd';
function privateStuff(){
var a = 'asd';
return a;
}
return{
someArray:[],
someMethod: function(foo, bar){
var foo = *1
}
,
myProperty:'test'
}
}();
TEST.*2
with *1 and *2 i marked places where i tried auto complete.
in *1 i get SOME_CONSTANT and privateStuff method, and if i put this.(autocomplete) i get access to all the methods and properties inside of return {} block
when i try autocomplete on *2 i get all the methods and properties inside return {} block.
SOME_CONSTANT and privateStuff method are invisibile there, because they are "private".
For me that level of autocomplete is quite fine.
I think will be great if you read something about Douglas Crockford. He is THE architect in yahou YUI framework. And after that you can have a better idea to how build a great framework. And for the parameter there are 2 options. 1.- send via object example
{ option :{ var1 : "value" , var2:"value"}, var3 : "value" }
And the you can check if the option exist.
The second one not to great is check if the parameter is undefined.
function foo(var1,var2){
var var1_this = null;
if(var1 != undefined)
var1_this = var1;
}
and just a comment why build a new javascript framework? use Prototype, JQuery, Mootols, YUI. why reinventing the wheel?
This is in reply to the comments to mwilcox's post.
That example will actually work. Since myLibrary is defined without var, it is automatically put into the global namespace and accessible as such. Through the closure created by the self-executing function, the private variables and methods are still accessible in the myLibrary methods. You can easily try this out by putting it into Firebug or Rhino.
These days, I do not tend to hide my variables, i.e. I use the Pseudoclassical pattern or the Prototypal pattern and prefix my intended private methods with an _:
// Pseudoclassical pattern
function Hello() {}
Hello.prototype = {
method1: function() {},
method2: function() {},
_pseudeoPrivate: function() {}
};
/* Prototypal pattern. To create multiple instances of this object,
you need a helper function such as
function beget(o) {
var F = function() {};
F.prototype = o;
return new F;
}
var instance = beget(world);
*/
var world = {
method1: function() {},
method2: function() {}
};
To prevent my code from polluting the global namespace, I have a build process that wraps my modules in a closure and exports the public api to the namespace. This technique is also used by jQuery. You can see that in their source code (look at intro.js & outro.js) on Github.
This would allow you to use a pattern that allows your IDE (or ctags with vim) to see your api, whilst also preventing the pollution of the global namespace.
I write my libraries like this:
function MyLibrary() {
// code
}
MyLibrary.prototype.memberFunc = function() {
// code
}
MyLibrary.prototype.memberVar = 5;
new MyLibrary();
This way, in Geany (which uses CTAGS) MyLibrary is well recognized (for the most part, for example, memberVar is recognized as a function) and autocompletion seems to work. I don't know about IDEA9, but you could try it this way (I have a hunch it's a bit more evolved than CTAGS).
I recommend that you don't use private variables, but I understand you want them hidden from the intellisense. This is how I would do it:
(function(){
var privateVar = "shhhh!";
var privateMethod = function(){}
myLibray = {
prop:42,
foo: function(){
return privateMethod()
},
bar: function(){
return privateVar;
}
}
})();
This way you can have your private stuff in a closure and your library should be accessible.
[ edited. I clumsily did not include myLibrary in the anonymous function and it could not see the private vars. oops. ]
BTW, my reasons for private variables being bad: http://clubajax.org/javascript-private-variables-are-evil/

Categories

Resources