Is there any mistake in new Function? - javascript

I have read the Function. So I try to transform function declaration into function expression by new Function. But, I am stuck in the code below:
function Foo(name, age) {
Foo.prototype.name = name;
Foo.prototype.age = age;
}
var foo = new Foo(1,2); // this is ok
console.log(Foo.prototype.hasOwnProperty('name'));
console.log(foo.hasOwnProperty('name'));
However there is an error after transformation:
var Foo = new Function(['name', 'age'], 'Foo.prototype.name=name;Foo.prototype.age=age;');
var foo = new Foo(1,2); // error: Foo is not defined
console.log(Foo.prototype.hasOwnProperty('name'));
console.log(foo.hasOwnProperty('name'));
Is there any mistake? Any answer is helpful.
The code is right in my chrome browser. However it makes an error on platform:
nodejs: 6.10.0
win7 64bit

The error is because var Foo isn't defined where the Function can reach it, at least not while using Node.
When you create a function from a string using the new Function() constructor, the function only has access to the global scope, regardless of where it's created.
And, when within a Node module, var Foo and var foo aren't global variables. They're local variables that exists only within the current file/module, within a "module" scope.
var bar = 'bar';
console.log(bar); // function
console.log(global.bar); // undefined
To allow the new Function() to access Foo, you'll have to define the latter as a global variable (or a property of the global object).
global.Foo = new Function(['name', 'age'], 'Foo.prototype.name=name;Foo.prototype.age=age;');
var foo = new Foo(1,2);
// ...
Though, you should be aware that modifying the global scope/object like this is generally frowned upon in Node, since this goes against its intent/design of using isolated modules.
Though, to define the function from an expression, you don't need to use the Function constructor. You can instead place the declaration where an Expression is expected, such as after an assignment operator.
var Foo = function (name, age) {
Foo.prototype.name = name;
Foo.prototype.age = age;
};
var foo = new Foo(1,2); // this is ok
// ...

Related

JS new Function - logging a variable by name dynamically

We are given a code snippet in run time along with a name of a variable used in code. We want to evaluate the given code and log the value of the variable.
Example:
suppose our code is var foo = "Blah"; and the name of the var is foo.
eval('var foo = "Blah"; let varName = "foo"; console.log(this[varName]);');
yields Blah.
yet
new Function('var foo = "Blah"; let varName = "foo"; console.log(this[varName]);')();
yields undefined.
Is there a way to make get this to work with new Function?
With new Function, you're creating a new function. The code that is executed looks something like:
function someFunction() {
var foo = "Blah"; let varName = "foo"; console.log(this); console.log(this[varName]);
}
someFunction();
There, foo is in local scope of the someFunction. It's not global, so variables declared with var inside the function don't get put onto the global object.
In contrast, eval runs on the top level. Your eval code that is executed looks something like:
var foo = "Blah"; let varName = "foo"; console.log(this[varName]);
which is all on the top level, so the foo variable that was declared gets put onto the global object, the this.
Substitute the variable name into the function definition directly, rather than using this.
let varName = 'foo';
new Function(`var ${varName} = "Blah"; console.log(${varName});`)();
Everything here is about Scope. Global Scope and Block Scope.
Global Scope
Variables declared Globally (outside any function) have Global Scope.
var bikeName = "Honda";
// code here can use bikeName
function myFunction() {
// code here can also use bikeName
}
and
var greeter = "hey hi";
function newFunction() {
var hello = "hello"; //Variables declared Locally (inside a function) have Function Scope.
}
console.log(hello); // error: hello is not defined
Here, greeter is globally scoped because it exists outside a function while hello is function scoped. So we cannot access the variable hello outside of a function.
Block Scope
A block is a chunk of code bounded by {}. A block lives in curly braces.
let times = 4;
if (times > 3) {
let hello = "say Hello instead";
console.log(hello);// "say Hello instead"
}
console.log(hello) // hello is not defined
You should read about them. Things will get clear
Hence in your case:
new Function('var foo = "Blah"; let varName = "foo"; console.log(this[varName]);')();
Everything inside function has function scope and will not be available global!

Functions created with the Function constructor are always created in the global scope

