Is there way to create a new global method where I can have variable.myMethod() and it return true or false? Basically, I want to check to see if the variable is undefined and instead of using typeof(variable) == 'undefined' or specifying a function, is it possible to do something like variable.isUndefined() and it would return true or false?
I'm going to go ahead and post this as an answer, so I can go into a bit more detail.
As I mentioned in my comment, you have to be extremely careful about the terms that you use here, as undeclared and undefined mean two very different things.
If a variable is "undeclared", it doesn't exist, thus you cannot attempt to call any methods that might exist on it if it were declared.
If a variable is "undefined", it exists, but it doesn't have a value assigned to it. When this is the case, you can attempt to call methods that may exist on it, however the chances are that they'll fail, since variable doesn't have any value.
Every type in JavaScript is a child of the Object type, therefore you add a method to them, like follows:
Object.prototype.myMethod = function() {
console.log("This is my method");
};
So, in theory, you could create a method to check to see if a value exists, and return a true/false value.
Similarly to what StackOverflow user Barmar pointed out, undefined and null are not children of the Object type, thus your method will not exist.
As other comments have stated, you're probably better of sticking with something like follows:
if (!myVariable) {
// myVariable doesn't have a value
}
I'd like to point out that most of my explanation was unnecessary, as user Barmar pointed out, there is no practical difference between undeclared and undefined.
If a variable is undeclared, it's "value" is essentially read as undefined, thus your method will not exist.
this is a paradox. you can never have a method inside an undefined object because and undefined object does not have anything at all. to make it clear imagine this object
var a = {};
a.b is undefined here, so trying to call a.b.isDefined() can not work because you dont even have b. to make it work you need b defined like this
var a = {b:1,isUndefined:function(){return false}}
so you have to make a generic function that takes objects. This will do the trick
function isUndefined(obj,stringLink){
var arrayLink = stringLink.split(".");
var current = obj[arrayLink[0]];
if(!current)return false;
for(var i =1;i< arrayLink.length;i++){
current = current[arrayLink[i]];
if (!current)return false;
}
return true;
}
it will more or less check for nested object until it reach the target.
if you have
var a = {b:{c:{d:{e:{f:1}}}}}
//this function will do a["b"]["c"]["d"]["e"]["f"]
isUndefined(a,"a.b.c.d.e.f") //gives true
//or you can use
if(a&&a.b&&a.b.c&&a.b.c.d&&a.b.c.d.e&&a.b.c.d.e.f)//lots of work here
Related
I want to calculate the properties of an object based on a string.
But these property definitions might reference another object called 'actor'.
If this actor exists (which is not always the case) my code works, if the actor does not exist (is undefined) I want the evaluation to return NaN for actor-dependant properties.
Example:
The property definition string might look like:
"name = 'pant leg insurance';
cost = 10;
useful = actor.hasPants();
max = actor._legs;"
These variables are defined before the definition string is run through
eval(propertyString);
If the actor exists everything is fine, but if the actor does not exist I want every actor-dependant value (in this case 'useful' and 'max') to return NaN.
I already researched a bit and found the Proxy object, but this only helps if I want to access a direct property of the actor, neither with functions nor with properties which are properties of properties [...] of the actor.
var actor;
if (actor === undefined) {
actor = new Proxy({}, {
get: function(target, property) {
return NaN;
}
});
}
console.log(actor.anything);
console.log(actor.anyfunction());
console.log(actor.anything.anything);
console.log(actor.anything.anyfunction());
How do I achieve that this snippet would return NaN for any property or function calls on actor?
No, proxies cannot achieve this. When a property is accessed, you don't know whether it will be used directly in the assignment or will be called as a method, so you can't decide whether to return NaN or a function. There is no callable NaN value.
Instead, you will need to process your property definition string (you probably want to anyway, as assigning to undeclared variables is evil) and test each line for usage of actor, and when it does apply your if-not-exists-then-NaN logic.
I am puzzled with this one. I have the following code.
var s = "test";
s.len = 4;
var t = s.len;
The question is why the variable t has a value of undefined.
If you check the s.len after that code it is undefined.
If you check s the value is test. Not sure what is going on here. I am sure there is an explanation, but can't get my head around that and don't know how to search that.
For those who consider to vote down. This is a question we got in a course, and we are expected to prepare for the next session with this riddle.
I am not new to programming, but I fail to research how JavaScripts treats this code. It is valid code really, execute it in your Dev Tools and you will see.
I define a property for the string s called len assign to it the value 4. This property is, I believe created, but undefined. I would like to now why is it ? Is it specific to strings in JavaScript ?
but I fail to research how JavaScripts treats this code.
That is easy: strings are primitive types in JS, which means they don't have properties by themselves.
For . operator to work with them (e.g. for .length call) javascript defines such a thing called "wrapper objects".
So when you try to access a property of a primitive object - a temporary wrapper object is created that does behave as an object, hence you can access and assign properties to it.
The problem is that the wrapper object is temporary, so after it's used to access a property the object is discarded with all its state.
That's why when you assign a .len property you cannot access it on the next line: it's lost.
So a pseudo code for what actually happens behind the scenes for your code is
var s = "test";
(new String(s)).len = 4; // here you add an attribute for a new object
// and `s` is left untouched
var t = s.len;
The question is why the variable t has a value of undefined.
Because you have defined s as a string not as an object. so s.len should be undefined!
I am not sure what are you trying to do. But if you want to get the length of s then t = s.length will simply work.
I define a property for the string s called len assign to it the value 4. This property is, I believe created, but undefined. I would like to now why is it ? Is it specific to strings in JavaScript ?
You can find the answer from this question
run :
var s1 = "test";
console.log(typeof s1)//string
var s2 = {}
console.log(typeof s2)//object
s1.len = 4;
s2.len = 4;
console.log(s1.len);//undefine
console.log(s2.len);//4
I'm making a class that will be recreated many times, and in order to save memory I need to thoroughly delete it. Basically I need to access its containing variable if possible.
Here's the example:
function example(){
this.id=0;
this.action=function(){alert('tost');}
this.close=function(){ delete this;}
}
var foo=new example();
My question is:
How can I get access to the foo variable from within the example function so I can remove it?
window.foo will access that global variable.
this.close=function(){ delete window.foo; }
However, I remember there is something fishy with global variables, delete and window, so you might want to do otherwise, and simply use window.foo = null; for example.
If you want to access a variable defined in another function, you'll want to read the answers to this SO question.
Since what you want is to allow the garbage collector to release that object, you need to ensure that there are no references left to the object. This can be quite tricky (i.e. impossible) because the code manipulating the object can make multiple references to it, through global and local variables, and attributes.
You could prevent direct reference to the object by creating a proxy to access it, unfortunately javascript doesn't support dynamic getters and setters (also called catch-alls) very well (on some browseres you might achieve it though, see this SO question), so you can't easily redirect all field and method (which are just fields anyway) accesses to the underlying object, especially if the underlying object has many fields added to it and removed from it dynamically (i.e. this.anewfield = anewvalue).
Here is a smiple proxy (code on jsfiddle.net):
function heavyobject(destroyself, param1, param2) {
this.id=0;
this.action=function(){alert('tost ' + param1 + "," + param2);};
this.close=function(){ destroyself(); }
}
function proxy(param1, param2) {
object = null;
// overwrites object, the only reference to
// the heavyobject, with a null value.
destroyer = function() { object = null; };
object = new heavyobject(destroyer, param1, param2);
return function(fieldname, setvalue) {
if (object != null) {
if (arguments.length == 1)
return object[fieldname];
else
object[fieldname] = setvalue;
}
};
}
var foo = proxy('a', 'b');
alert(foo("action")); // get field action
foo("afield", "avalue"); // set field afield to value avalue.
foo("action")(); // call field action
foo("close")(); // call field close
alert(foo("action")); // get field action (should be 'undefined').
It works by returning a function that when called with a single argument, gets a field on the wrapped object, and when called with two arguments sets a field. It works by making sure that the only reference to the heavyobject is the object local variable in the proxy function.
The code in heavyobject must never leak this (never return it, never return a function holding a reference to var that = this, never store it into a field of another variable), otherwise some external references may be created that would point to the heavyobject, preventing its deletion.
If heavyobject's constructor calls destroyself() from within the constructor (or from a function called by the constructor), it won't have any effect.
Another simpler proxy, that will give you an empty object on which you can add fields, read fields, and call methods. I'm pretty sure that with this one, no external reference can escape.
Code (also on jsfiddle.net):
function uniquelyReferencedObject() {
object = {};
f = function(field, value) {
if (object != null) {
if (arguments.length == 0)
object = null;
else if (arguments.length == 1)
return object[field];
else
object[field] = value;
}
};
f.destroy = function() { f(); }
f.getField = function(field) { return f(field); }
f.setField = function(field, value) { f(field, value); }
return f;
}
// Using function calls
o = uniquelyReferencedObject();
o("afield", "avalue");
alert(o("afield")); // "avalue"
o(); // destroy
alert(o("afield")); // undefined
// Using destroy, getField, setField
other = uniquelyReferencedObject();
other.setField("afield", "avalue");
alert(other.getField("afield")); // "avalue"
other.destroy();
alert(other.getField("afield")); // undefined
The truth is that you can not delete objects in Javascript.
Then you use delete operator, it accepts the property of some object only.
So, when you use delete, in general you must pass to it something like obj.p. Then you pass just a variable name actually this means 'property of global object', and delete p is the same as delete window.p. Not sure what happens internally on delete this but as a result browser just skip it.
Now, what we actually deleting with delete? We deleting a reference to object. It means object itself is still somethere in memory. To eliminate it, you must delete all references to concrete object. Everythere - from other objects, from closures, from event handlers, linked data, all of them. But object itself doest have information about all this references to it, so there is no way to delete object from object itself.
Look at this code:
var obj = <our object>;
var someAnother = {
...
myObjRef: obj
...
}
var someAnotherAnother = {
...
secondRef : obj
...
}
To eliminate obj from memory you must delete someAnother.myObjRef and someAnoterAnother.secondRef. You can do it only from the part of programm which knows about all of them.
And how we delete something at all if we can have any number of references everythere? There are some ways to solve this problem:
Make only one point in program from there this object will be referenced. In fact - there will be only one reference in our program. and Then we delete it - object will be killed by garbage collector. This is the 'proxy' way described above. This has its disadvantages (no support from language itself yet, and necessarity to change cool and nice obj.x=1 to obj.val('x',1). Also, and this is less obvious, in fact you change all references to obj to references to proxy. And proxy will always remain in memory instead of object. Depending on object size, number of objects and implementation this can give you some profit or not. Or even make things worse. For example if size of your object is near size of proxy itself - you will get no worth.
add to every place there you use an object a code which will delete reference to this object. It is more clear and simple to use, because if you call a obj.close() at some place - you already knows everything what you need to delete it. Just instead of obj.close() kill the refernce to it. In general - change this reference to something another:
var x = new obj; //now our object is created and referenced
x = null;// now our object **obj** still im memory
//but doest have a references to it
//and after some milliseconds obj is killed by GC...
//also you can do delete for properties
delete x.y; //where x an object and x.y = obj
but with this approach you must remember that references can be in very hard to understand places. For example:
function func() {
var x= new obj;// our heavy object
...
return function result() {
...some cool stuff..
}
}
the reference is stored in closure for result function and obj will remain in memory while you have a reference to result somethere.
It hard to imagine object that is heavy itself, most realistic scenario - what you have some data inside it. In this case you can add a cleanup function to object which will cleans this data. Let say you have an gigant buffer (array of numbers for example) as a property of the object, and if you want to free memory - you can just clear this buffer still having object in memory as a couple dozens of bytes. And remember to put your functions to prototype to keep instances small.
Here is a link to some very detailed information on the JavaScript delete operator.
http://perfectionkills.com/understanding-delete/
I've been working on a javascript library, and I have a lot of redundant checks like this:
if(typeof foo !== "undefined" && foo !== null)
So, I wanted to create a function that will be a shortcut to this unwieldy check. So I came up with this:
function isset(a)
{
return (typeof a !== "undefined" && a !== null) ? true : false;
}
But, since the value could be undefined, and it attempts to use a possibly undefined variable, it turns out to be useless.
Is there a way to accomplish this without have to extend a native prototype?
It really depends on what you mean by undefined.
1. You mean the variable does not exist.
In this case, what you want is not possible. typeof is an operator and therefore has magic behavior you just can't emulate using the language. If you try to pass a variable that doesn't exist to your function, it will throw a ReferenceError.
(See below for a workaround.)
2. You mean the variable has the value undefined, but does exist.
In this case, your function will do the trick -- though it could be simplified to the following:
function isset(variable) {
return variable != null;
}
This function will return false if the variable is either undefined or null. It takes advantage of the fact that undefined == null in JavaScript. Of course, with such a short function, one could argue that the function isn't needed at all.
Recall that a variable that is declared has a value -- undefined -- by default.
The name of your function suggests you mean case #1. I don't know what sort of library you are writing, but I can't imagine a case in a library where you would need to check if a variable exists, though I can definitely think of many possibilities for case #2.
If case #1 is necessary, remember that you can re-declare variables without changing their value:
a = 1; // pretend this was set somewhere higher up in the code
var a; // this does not change the value of `a`
If you re-declare variables before you use isset, you could avoid the ReferenceError problem. You won't be able to tell if the code has already declared the variable, though; you will only be able to tell if they have not assigned it to some other value.
You can check for null and undefined at the same time by using != instead.
// checks for both null and undefined
if( foo != null ) { ...
...so no need to use a function to shorten it.
null and undefined also evaluates to false in an if statement. So the following statement also works:
if(!foo)
...
This should cut it down significantly.
I do not understand why people keep promoting if (var) or if (!var). Both fail in my browsers. Meantime if (obj.prop) passes. This means that we should use if (this.someVar) or if (window.someVar) instead of if (varbl). Ok?
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Why is there a null value in JavaScript?
I don't understand what null is for. 'Undefined' as well.
It helps to appreciate the difference between a value and a variable.
A variable is a storage location that contains a value.
null means that the storage location does not contain anything (but null itself is just a special kind of value). Read that last sentence carefully. There is a difference between what null is and what null means. 99% of the time you only care about what null means.
Undefined means that the variable (as opposed to the value) does not exist.
null is an object you can use when creating variables when you don't have a value yet:
var myVal = null;
When you do this, you can also use it to check to see if it's defined:
// null is a falsy value
if(!myVal) {
myVal = 'some value';
}
I wouldn't use it this way, normally. It's simple enough to use 'undefined', instead:
var myVal; // this is undefined
And it still works as a falsy value.
Creating Objects
When you create an object in javascript, I like to declare all my object properties at the top of my object function:
function myObject() {
// declare public object properties
this.myProp = null;
this.myProp2 = null;
this.init = function() {
// ... instantiate all object properties
};
this.init();
}
I do this because it's easier to see what the object properties are right off the bat.
If a variable is not known or not initialized in the current scope it is undefined.
If you want to use a variable and indicate that it has an invalid value for instance you may want to assign it null because accessing an undefined variable will throw an error if you try to work with it (despite checking if it is undefined).
If something is undefined you also have the possibility to add it to an object. If a variable is defined but contains null you know that this variable may be used already by another part of your program.
For example, it can prepare a global variable to be used in more parts of the code.
If you start your code with var iNeedThisEverywhere = null; then you can use it inside more objects/actions in the code, but if you don't do that, then this variable will not be shared throughout the code.
Of course, you will actually put something inside that variable somewhere during the code, but since you defined this variable at the very beginning, it will be shared further anyway.
A variable holding null holds a reference to the "black hole" named null.
10 + 10 + null = null
Null is related historically to databases, http://en.wikipedia.org/wiki/Null_(SQL)
(Correct me if I'm wrong here)
A variable not initiated (unknown) is undefined.
regards,
/t