Assume I have a simple object in js with one private variable:
function test(){
var value=true;
}
and now I want to create one instance:
var r=new test() //I want to get r === true
How can I return a value from it?
If I write:
function test(){
var value=true;
return value;
}
I have a test {} in result.
If I write:
function test(){
var value=true;
return function(){ return value; }
}
then I can get the value, but I must add additional parentheses:
var r=new test()() //r === true
I don't want the parentheses, so I tried to change the code to:
function test(){
var value=true;
return (function(){ return value; } )();
}
But in response, again I get test {}
How to write the return statement in this situation?
I believe you need to do something like:
function test(){
this.value = true;
}
and then
var r=new test();
if (r.value == true) {
//Do something
}
First I feel obliged to clarify a possible misunderstanding:
function test(){
var value=true;
}
is not an object with a private variable. It is a function with a local variable. When you call the function with new, it creates an object inheriting from the functions's prototype with no properties. If you call the function normally, it simply executes the function body and returns undefined (since you are not returning anything).
Solutions:
Do you actually need a constructor function? I'm asking because your example is very simple. Obviously you cannot have the function return two values, true and the object.
So, you could just call the function without new:
function test() {
var value = true;
return value;
}
var r = test();
If you really want r to be true then I see no reason to call the function as a constructor function.
The reason why you got test {} as result was because you called the function with new. If you do that, the function will always return an object and if you don't do so explicitly (value is a boolean, not an object), it implicitly returns this (which is an object).
So again, if you really want r to be equal to value from inside the function, then simply don't call the function with new.
If you need an object though, there are a couple of ways:
You can assign the value to a property and access it instead, like PokeHerOne showed in his answer or add a function which returns that value, as papaiatis demonstrates. The advantage is that the value is accessed explicitly and other people looking at your code understand what's going on.
Additionally, depending on what you want to do with that value / object, you can implement the valueOf methods, which gets called by various operators.
For example:
function Test(){
var value = true;
this.valueOf = function() {
return value;
}
}
var t = new Test();
console.log(t); // logs the Test instance
console.log(t == true); // logs `true`
I.e. t is an object but behaves like the value true (value) in various operations. This is powerful but can also be quite confusing, since the type conversion is somewhat implicit and it's not something that is used in JavaScript very often.
Used methods defined internally:
function TestClass(){
var value = true;
this.getValue = function(){
return value;
};
}
var t = new TestClass();
alert(t.getValue()); // true
Since value is defined as private it is not accessible from outside:
alert(t.value) // undefined
Related
I want a function in JS, which can take some value at first call and set it to a variable inside it.
And then again on another call i want to again get the data of that variable.
something like this:
while calling the function for first time
function set_and_get(value){
var a = value;
}
on another call it should return the value like
returned_value = set_and_get()
Thanks.
Normally the pattern looks more like this where the function will return another function which you then would use.
function set_and_get(value){
return function () {
return value;
}
}
var test = set_and_get(1)
console.log(test())
var test2 = set_and_get(2)
console.log(test(), test2())
Now if the function can not be reused, aka once it is set, it is done. You could just overwrite the function. It is not the best practice, but it can work.
function set_and_get(value) {
set_and_get = function() {
return value;
}
return value
}
console.log(set_and_get(1))
console.log(set_and_get())
console.log(set_and_get(2))
While not necessarily recommended, you can attach a property to the function object itself:
function get_and_set(value) {
if (value !== undefined) {
get_and_set._value = value;
} else {
return get_and_set._value;
}
}
but note that the property is in no way protected - it is possible to read it (And overwrite it) from outside the helper function.
You would have to use a combination of concepts called closure and high order function.
var set_and_get_fn = function(value){
var a = value;
var set_and_get = function(){
return a;
}
return set_and_get;
}
var set_and_get = set_and_get_fn(10);
var returned_value = set_and_get();
// 10
set_and_get();
// still 10
set_and_get = set_and_get_fn(12);
set_and_get();
//12
set_and_get();
//12
Closure allows an inner function set_and_get to have access to the variables of it's outer function/context set_and_get_fn, even after set_and_get_fn has returned. set_and_get has closed over variable a. High order functions allows you to treat functions as objects, you can pass them as arguments and return them from functions. I'm returning set_and_get function from set_and_get_fn
I want to know how the function has been initialized, with the expression or declaried as fuction. _ Amazon interview question
expression : var a = function (){ }
declaration: function a (){ }
You could just do a.toString() and parse out the name. Or do the same with regular expressions
a.toString().test(/^\s*function\s*\(/);
function a(){ }; // gives false
var a = function (){ }; // gives true
Of course as Grundy pointed out this fails with named functions. Something like
var a = function b() {};
or
function b() {};
var a = b;
And ES6 has .name (see the Browser table at the bottom for the current state of affairs) - https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Function/name
I don't think it's possible to do so. The only difference between:
var func = function(){ };
and:
function func() { };
Is that the first one gets assigned on runtime. The way I see it, is that both function statements return a reference to their respective function objects. In that sense they are both the same. The only thing you could argue is that one is not named and the other one is, but you could have assigned a named function to a variable too.
However, there seems to be a difference on how they get assigned. The second one seems to get assigned to a variable that its named after, right at the start of the execution context. The first one has to wait for the explicit assignment within the execution context.
So you'd be testing for when they get assigned. You might think that's is possible to do so within the global object like:
//some protected vars that can't work without same-origin
var protected = ['caches', 'localStorage', 'sessionStorage', 'frameElement'];
var definedAtInit = [];
for(prop in window){
if(!isSandboxed(prop) && typeof window[prop] === 'function'){
definedAtInit.push(prop);
}
};
function isSandboxed(prop){
return protected.indexOf(prop) !== -1;
}
function isItDefinedAtInit(funcName){
return definedAtInit.indexOf(funcName) !== -1;
}
var func = function() {
console.log('test');
}
var results = { isItDefinedAtInit : isItDefinedAtInit('isItDefinedAtInit'),
func : isItDefinedAtInit('func')
};
document.getElementById('results').innerHTML = JSON.stringify(results, '/t');
<pre id="results"></pre>
However, you could still do something like:
var isItDefinedAtInit = function() { };
//After this, isItDefinedAtInit('isItDefinedAtInit') would be wrong.
And you still have the problems with other execution contexts, I don't think functions declared within a function execution context get attached to any object.
I think these kind of checks are a bad idea to be honest.
There is only way, we can determine function has defined with function declarations not as expression.
as Grundy mentioned name property of the respective function gives require information, if it has been defined with expression name property holds undefined value, else it holds function name.
Here is the code :
var isDefinedAsFunction = function(fn){
return fn.name !== undefined
}
So I have this code:
function fn(a){
var f=(new Function("return a"));
return f();
}
fn(7)//ReferenceError: a is not defined
Same problems with local variables:
function fn(){
var a=7;
var f=new Function("return a");
return f();
}
fn(7)//ReferenceError: a is not defined
I want it to return a but the new function cant see a,
it can only see global a
var a=1;
function fn(a){
var f=(new Function("return a"));
return f();
}
fn(7)//1
With the normal initialization the function can see the argument.
function fn(a){
var f=function(){return a};
return f();
}
fn(7)//7
I need to call the basic constructor in my project and can't use global variables.
I know that i could solve this by giving arguments to the newly created function and call it with that like this:
function fn(a){
var f=(new Function('a',"return a"));
return f(a);
}
fn(7)//7
And also could use some parsing function and some stupidly long method to make incoming arguments reachable like this:
function parsargs(funct){
//some parsing methodes giving back argument name list from funct.toString()
return "['a','b']";//like this
}
function fn(a,b){
var arrgstr,retfunc;
arrgstr="";
for(var i in arguments)
{
if(i<arguments.length-1)
arrgstr+=arguments[i]+",";
else
arrgstr+=arguments[i];
}
//return arrgstr;
retfunc="var f=new Function("+parsargs()+",'return b*a');return f("+arrgstr+")";
return (new Function(retfunc))();
}
fn(7,4)//28
But there must be an easier way which reaches local variables and functions as well...
Any suggestions?
PS:
i am trying to replace eval() in the project
Here is a simplified version of my original problem:
fiddle
The answer is NO...
Your exact question isn't clear but, supposing you can use arguments.callee (i.e. non strict mode) and that you want to be able to have any arguments name in fn, you "may" do this:
function fn(a,b){
var strargs = arguments.callee.toString().match(/\(([^\)]*)\)/)[1];
return (new Function(strargs.split(","),"return a+b")).apply(null,arguments);
}
console.log(fn(7, 3)) // 10
But I have a strong feeling this is a XY question and that we could have given a more useful answer knowing the real original problem to solve.
You could call your new Function with a context that references the local variables that you need:
function f(a) {
var b = 30;
return new Function("return this.a + this.b").call({ a: a, b: b })
}
f(10) // 40
The reason why this isn't working as easy as you would like is that JavaScript doesn't blindly put variables in a scope. Instead, it parses the function body (as good as it can) and determines which variables the code will need. It will then look up the variables in the outer scopes, create references for them and attach those references to the new function. That's what keeps variables from the outer scope accessible inside of the function when it eventually will be executed.
You want to build a function from a string body. JavaScript can't tell which variables the body will use and hence, it won't make those variables available.
To make it work for function arguments, use apply()::
function fn(a){
var argref = arguments; // create reference to the arguments of fn() and hence to a or any other arguments
var func = new Function("return arguments[0]");
var wrapper = function() {
return func.apply(null, argref);
};
return wrapper;
}
Note that you still can't reference arguments by name since the code never specifies what the names of the arguments of func are - JavaScript can't magically read you mind and do what you want. If you want to access the arguments by name, you need to tell the interpreter the names.
This question has some code how to determine the names from a function reference: How to get function parameter names/values dynamically from javascript
I don't see a way to make local variables available without passing them to fn() as arguments. Even if you used them inside of fn(), they would be out of scope when func() is eventually executed.
A simple solution would be to pass an object to fn():
function fn(conf) {
var func = new Function('conf', "return conf.a");
var wrapper = function(conf) {
return func.apply(null, conf);
};
return wrapper;
}
fn({a:7});
new Function doesn't create a closure context, but eval does.
Here's a low-tech way to build a function with an arbitrary evaluated body and access to the calling scope:
function f(a) {
return eval("(function() { return a })")()
}
f(10) // 10
Being fairly new to Javascript and from a c# background I have been stumbling along adequately. I knew that soon enough I would need to get my head round the fact that functions are objects in their own right and that JS closures are often the cause of confusion.
I am trying to understand this little snippet of code
// Function which returns object with function properties
function myFunc() {
value = 42;
var result = {
value: value,
getValue: getValue,
incrementValue: incrementValue,
setValue: setValue,
};
return result;
function setValue(y) {
value = y;
};
function getValue() {
return value;
};
function incrementValue() {
value++;
};
};
// Helper function to print out results
function printResults(m,x){
$('#output').append(m + ': ' + x).append('<br/>');
};
var myObject = myFunc(); // returns the object
printResults('Inital call to getValue',myObject.getValue());
myObject.setValue(59);
printResults('Called changeValue',myObject.getValue());
printResults('Value property of object',myObject.value);
printResults('Called getValue again',myObject.getValue());
myObject.incrementValue();
printResults('Call increment value',myObject.getValue());
printResults('Value property of object',myObject.value);
I get the following results when run in jsFiddle
Inital call to getValue: 42
Called changeValue: 59
Value property of object: 42
Called getValue again: 59
Call increment value: 60
Value property of object: 42
These show that the functions are using the variable value within their closure and this persists between invocation of the inner functions. BUT, the value of value does not change in the returned object.
I think I get the basic point that functions are executed using the scope chain that was in effect when they were defined.
Questions
Can I make the value property of the returned object operate in the same way - or is the only way to return it via a function, since the latter retains the variable in its closure?
And, just for confirmation, for every invocation of myFunc(), I assume I will get an object whose function properties will have their own scope chain and therefore independent of each invocation.
First of all, do not forget the var keyword when declaring variables. When you declare value = 42 inside myFunc, you are actually creating a variable in the global namespace instead of the function scope. It should start like this:
function myFunc() {
var value = 42;
Now, myObject.result is returning 42 because myFunc returns your result object which contains a copy of the value variable declared inside the function.
Your functions setValue, getValue and incrementValue are changing the value of value, not result.value. When you call myObject.value, you are getting the value from the returned object, not the inner variable of your function.
You could get it to work using something like this:
function myFunc() {
var value = 42;
var result = {
value: value,
getValue: getValue,
incrementValue: incrementValue,
setValue: setValue
};
return result;
function setValue(y) {
result.value = y;
}
function getValue() {
return result.value;
}
function incrementValue() {
result.value++;
}
}
However, there are better design patterns than this. You could use the new keyword and prototype to define the methods available for the objects returned from your function. Take this example:
function myFunc() {
this.value = 42;
}
myFunc.prototype.setValue = function(y) {
this.value = y;
}
myFunc.prototype.getValue = function(y) {
return this.value;
}
myFunc.prototype.incrementValue = function(y) {
this.value++;
}
var myObject = new myFunc();
console.log(myObject.getValue()); // 42
myObject.setValue(30);
myObject.incrementValue();
console.log(myObject.getValue()); // 31
Yes, you can:
var result = {
get value() {
return value;
},
getValue: getValue,
incrementValue: incrementValue,
setValue: setValue,
};
Hooray for ECMAScript 5. Of course, this won’t work on IE < 8.
<aside>value = 42; should be var value = 42;.</aside>
This doesn’t have a lot to do with the lifetime of variables, by the way – it’s just how assignment works. There are references in JavaScript, but no “reference variables” or “reference properties”. The object contains a copy of whatever value was at the time; creating a getter like this is just like creating a function that’s called implicitly.
Can I make the value property of the returned object operate in the same way
If you mean that it shows the updated value, yes, you can do that. You just have to change the code to update the value property as well:
function myFunc() {
var value = 42; // don't forget var!
var result = {
value: value,
getValue: getValue,
incrementValue: incrementValue,
setValue: setValue,
};
return result;
function setValue(y) {
result.value = value = y;
}
function getValue() {
return value;
}
function incrementValue() {
value++;
result.value = value;
}
}
The reason why I choose to use both value and result.value is to prevent the modification of the value through result.value. If you notice, I don't internally read from result.value, I only write to it. That means that assignments to result.value from external code doesn't have an effect. This conforms to how your existing code works.
And, just for confirmation, for every invocation of myFunc(), I assume I will get an object whose function properties will have their own scope chain and therefore independent of each invocation.
Yes, every invocation of myFunc creates a new object and new functions and they are completely independent from objects/functions created by previous invocations.
Say I have a pure constructor function (containing nothing but this.Bar = bar)
1) When I call it from another function, can I pass the caller function's arguments directly when I call or must I do var myBar=new bar, myBar.Bar=thebar, where the bar is a caller argument?
2) Will the constructor still instantiate even if it doesn't get all the args?
3) How can I check if one of the args is unique, IE no other instance of the object has this value for the property in question? Specifically, I want to assign each object a unique index at creation. Maybe array?
Many thanks in advance
Say I have a pure constructor function (containing nothing but this.Bar = bar)
I'm going to assume you mean:
function MyConstructor(bar) {
this.Bar = bar;
}
(Note: The overwhelming convention in JavaScript is that property names start with a lower-case letter. So this.bar, not this.Bar. Initially-capped identifiers are usually reserved for constructor functions.)
1) When I call it from another function, can I pass the caller function's arguments directly when I call or must I do var myBar=new bar, myBar.Bar=thebar, where the bar is a caller argument?
You can pass them directly:
function foo(a, b, c) {
var obj = new MyConstructor(b);
}
2) Will the constructor still instantiate even if it doesn't get all the args?
The number of arguments passed is not checked by the JavaScript engine. Any formal arguments that you don't pass will have the value undefined when the function is called:
function MyConstructor(bar) {
console.log(bar);
}
var obj = new MyConstructor(); // logs "undefined"
3) How can I check if one of the args is unique, IE no other instance of the object has this value for the property in question? Specifically, I want to assign each object a unique index at creation. Maybe array?
In general, that's usually not in-scope for a constructor. But yes, you could use an array, or an object, to do that.
var knownBars = [];
function MyConstructor(bar) {
if (knownBars.indexOf(bar) !== -1) {
// This bar is known
}
else {
// Remember this bar
knownBars.push(bar);
}
}
Of course, indexOf may not be what you want for searching, so you may need to use some other method of Array.prototype or your own loop.
Another way would be to use an object; this assumes that bar is a string or something that can usefully be turned into a string:
var knownBars = {};
function MyConstructor(bar) {
if (knownBars.indexOf(bar) !== -1) {
// This bar is known
}
else {
// Remember this bar
knownBars[bar] = 1;
}
}
When I call it from another function, can I pass the caller function's arguments directly
There wouldn't be much point in having this.Bar = bar in the constructor function if you could not.
Will the constructor still instantiate even if it doesn't get all the args?
Assuming nothing inside it throws an exception if the argument is missing, yes. Arguments just get a value of undefined.
How can I check if one of the args is unique, IE no other instance of the object has this value for the property in question?
You'd need to have a shared store of them that you check against.
For example:
var Constructor = (function () {
var unique_check_store = {};
function RealConstructor(bar) {
if (typeof bar == 'undefined') {
throw "You must specify bar";
}
if (unique_check_store.hasOwnProperty(bar)) {
throw "You have already created one of these called '" + bar + "'";
}
this.Bar = bar;
unique_check_store[bar] = true;
}
return RealConstructor;
})();
var a, b, c;
try {
a = new Constructor();
} catch (e) {
alert(e);
}
try {
b = new Constructor("thing");
} catch (e) {
alert(e);
}
try {
c = new Constructor("thing");
} catch (e) {
alert(e);
}
alert(a);
alert(b);
alert(c);