From the MDN description of Function:
Note: Functions created with the Function constructor do not create
closures to their creation contexts; they always are created in the
global scope. When running them, they will only be able to access
their own local variables and global ones, not the ones from the scope
in which the Function constructor was called. This is different from
using eval with code for a function expression.
I understand,
var y = 10;
var tester;
function test(){
var x = 5;
tester = new Function("a", "b", "alert(y);");
tester(5, 10);
}
test(); // alerts 10
Replacing the tester = new Function("a", "b", "alert(y);"); with tester = new Function("a", "b", "alert(x);");, I will get
// ReferenceError: x is not defined
But couldn't understand the author's line-
...they always are created in the global scope.
I mean how is the new Function("a", "b", "alert(y);"); nested within the test fn is in global scope?
In fact, accessing it from outside the test fn will simply result in
Uncought TypeError:tester is not a function
Please elucidate.
In your example, "created in the global scope" means that tester will not have closure over x from test:
function test(){
var x = 5;
tester = new Function("a", "b", "alert(x);"); // this will not show x
tester(5, 10);
}
When you new up a Function, it does not automatically capture the current scope like declaring one would. If you were to simply declare and return a function, it will have closure:
function test(){
var x = 5;
tester = function (a, b) {
alert(x); // this will show x
};
tester(5, 10);
}
This is the trade-off you make for having dynamically compiled functions. You can have closure if you write the function in ahead of time or you can have a dynamic body but lose closure over the surrounding scope(s).
This caveat doesn't usually matter, but consider the (slightly contrived) case where you build a function body as a string, then pass it to a function constructor to actually be evaluated:
function addOne(x) {
return compile("return " + x + " + 1");
}
function addTwo(x) {
return compile("return " + x + " + 2");
}
function compile(str) {
return new Function(str);
}
Because the function is instantiated by compile, any closure would grab str rather than x. Since compile does not close over any other function, things get a bit weird and the function returned by compile will always hold a closure-reference to str (which could be awful for garbage collection).
Instead, to simplify all of this, the spec just makes a blanket rule that new Function does not have any closure.
You have to create an object to expose via return inside the test() function for it to be global. In other words, add var pub = {} and name your internal functions as properties and/or methods of pub (for example pub.tester = new func) then just before closing test() say return pub. So, that way it will be publically available (as test.tester). It's Called the Revealing Module Pattern.
What it means is that inside the function you can only refer to global variables, as you've found. However, the reference to the function itself is still in the local scope where it was created.
I'm confused as to where the confusion is.
It says that the function will be in global scope...and therefore will only have access to its own scope and the global scope, not variables local to the scope in which it was created.
You tested it and it has access to its own scope and the global scope, not variables local to the scope in which it was created.
So where's the confusion?
Is it in your assigning of the function to the variable testing? testing is just a local variable with a reference to the function...that has nothing to do with the scope of the creation of the function.
Scope is lexical, and has to do with where the function is created, not what random variables a function reference happens to be assigned to at runtime. And the documentation is telling you that when you make a function this way it acts as if it was created in the global scope...so it's acting completely as expected.
Here's an illustration:
This:
var y = 10;
var tester;
function test()
{
var x = 5;
// 10 and errors as not defined
tester = new Function("console.log(y); console.log(x);");
}
Is similar to this:
var y = 10;
var tester;
function test()
{
var x = 5;
// also 10 and errors as not defined
tester = something;
}
function something()
{
console.log(y);
console.log(x);
}
NOT
var y = 10;
var tester;
function test()
{
var x = 5;
// 10 and 5...since x is local to the function creation
tester = function()
{
console.log(y);
console.log(x);
}
}

Why is the value of this variable undefined

