Possible to have a JavaScript method to handle undefined properties? - javascript

What works:
Having a JavaScript object like e.g.
var obj = {
var1: "one"
};
I can call it like one of the following ways:
console.log(obj.var1);
console.log(obj['var1']);
What fails:
This one would fail:
console.log(obj.var2);
because var2 is no property/variable of the anonymous object, thus, undefined is printed in the console log.
My goal:
What I would love to have is a fallback function that would be called automatically when no matching property/variable is found.
E.g. something like:
var obj = {
var1: "one",
__propertyNotFound__: function (name) {
if ( name=="var2" ) return "two";
else return null;
}
};
Unfortunately I found no whatsoever close solution.
My question:
Being a rather JavaScript newbie, is my question a dumb question and the complete wrong approach or could it make sense and is there actually a solution to solve this?

Well, won't be really automatic but you could do something like this:
var obj={
a:2,
b:5,
get:function(index){
if(this.hasOwnProperty(index)){
return this[index];
}else{
return this.notFound(index);
}
},
notFound:function(index){
if ( index=="var2" ) return "two";
else return null;
}
}
console.log(obj.get('var2')) // two
You will have to use .get to access properties, but you can handle not found with that way

Instead of directly referring to the property when you try to retrieve its value, implement a getter function that will be able to return a requested property, as well as perform any desired operation in case you request an undefined property.

Related

understanding the code from transit.js

