I am creating a variable where its value is determined by a particular method. This particular method should return an object with two properties. However, after the method returns the variable is undefined. I check the objects value right before it's returned and its fine. So there is something happening between the return and instantiate of the variable that causes it to be undefined. Here is a code snippet:
var results = findTarget(target, after, append); //undefined
function findTarget(target, after, append){
var currenttemplate = $(target).attr('data-template');
for(var i=0; i<after.length; i++){
if(after[i] === currenttemplate)
return {target : target, drop : "after"};
}
for(var j=0; j<append.length; j++){
if(append[j] === currenttemplate){
var obj = {target : target, drop : "append"};
console.log(obj); //is fine here
return obj; //this gets returned
}
}
if(currenttemplate === threshold) {
return "";
}
findTarget($(target).parent()[0], after, append);
}
You need to add a return at the end:
function findTarget(target, after, append){
/* ... */
return findTarget($(target).parent()[0], after, append);
}
If not, you call recursively findTarget, and this recursive call returns the appropriate value, but the first call to findTarget doesn't return it.
Related
I have the next object:
var persons= {};
persons["Matt"].push("A");
persons["Matt"].push("B");
persons["Matt"].push("C");
And I want to know if the object contains the element which I try to insert.
E.g:
persons["Matt"].push("A"); /* The element A already exist... And I don't want duplicate elements.*/
Anybody know one way to make it?
EDIT WITH MORE DETAILS:
I have a the next code:
function insertIfNotThere(array, item) {
if (array.indexOf(item) === -1) {
array.push(item);
}
}
function EventManager(target) {
var target = target || window, events = {};
this.observe = function(eventName, cb) {
if (events[eventName]){
insertIfNotThere(events[eventName], cb);
}else{
events[eventName] = []; events[eventName].push(cb);
}
return target;
};
this.fire = function(eventName) {
if (!events[eventName]) return false;
for (var i = 0; i < events[eventName].length; i++) {
events[eventName][i].apply(target, Array.prototype.slice.call(arguments, 1));
}
};
}
I use your method for checking if the element with the content indicated exist. But... It push the element ever... I don't know what's happening...
First things first. When you do
persons= {};
you are creating a global property called persons and assigning an empty object to it. You might want a local variable here. So, change it to
var persons = {};
And then, when you create a new key in the object, by default, the value will be undefined. In your case you need to store an array. So, you have to initialize it like this
persons['Matt'] = [];
and then you can use the Array.prototype.indexOf function to find out if the item being added is already there in the array or not (it returns -1 if the item is not found in the array), like this
if (persons['Matt'].indexOf("A") === -1) {
persons['Matt'].push("A");
}
if (persons['Matt'].indexOf("B") === -1) {
persons['Matt'].push("B");
}
You can create a function to do this
function insertIfNotThere(array, item) {
if (array.indexOf(item) === -1) {
array.push(item);
}
}
var persons = {};
persons['Matt'] = [];
insertIfNotThere(persons['Matt'], 'A');
insertIfNotThere(persons['Matt'], 'B');
// This will be ignored, as `A` is already there in the array
insertIfNotThere(persons['Matt'], 'A');
Use indexOf to check for the existence of A. If it doesn't exist (is -1), add it to the array:
if (persons['Matt'].indexOf('A') === -1) {
persons['Matt'].push('A');
}
In below code I'm attempting to add a function test to an Array. The function test contains a parameter param1 :
var param1 = "param1"
var fArr = []
fArr.push(test(param1));
for (var i = 0; i < fArr.length; i++) {
fArr[i](param)
}
function test(param){
console.log('param is '+param)
}
When I run this code I receive error :
Uncaught ReferenceError: param is not defined
How can I pass a parameter to the function that is added to array fArr ?
You're not adding a function to the array. You're calling the function, and adding what it returns to the array. But the function doesn't return anything, so you're pushing undefined onto the array.
What I think you want is:
var param1 = "param1";
var fArr = [];
fArr.push(function() {
test(param1));
});
for (var i = 0; i < fArr.length; i++) {
fArr[i]();
}
function test(param){
console.log('param is '+param);
}
P.S. Get out of the bad habit of omitting ; at the end of statements.
The error is here: fArr[i](param). You never initialized variable param.
Are you sure you do not want to use param1?
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 am struggling to understand how this JavaScript code work. I am learning JS, and not exposed to a dynamic, functional language before. So, I visualize function calls in bit procedural, hierarchical order. With d3.js, one can draw svg elements as explained here
var dataset = [ 5, 10, 15, 20, 25 ];
d3.select("body").selectAll("p")
.data(dataset)
.enter()
.append("p")
.text("New paragraph!");
Let’s change the last line:
.text(function(d) { return d; });
Check out what the new code does on this demo page.
Whoa! We used our data to populate the contents of each paragraph, all thanks to the magic of the data() method. You see, when chaining methods together, anytime after you call data(), you can create an anonymous function that accepts d as input. The magical data() method ensures that d is set to the corresponding value in your original data set, given the current element at hand.
This magic, mentioned above is what I fail to understand. "d" is not a global variable, as if I change to another (c) name, it still works. So, the data method may be setting the value for the anonymous fn.
But, typically(with my limited reading) chaining is possible because the current function returns an object, on which the next method can be invoked. In the above case, how data method knows whether a text ("New paragraph!") is passed by the user, otherwise pass the data to the anonymous fn. The doubt is, the text method is down the line and data() is already executed. How the data is passed to the anonymous function?
thanks.
Digging into d3.js internals shows the following result for text function:
d3_selectionPrototype.text = function(value) {
return arguments.length < 1
? this.node().textContent : this.each(typeof value === "function"
? function() { var v = value.apply(this, arguments); this.textContent = v == null ? "" : v; } : value == null
? function() { this.textContent = ""; }
: function() { this.textContent = value; });
};
In case the supplied argument is a function, the following code gets executed:
this.each(function() {
var v = value.apply(this, arguments); // executing function provided
this.textContent = v == null ? "" : v;
});
Function each is declared as:
d3_selectionPrototype.each = function(callback) {
for (var j = -1, m = this.length; ++j < m;) {
for (var group = this[j], i = -1, n = group.length; ++i < n;) {
var node = group[i];
if (node) callback.call(node, node.__data__, i, j); // this is the line you are interested in
}
}
return this;
};
so on each invocation it supplies an element from this. And, getting down to it, this is populated by data function invocation.
Well, I have never used d3 before, but this is what I understand.
d is the data object (I would call it data instead of d had set in the data() method.
So what does the text() method does? Will it will call the function and use it's output, something like this:
function text (callback) {
var theText;
if (typeof callback === "function") {
theText = callback(dataset);
} else {
theText = callback;
}
// does something more
}
So, if callback is a function call it, and use its return value as text.
Then, what I'm guessing, is that if the function is an array, it will call the text method for each element in the array.
Something like this...
function text(callback) {
var theText;
if (typeof callback === "function") {
theText = callback(dataset);
} else {
theText = callback;
}
if (theText instanceof Array) { // this is not the best way to check if an object is an array, I'll come back to this later. I'm sorry.
for (var i=0, len=theText.length; i<len; i++) {
text(theText[i]);
}
} else {
// do something else
}
// do something more
}
please take into account that this would be a really simple version of what really happens.
If it's not clear enough please let me know.
From the node REPL thing,
> d = {}
{}
> d === {}
false
> d == {}
false
Given I have an empty dictionary, how do I make sure it is an empty dictionary ?
function isEmpty(obj) {
return Object.keys(obj).length === 0;
}
You could extend Object.prototype with this isEmpty method to check whether an object has no own properties:
Object.prototype.isEmpty = function() {
for (var prop in this) if (this.hasOwnProperty(prop)) return false;
return true;
};
How about using jQuery?
$.isEmptyObject(d)
Since it has no attributes, a for loop won't have anything to iterate over. To give credit where it's due, I found this suggestion here.
function isEmpty(ob){
for(var i in ob){ return false;}
return true;
}
isEmpty({a:1}) // false
isEmpty({}) // true
This is what jQuery uses, works just fine. Though this does require the jQuery script to use isEmptyObject.
isEmptyObject: function( obj ) {
for ( var name in obj ) {
return false;
}
return true;
}
//Example
var temp = {};
$.isEmptyObject(temp); // returns True
temp ['a'] = 'some data';
$.isEmptyObject(temp); // returns False
If including jQuery is not an option, simply create a separate pure javascript function.
function isEmptyObject( obj ) {
for ( var name in obj ) {
return false;
}
return true;
}
//Example
var temp = {};
isEmptyObject(temp); // returns True
temp ['b'] = 'some data';
isEmptyObject(temp); // returns False
I'm far from a JavaScript scholar, but does the following work?
if (Object.getOwnPropertyNames(d).length == 0) {
// object is empty
}
It has the advantage of being a one line pure function call.
var SomeDictionary = {};
if(jQuery.isEmptyObject(SomeDictionary))
// Write some code for dictionary is empty condition
else
// Write some code for dictionary not empty condition
This Works fine.
If performance isn't a consideration, this is a simple method that's easy to remember:
JSON.stringify(obj) === '{}'
Obviously you don't want to be stringifying large objects in a loop, though.
You'd have to check that it was of type 'object' like so:
(typeof(d) === 'object')
And then implement a short 'size' function to check it's empty, as mentioned here.
If you try this on Node.js use this snippet, based on this code here
Object.defineProperty(Object.prototype, "isEmpty", {
enumerable: false,
value: function() {
for (var prop in this) if (this.hasOwnProperty(prop)) return false;
return true;
}
}
);