I am currently learning javascript and came across this example
var t = function()
{
this.name = "Jam";
no = "123";
}
console.log(t.no); //Undefined
var m = new t();
console.log(m.name);
Why is the first statement undefined ?
t is a function object. As any other object, the function may have properties assigned. So in order your code to work you shall assign "123" to no property of your function (line A):
var t = function()
{
this.name = "Jam";
}
t.no = "123"; // line A
console.log(t.no); // "123"
var m = new t();
console.log(m.name);
Why is the first statement undefined ?
Because t doesn't have a property no.
First of all, the code inside the function, namely
this.name = "Jam";
no = "123";
is only executed when the function is called. You are doing this with var m = new t();, which comes after console.log(t.no);.
Secondly, no = "123"; does not create a property on the function object. It will attempt to set the value of variable no. Since the variable doesn't exist in your example, that line will either create a global variable no, or throw in error if your code is in strict mode.
Consider the following example:
var no = 21;
function foo() {
no = 42;
}
console.log(no); // 21
foo();
console.log(no); // 42
Because t is a function, that would be executed by t();. no on the other hand is a global scooed variable that is reached without prefix from everywhere.
t is a function expression. You you can access a returned object of a function like t().no or you can create a new object by using the function as a constructor like this
myT = new t()
console.log(t.no);
But your no variable is just a global variable inside the function and it is not a part of what it returns nor it is not attached to the returning object of the constructor function.
Here is a very good tutorial which covers all these topics at depths.

When creating an instance of a Javascript "class," is there a way to structure the object such that all methods may be accessed?

Is there a way to create an object in Javascript such that all of its methods are available to the constructor?
I'm finding it tough to phrase my problem clearly.. so an example!
Given this class
function Example() {
var someVar = something;
var moreState = initializedToSomethingElse;
verifySomething(); <-- Fails!
this.verifySomething = function() {
// do verify stuff
}
}
I can't call verifySomething in my constructor because the method, as far as the instance is concerned, doesn't exist yet. So, I get an undefined error. Is there a better way to create objects in javascript so that I can avoid this problem?
Is there a way to create an object in Javascript such that all of its methods are available to the constructor?
You can call any method once it's been created. In your example, there are two issues:
You haven't created the method yet
You are calling it incorrectly — in JavaScript, using the object qualifier (this. within a constructor, usually) isn't optional as it is in some other languages
If you define methods on the constructor function's prototype property, provided those assignments happen before the call to the constructor (which is usually true, and there are techniques for guaranteeing it), the methods will be available on this within the constructor. If you create methods within the constructor (as in your example), just create them first.
Here's your example using the constructor's prototype property, which refers to the object that will be used as the prototype of instances created via new:
function Example() {
var someVar = something;
var moreState = initializedToSomethingElse;
this.verifySomething(); // <== Works
}
Example.prototype.verifySomething = function() {
// do verify stuff
};
var e = new Example();
Here's an example defining within the constructor that makes use of the fact that function declarations (rather than expressions) are "hoisted" (completed before any step-by-step code runs).
function Example() {
var someVar = something;
var moreState = initializedToSomethingElse;
this.verifySomething = verifySomething; // <== Note we assign first
this.verifySomething(); // <== Works
function verifySomething() {
// do verify stuff
}
}
var e = new Example();
If you really don't like doing that assignment before calling it, you could use .call:
function Example() {
var someVar = something;
var moreState = initializedToSomethingElse;
verifySomething.call(this); // <== Works
// this.verifySomething(); // <== Would not work
this.verifySomething = verifySomething; // <== Note we assign after
function verifySomething() {
// do verify stuff
}
}
var e = new Example();
I mentioned above that there are techniques for guaranteeing that the prototype property of the constructor function has been fully fleshed-out before the constructor is ever called. Here's one of them (using a scoping function):
var Example = (function() {
function Example() {
var someVar = something;
var moreState = initializedToSomethingElse;
this.verifySomething(); // <== Works
}
Example.prototype.verifySomething = function() {
// do verify stuff
};
return Example;
})();
var e = new Example();
With the above, there's no way code outside the containing immediately-invoked scoping function can use Example until after that scoping function has finished, and therefore fully set up the prototype property.

Declaring variables with this or var?