I was just going through the source of transit.js and came across the following fucntion ::
$.cssHooks['transit:transform'] = {
// The getter returns a `Transform` object.
get: function(elem) {
return $(elem).data('transform') || new Transform();
},
// The setter accepts a `Transform` object or a string.
set: function(elem, v) {
var value = v;
if (!(value instanceof Transform)) {
value = new Transform(value);
}
// We've seen the 3D version of Scale() not work in Chrome when the
// element being scaled extends outside of the viewport. Thus, we're
// forcing Chrome to not use the 3d transforms as well. Not sure if
// translate is affectede, but not risking it. Detection code from
// http://davidwalsh.name/detecting-google-chrome-javascript
if (support.transform === 'WebkitTransform' && !isChrome) {
elem.style[support.transform] = value.toString(true);
} else {
elem.style[support.transform] = value.toString();
}
$(elem).data('transform', value);
}
};
I understand the latter part of the function, but its really hard to understand the initial part of the function, the function can be found on git too , HERE .
Initially I see this, $.cssHooks['transit:transform'] what is that line really saying?
After that we have the below line of code I.E. the getter and setter method,
set: function(elem, v) {
But who is passing the elem and v inside the function, I don't see anything being passed?
Read about cssHooks at jQuery cssHooks
Look at the source code (search for hooks.get and hooks.set)
.cssHooks is an array of objects that contains getter and setters tha will be executed by .css(). Thats all.
$.cssHooks['transit:transform'] = {set: function(elem,value){}, get: function(elem){}}
equal:
$.cssHooks['transit:transform'] = {};
$.cssHooks['transit:transform'].set = function(elem, value){};
$.cssHooks['transit:transform'].get = function(elem){};
$(element).css('transit:transform',value)
comes to:
$.cssHooks['transit:transform'].set(element,value)
$(element).css('transit:transform')
comes to:
$.cssHooks['transit:transform'].get(element)
$.cssHooks['transit:transform'] = {set:function(){}, get: function(){} }
{...} is an object creation.get and set not executed at this moment.
They created {set:function(){}, get: function(){} }
So. Simply: .css() will execute set and get functions for hooked property.
If you want to know how real getters and setters works:
Object.defineProperty()
In Javascript, you can add/access to a property with this syntax :
myObject.myProperty
or with this syntax :
myObject['myProperty']
This is the same result
So your line
$.cssHooks['transit:transform']
just mean that we want to store an object (code between {} in your original post) inside the 'transit:transform' property which is inside the cssHooks property which is inside the $ object
This is the same things :
$['cssHooks']['transit:transform']
The reason why they use the [''] syntax is that transit:transform contains the ':' char which is not allowed if you want to access it this way :
$.cssHooks.transit:transform //doesn't work
EDIT:
To answer to your second question, i don't know...the code you are showing is just the 'description' of the "transit:transform' property

How to chain methods in javascript?

Assuming I have the following object.
myobj = {
'item1'{'key1':'value1'},
'item2'{'key2':'value2'}
}
How can I define a function such that I could call:
var value = getMyObjItem('item2').getValue();
in order to get 'value2'? I would like to avoid defining a 'getItem' (takes item parameter) and 'getItemByValue' (takes two parameters of item and key).
It wasn't clear what you wanted, but I did the best I could with the information I had. The following function operates in the exact manner you asked for, and is probably a good example of giving you what you asked for rather than what you needed. Nonetheless:
myobj = {
'item1': {'key1':'value1'},
'item2': {'key2':'value2'}
};
function getMyObjItem(key) {
return {
value: myobj[key]["key" + key.replace("item", "")],
getValue: function() {
return this.value;
}
};
}
var value = getMyObjItem('item2').getValue(); // will return "value2"
Note that this will only work if you maintain the exact property scheme that you demonstrated in the example.

javascript: dynamic call of nested function

in an existing implementation (can't change the structure much), i'm trying to call a function which is nested inside another function:
function outer(innerFunction, obj) {
//TODO: call innerFunction here, passing obj as first parameter
function inner1(obj) {
alert(obj.key);
}
}
outer('inner1', {key:'value'});
jsfiddle is here: http://jsfiddle.net/tbyyw/
i've alreay thought about using eval(), but i don't know how to pass an object - and they say 'eval is evil' ;)
another solution i've come up with is checking the innerFunction string, but this means i have to know which inner functions exist (besides, adding new functions would mean having to write extra checks then):
if(innerFunction == 'inner1') inner1(obj);
so is there another way without changing the overall implementation?
Without changing the overall structure eval appears to be the only option:
function outer(funcName, obj) {
var func = eval(funcName);
func(obj);
function inner1(obj) {
alert(obj.key);
}
}
There's nothing particularly "evil" about eval as long as you have full control over the code, but if you want, you can insert an additional security check:
if (funcName.match(/\W/))
throw "invalid function name!";
var func = eval(funcName);
This will raise an exception if someone tries to pass anything else than a simple identifier, i.e. a function name.
Is this what you wanted?
function outer(innerFunction, obj) {
var fn = {
inner1: function (obj) {
alert(obj.key);
}
};
fn[innerFunction](obj);
}
outer('inner1', {key:'value'});
http://jsfiddle.net/tbyyw/1/
A simple switch statement would be least intrusive. Or is the function name completely dynamic?
function outer(innerFunction, obj) {
switch (innerFunction) {
case "inner1": inner1(obj); break;
}
function inner1(obj) {
alert(obj.key);
}
}
outer('inner1', {key:'value'});
​

How to create javascript function lookup object?

I'm attempting to create a function lookup in Javascript essentially mapping a data type to a function that does something for that data type. Right now I have something similar to:
var Namespace = Namespace || {};
Namespace.MyObj = function () {
var stringFunc = function(someData) {
//Do some string stuff with someData
};
var intFunc = function(someData) {
//Do some int stuff with someData
};
var myLookUp = {
'string': stringFunc,
'int' : intFunc
};
return {
PublicMethod: function (dataType, someData) {
myLookUp[dataType](someData);
}
};
} ();
When I invoke Namespace.MyObj.PublicMethod(dataType, someData) I get an error that myLookUp is not defined. I'm assuming I'm not going about setting up the function lookup object correctly, but not sure how to do so. Thanks for any help.
The problem might simply be incorrect case
myLookup[dataType](someData);
should be (notice the capital U)
myLookUp[dataType](someData);
Just looked at my post after I wrote it up, stupid oversight, I'm declaring the properties as strings, instead of just properties.
....
var myLookUp = {
string: stringFunc,
int: intFunc
};
....
Fixes the issue.
Some additional follow up, in my actual code dataType is the result of a jQuery select. Don't know why or if this would be browser dependant (I'm using FireFox), but using double quotes around the property definition works, single quotes does not, and no quotes works as well. :-\

Why does this function return as undefined?

String.prototype.parse = function(f) {
alert(this.replace(f, ""));
};
var a = "Hello World";
parse.apply(a, ["Hello"]);
Is the code correct?
No, that’s not correct. The function is defined as String.prototype.parse, so it is not available as parse (in fact, parse is undefined).
You could run it like the following:
String.prototype.parse.apply(a, ["Hello"]);
But actually, the reason why you add the function to the prototype of String is that you extend String objects with that function. So you actually should just run the function like this:
a.parse("Hello");
edit:
Oh, and in response to your question title “Why does this function return as undefined?”: The function doesn’t return anything, because you don’t tell the function to return anything. You could for example define it like this to return the replaced string (instead of alerting it):
String.prototype.parse = function(f) {
return this.replace(f, "");
};
And then you could alert the return value of the function:
alert(a.parse("Hello"));
There is no such variable parse defined in your code sample. If you really want to apply the function later on, you should do this:
// Capture function as a local variable first
var parse = function(f) { alert(this.replace(f, "")); };
String.prototype.parse = parse;

Categories