I was reading through fluent api I got a doubt.
I want to take in a string upon which a jQuery function or example is called upon
Function
function compareThis(newString) {
function compare(newString) {
if (this == newString) {
alert("same string");
} else {
alert("differnt string");
}
}
}
Where it is called as
("alerting").compareThis("alerted").compare(); //alert 'different string'
I want to pass the data/string not as parameter but as called upon.
JSFiddle
Note: I would like to call the function in similar cases like finding date interval etc
You can use prototype to add function to String class:
String.prototype.compare = function(newString){
if (this == newString) {
alert("same string");
} else {
alert("differnt string");
}
};
I think you should adapt the code for your function, but it's the idea.
Maybe I missed interpreted however, it looks as it you required a form of method chaining to compare string. To do this you can create a variable and create functions inside it.
var compare = (function(){
var thisString;
var stringToCompare;
var create = function(sVal) {
thisString = sVal;
return this;
};
// Public
var compareThis = function(sVal) {
stringToCompare = sVal;
return this;
};
var compare = function(anotherString) {
return thisString == stringToCompare;
};
return {
create: create,
compareThis: compareThis,
compare: compare
};
}());
var b = compare.create('test').compareThis('test').compare();
alert(b);
Example fiddle
Related
Ok, so I'm a complete newbie to OOP in Javascript, apparently. I thought I understood it, but it appears I only know a small portion. Anyway, what I'm trying to do is setup an object to store and return data from an XML input by using a fairly simple string to retrieve data. I'd like to retrieve the data with a string similar to reader.getItem().getSubItem() or something like that.
Below is an example of what I attempted, but I get the error anonymous is not a function each time I try to do a call to fr.getType().isTexture() so obviously, I need to change something.
//Create the object by passing an XML element containing sub-elements
var fr = new FeatureReader(test.child(i));
alert(fr.getName()); //returns the object's name
alert(fr.getType().isTexture()); //"anonymous is not a function" error
function FeatureReader(feature) {
var feat = feature;
this.getName = function() {
return feat.name;
};
this.getType = new function() {
this.isTexture = new function() {
if (feat.type.texture == "yes") {
return true;
}
return false;
};
this.isModel = new function() {
if (feat.type.model == "yes") {
return true;
}
return false;
};
};
}
Now, obviously I could just remove the surrounding this.getType = function() {} around the this.isTexture and this.isModel to get my data, but for the sake of learning something, I'd like to see how it is recommended that I set this object up to get the returned values using a string similar to what I mentioned in the first and second paragraphs.
When you do this:
this.isTexture = new function() {
if (feat.type.texture == "yes") {
return true;
}
return false;
};
you're setting the "isTexture" property to the object constructed, not to that function. If you drop the new keyword from the statement, you'll be setting "isTexture" to be a function.
An expression of the form new <some-function> evaluates to an object, in other words.
edit — your "getType" property will also be an object, for the same reason. However, I think this would work:
alert( fr.getType.isTexture() );
Also note that your if statement can be simplified:
return feat.type.texture == "yes";
What you can do is simply assign an object instead of using new:
function FeatureReader(feature) {
var feat = feature;
this.getName = function() {
return feat.name;
};
this.getType = {
isTexture: function() {
return feat.type.texture == "yes";
},
isModel: function() {
return feat.type.model == "yes";
}
};
}
Then use the method like:
instance.getType.isTexture()
Note that you don't need to return true or false, as returning an expression that evaluates to boolean like a == b
returns a boolean value.
I wrote this fast-templating function:
var templatize = function(string) {
return function (string) {
return string.replace(/{{(.*?)}}/g, function(pattern, match) {
value = this[match];
if (value) {
return value;
} else {
return pattern;
}
});
}.call(this, string);
}
Which does this:
var foo = "bar", bar = "foo";
templatize("We are {{foo}} and {{bar}}, but not {{crazy}}"); // "We are bar and foo but not {{crazy}}"
I'm quite happy with this except that I have scoping problem. For sure, the templatize method will be accessible through namedscope, but then, the current context of execution of templatize is not accessible in my function automatically.
Something like calling $.proxy(templatize, this)("We are {{foo}} and {{bar}}, but not {{crazy}}") should work, right?
But I'd like to achieve this without needing to call $.proxy() (and without any jQuery preferably) so that context is automatically transfered to the execution one.
I'm struggling with .call(), .apply(), and other closures, but I think I read somewhere over the internet that it was possible. Thanks
You can avoid using jQuery doing this :
var templatize = function(string) {
var me = this; // the data source
return string.replace(/{{(.*?)}}/g, function (full, key) {
// "this" refers to the string itself
return me[key] || full;
});
}
In case you want to use jQuery.proxy(), wrap the replacement function :
var templatize = function(string) {
return string.replace(/{{(.*?)}}/g, jQuery.proxy(function (full, key) {
// "this" now refers permanently to the data source
return this[key] || full;
}, this));
}
In both cases you can bind the data source to this using call :
templatize.call({ hello: 'Hi!' }, '{{hello}}');
Going further
You could optimize by compiling the template for reuse :
function compile(tpl) {
var i = -1, tmp = [];
tpl = tpl.split(/{{([^{}]+)}}/);
while (++i < tpl.length) {
if (i % 2) tmp.push('this["' + tpl[i] + '"]');
else if (tpl[i]) tmp.push('"' + tpl[i].replace(/"/g, '\\"') + '"');
}
return new Function(
'return [' + tmp.join() + '].join("");'
);
}
Usage example :
var tpl = compile('{{hello}} {{hello}}');
tpl.call({ hello: 'Hi!' }); // "Hi! Hi!"
tpl.call({ hello: 'Yo!' }); // "Yo! Yo!"
Regarding the example above, here is the function returned by compile :
function () {
return [this["hello"]," ",this["hello"]].join("");
}
Note that you can use an array as well :
var tpl = compile('{{1}} {{0}}');
tpl.call(['a', 'b']); // "b a"
Performance test : http://jsperf.com/template-compiling.
why don't you pass an object containing the view variables? would be cleaner then potentially displaying any existing variable in your view.
var templatize = function(string, variables) {
return function (string) {
return string.replace(/{{(.*?)}}/g, function(pattern, match) {
value = variables[match];
if (value) {
return value;
} else {
return pattern;
}
});
}.call(this, string);
}
Instead of just saying:
var thing = timeConsumingMethod();
I have my variable hidden in a method like so:
function _thing() {
var thing = timeConsumingMethod() );
return thing;
}
It gets called a number of times. I'm concerned that I'm made things very inefficient. I assume it calls timeConsumingMethod every time (which is unneeded, it's always the same) I call "_thing()" to get my variable.
How do I manage these types of variables in simple efficient way? Is something like this a solution?:
function _thing() {
return _thing.thing
}
_thing.thing = timeConsumingMethod();
Basically, i want the protection of a function and to (ideally0 access my variable using _thing() or something similar, but I only want timeConsumingMethod to run once.
edit: tried this, doesn't work either:
function _thingy() {
var thing = timeConsumingMethod();
}
_thingy.test = function() {
return( _thingy.thing)
}
Why not just:
function SomethingTimeConsuming() { ... }
function LazyThing(sourceFunction) {
this.sourceFunction = sourceFunction;
this.value = null;
this.Value = function() {
if ( this.value == null) this.value = sourceFunction();
return this.value;
}
}
JSFiddle: http://jsfiddle.net/YSAjJ/
Output:
[14:20:20.079] Calling time-consuming function *(1 time)
Is there any ways to short-up such chain call?
if (obj && obj.prop && obj.prop.subProp1 && obj.prop.subProp1.subPropFunc) {
obj.prop.subProp1.subPropFunc();
}
The only alternative I can imagine is try-catch. Any other ideas?
*I really tired of writing these. It's much easier in coffeescript using ?..
This should work given your sample code (haven't tested "all cases", just a copy of your sample):
function propsExist(obj) {
if (!obj) return false;
for (var i = 1; i < arguments.length; i++) {
if (!obj[arguments[i]]) return false;
obj = obj[arguments[i]];
}
return true;
}
if (propsExist(obj, "prop", "subProp1", "subPropFunc")) {
obj.prop.subProp1.subPropFunc();
}
The method propsExist() takes a variable number of arguments, the first of which being the original object you want to check properties/functions on. It will iterate through the list of properties you send to it and check them in-order. If one doesn't exist, it will return false. If it makes it through the whole loop, it validated successfully!
If you always want to call the sub-property's function if it validates, you could also just change the propsExist function to call it instead of returning true (then rename the function to something like callIfValid(obj, ...)
Same idea as the previous post, just a different solution.
function checkChain(variablePath,startingPoint){
var check = startingPoint || window,
parts = variablePath.split("."),
i;
for (i=0;i<parts.length;i++) {
check = check[parts[i]];
if (!check) {
return null;
}
}
return check;
}
var foo = { bar : { cat : { says : function(x){ alert(x); } } } };
var test1 = checkChain("foo.bar.cat.says");
if (test1) {
test1("meow");
}
var test2 = checkChain("foo.bar.cat.bark");
if (test2) {
test2("burp");
}
var test3 = checkChain("cat.says",foo.bar);
if (test3) {
test3("huh?");
}
I have a json object retrieved from server in my $(document).ready(...); that has an string that I would like to resolve to a function also defined within $(document).ready(...); so, for example:
$(document).ready(function{
$.getJSON(/*blah*/,function(data){/*more blah*/});
function doAdd(left,right) {
return left+right;
}
function doSub(left,right) {
return left-right;
}
});
with json string:
{"doAdd":{"left":10,"right":20}}
One way I thought about was creating an associative array of the function before loading the json:
var assocArray=...;
assocArray['doAdd'] = doAdd;
assocArray['doSub'] = doSub;
Using eval or window[](); are no good as the function may not be called for some time, basically I want to link/resolve but not execute yet.
Change your JSON to
{method: "doAdd", parameters : {"left":10,"right":20}}
Then do
var method = eval(json.method);
// This doesn't call it. Just gets the pointer
Or (haven't tried this)
var method = this[json.method]
How about something like this?
$(function(){
// Function to be called at later date
var ressolvedFunc = null;
// Ajax call
$.getJSON(/*blah*/,function(data){
// Generate one function from another
ressolvedFunc = (function(data) {
var innerFunc;
var left = data.left;
var right = data.right;
// Detect action
for (action in data) {
if (action == "doAdd")
innerFunc = function() {
return left + right;
};
else
innerFunc = function() {
return left - right;
};
}
return innerFunc;
})(data);
});
});
The anonymous function returns fresh function, with the new values stored within the enclosure. This should allow you to call the function at later date with the data previously retrieved from the GET request.
Rich
try this:
var doX = (function() {
var
data = [],
getDo = function(action) {
for(var d in data) {
if (data[d][action]) {
return data[d];
}
}
return null;
};
return {
set: function(sdata) {
data.push(sdata);
},
doAdd: function() {
var add = getDo("doAdd");
if (!add)
return 0;
return add.doAdd.left + add.doAdd.right;
},
doSub: function() {
var sub = getDo("doSub");
if (!sub)
return 0;
return sub.doAdd.left + sub.doAdd.right;
}
};
})();
$(document).ready(function{
$.getJSON(/*blah*/,function(data){ doX.set(data); });
});