What is the difference between declaring a variable with this or var ?
var foo = 'bar'
or
this.foo = 'bar'
When do you use this and when var?
edit: is there a simple question i can ask my self when deciding if i want to use var or this
If it is global code (the code is not part of any function), then you are creating a property on the global object with the two snippets, since this in global code points to the global object.
The difference in this case is that when the var statement is used, that property cannot be deleted, for example:
var foo = 'bar';
delete foo; // false
typeof foo; // "string"
this.bar = 'baz';
delete bar; // true
typeof bar; "undefined"
(Note: The above snippet will behave differently in the Firebug console, since it runs code with eval, and the code executed in the Eval Code execution context permits the deletion of identifiers created with var, try it here)
If the code is part of a function you should know that the this keyword has nothing to do with the function scope, is a reserved word that is set implicitly, depending how a function is called, for example:
1 - When a function is called as a method (the function is invoked as member of an object):
obj.method(); // 'this' inside method will refer to obj
2 - A normal function call:
myFunction(); // 'this' inside the function will refer to the Global object
// or
(function () {})();
3 - When the new operator is used:
var obj = new Constructor(); // 'this' will refer to a newly created object.
And you can even set the this value explicitly, using the call and apply methods, for example:
function test () {
alert(this);
}
test.call("hello!"); //alerts hello!
You should know also that JavaScript has function scope only, and variables declared with the var statement will be reachable only within the same function or any inner functions defined below.
Edit: Looking the code you posted to the #David's answer, let me comment:
var test1 = 'test'; // two globals, with the difference I talk
this.test2 = 'test'; // about in the beginning of this answer
//...
function test4(){
var test5 = 'test in function with var'; // <-- test5 is locally scoped!!!
this.test6 = 'test in function with this'; // global property, see below
}
test4(); // <--- test4 will be called with `this` pointing to the global object
// see #2 above, a call to an identifier that is not an property of an
// object causes it
alert(typeof test5); // "undefined" since it's a local variable of `test4`
alert(test6); // "test in function with this"
You can't access the test5 variable outside the function because is locally scoped, and it exists only withing the scope of that function.
Edit: In response to your comment
For declaring variables I encourage you to always use var, it's what is made for.
The concept of the this value, will get useful when you start working with constructor functions, objects and methods.
If you use var, the variable is scoped to the current function.
If you use this, then you are assigning a value to a property on whatever this is (which is either the object the method is being called on or (if the new keyword has been used) the object being created.
You use var when you want to define a simple local variable as you would in a typical function:-
function doAdd(a, b)
{
var c = a + b;
return c;
}
var result = doAdd(a, b);
alert(result);
However this has special meaning when call is used on a function.
function doAdd(a, b)
{
this.c = a + b;
}
var o = new Object();
doAdd.call(o, a, b);
alert(o.c);
You note the first parameter when using call on doAdd is the object created before. Inside that execution of doAdd this will refer to that object. Hence it creates a c property on the object.
Typically though a function is assigned to a property of an object like this:-
function doAdd(a, b)
{
this.c = a + b;
}
var o = new Object();
o.doAdd = doAdd;
Now the function can be execute using the . notation:-
o.doAdd(a, b);
alert(o.c);
Effectively o.doAdd(a, b) is o.doAdd.call(o, a, b)
var foo = 'bar'
This will scope the foo variable to the function wrapping it, or the global scope.
this.foo = 'bar'
This will scope the foo variable to the this object, it exactly like doing this:
window.foo = 'bar';
or
someObj.foo = 'bar';
The second part of your question seems to be what is the this object, and that is something that is determined by what context the function is running in. You can change what this is by using the apply method that all functions have. You can also make the default of the this variable an object other than the global object, by:
someObj.foo = function(){
// 'this' is 'someObj'
};
or
function someObj(x){
this.x=x;
}
someObj.prototype.getX = function(){
return this.x;
}
var myX = (new someObj(1)).getX(); // myX == 1
In a constructor, you can use var to simulate private members and this to simulate public members:
function Obj() {
this.pub = 'public';
var priv = 'private';
}
var o = new Obj();
o.pub; // 'public'
o.priv; // error
Example for this and var explained below:
function Car() {
this.speed = 0;
var speedUp = function() {
var speed = 10; // default
this.speed = this.speed + speed; // see how this and var are used
};
speedUp();
}
var foo = 'bar'; // 'var can be only used inside a function
and
this.foo = 'bar' // 'this' can be used globally inside an object

Categories

Resources