jQuery extent JSON array parameter replace - javascript

I am trying to understand jquery extend method , As per the API documentation
The merge performed by $.extend() is not recursive by default; if a
property of the first object is itself an object or array, it will be
completely overwritten by a property with the same key in the second
or subsequent object. The values are not merged.
It says array or object property will not merged and will be replaced . In below example parameter is JSON array and it is getting merged instead of getting replaced .
var a = {
external : true,
parameter : [{name:'ip1'},{name:'ip2'},{name:'ip3'}]
};
var b = {
data:'Sumeet',
parameter : [{name:'ip1'},{name:'ip2'}]
};
$.extend(true,a,b);
console.log(a);
Output :
{
data: "Sumeet",
external: true,
parameter: [{
name: "ip1"
}, {
name: "ip2"
}, {
name: "ip3"
}]
}
The parameter should have only ip1 and ip2

Note that your citation says "by default". The documentation later also says:
However, by passing true for the first function argument, objects will be recursively merged.
Full paragraph:
The merge performed by $.extend() is not recursive by default; if a property of the first object is itself an object or array, it will be completely overwritten by a property with the same key in the second or subsequent object. The values are not merged. This can be seen in the example below by examining the value of banana. However, by passing true for the first function argument, objects will be recursively merged.

Related

How to filter Object using Array.prototype.filter?

Given
var arr = [1,2,true,4,{"abc":123},6,7,{"def":456},9,[10]]
we can filter number items within array arr using Number constructor
var res = arr.filter(Number); // [1, 2, true, 4, 6, 7, 9, Array[1]]
are true and [10] expected in resulting array ? If we substitute false for true at arr
var arr = [1,2,false,4,{"abc":123},6,7,{"def":456},9,[10]]
var res = arr.filter(Number) // [1, 2, 4, 6, 7, 9, Array[1]]
using Array.isArray
var res = arr.filter(Array.isArray) // [Array[1]]
String
var res = arr.filter(String) // [1, 2, true, 4, Object, 6, 7, Object, 9, Array[1]]
If we want to filter items within arr that are object, at indexes 4 , 7 and we try
var res = arr.filter(Object) // [1, 2, true, 4, Object, 6, 7, Object, 9, Array[1]]
Although we would prefer to simply call arr.filter(Object), we could pass a function call; trying different properties of Object so that we can eventually find a property or method that we could use as a function or constructor to pass to as the pattern arr.filter(/* method, constructor, other approach */) to return the filtered results matching the object, or even property name or value of the object within the input array.
We start, innocently enough, by checking if the item in the array has a constructor having name equal to "Object"
var res = arr.filter(function(prop) {
return prop.constructor.name === "Object"
}) // [Object, Object]
though when we add an object to arr; e.g.;
var c = Object.create(null); arr.push(c);
var res = arr.filter(function(prop) {
return prop.constructor.name === "Object"
}) // `Uncaught TypeError: Cannot read property 'name' of undefined`
as c prototype and constructor are undefined. Although we are certain that this will not return expected results
var n = arr.filter(Object.hasOwnProperty, "abc"); // [1, 2]
at least an error was not returned; let us continue
var n = arr.filter(function(prop, val) {
return prop.hasOwnProperty(this.valueOf())
}, "abc"); // [Object abc: 123__proto__: Object]
the expected results are returned; though we are trying to use
var n = arr.filter(/* function reference */, this /* optional parameters passed */)
to
filter an array for Object : {} objects; even if the object does not have a defined prototype or constructor; optionally converting JSON string "{"abc":123}" to object; though we have not reached this far, yet;
pass a property name to .filter(callback, this) pattern where this serves as property name, or value of object; or utilize an approach using filter.bind , .call or .apply or other method to filter an object from the input array - without using full
.filter(function(prop, value) {})
pattern. How can we coerce the Object.hasOwnProperty() call into a pattern similar to
.filter(Object.hasOwnProperty, "abc")
?
Mentioning .call, .bind and .apply after searching for a similar Question and finding JS Array.prototype.filter on prototype method . Though not certain how to implement approaches described in filtering both objects and objects having specific properties as described above.
Note, Question can also be resolved by a destructuring , or other es-6, es-7 approach, providing comparable or, even stricter results, when compared to .filter(). That is, use .filter() without
function(prop, value) {
}
pattern. Returning objects; that is Object , {} ; and objects filtered by property ; objects filtered by property value.
Questions:
How to filter objects with or without Object prototype or constructor within in an array passed to Array.prototype.filter() without using an anonymous function callbackpattern ?
How to filter specific objects within an array passed to Array.prototype.filter() by passing property name or value to match object without using anonymous function callback pattern ?
How to filter objects with or without Object prototype or constructor
within in an array passed to Array.prototype.filter() without using an
anonymous function callbackpattern ?
As per spec
callbackfn should be a function that accepts three arguments and
returns a value that is coercible to the Boolean value true or false
Number object (function's constructor) does return NaN for bad Number conversion but String and Object constructors don't return a false value (yes, filter(Number) also filters out 0)
var arr = [0,1,2,true,4,{"abc":123},6,7,{"def":456},9,[10]];
arr.filter(Number); //outputs [1, 2, true, 4, 6, 7, 9, Array[1]]
You can create a customer function OBJ,
function OBJ(value,index,arr){ return typeof value === "object" && !Array.isArray(value) }
or Arrays are also welcome in the resultset then remove the Array.isArray check
function OBJ(value,index,arr){ return typeof value === "object" }
when used with
arr.filter(OBJ); //outputs [{"abc":123},{"def":456}]
There is no real way to do it safely without creating your own function. Additionally it is very complicated because the definition of Object is too broad.
Let's start with the following:
var types = ['1', 2, true, null, undefined, [], {}, new Date()];
and run the following:
types.map((e) => typeof e);
// ["string", "number", "boolean", "object", "undefined", "object", "object", "object"]
Do you think of null of as an Object? I don't think so. Do you think of an Array as of an Object, because the Array is an instance of Object? I am not sure as well.
What you can try is the following:
types.map(Object.isExtensible);
// [false, false, false, false, false, true, true, true]
This excludes the null from the result but still the array is present here. The Date Object is here as well as any other Object with any prototype, e.g. new Boolean() will also be an Object. Additionally the object could be frozen and this won't be returned as an Object here as well.
So the both examples here successfully demonstrate that the definition of Object is too broad and it cannot be really handled in a useful way.
You seem to want to filter an array for elements with a certain type. Pass an appropriate function to filter:
array.filter(istype("String"))
You just need to write istype now:
function istype(type) {
return function(x) {
return Object.prototype.toString.call(x) === '[object ' + type + ']';
}
}
You seem to have thought you could filter for numbers by saying filter(Number) etc. But that will not work. Number is just another function, which tries to turn something into a number (not check if it's a number). Then, filter filters the array depending on whether the result is truthy or falsy. Number will produce a truthy value for any non-zero number obviously, and true. For a string, or an object, or pretty much anything else, it will return NaN, which is falsy, with odd exceptions such as returning 0 for [] or an all-blank string.
Same with string. String is just another function, which tries to turn something into a string. Then, filter filters the array depending on whether the result is truthy or falsy. String will produce a truthy value for almost anything other than a non-empty string.
This has nothing whatsoever to do with destructuring; why would you think it does? You might want to remove that unfortunate part of your post. Nor is it clear what you mean by "calling filter without a callback"--using a callback to determine which elements to filter in and out is the entire DNA of filter. It is also unclear what pattern you are referring to when you say function(prop, value) { } pattern.
At the end of your question, you ask two specific questions:
How to filter objects with or without Object prototype or constructor within in an array passed to Array.prototype.filter() without using an anonymous function callbackpattern ?
You filter objects from an input array by providing a function which determines if a particular element is an object. That is not what the object prototype or constructor Object is, so that won't help you. You have to write a little function to pass to filter, that's how it works. It could be anonymous, or it could be defined elsewhere and passed in
How to filter specific objects within an array passed to Array.prototype.filter() by passing property name or value to match object without using anonymous function callback pattern ?
What do you mean by "passing property name or value to match object"? Do you mean, filter out elements which are missing a particular property name or value? Then write a function to do that. There is no built-in function for this purpose, if that is what are looking for.
Without passing a callback function, you can instead pass in a regex by using the RegExp.prototype.test method and binding a regex
var arr = [1,2,true,4,{"abc":123},6,7,{"def":456},9,[10]]
var res = arr.filter(RegExp.prototype.test.bind(/\[object Object\]/));
console.log(res)
This would match any string containing [object Object] as well, but it seems highly unlikely that a string would contain those exact words, unless you have made a mistake and included stringified objects in your array.
In ES6 the following would do it for the example values you have listed:
arr.filter(Object.isExtensible)
Obviously, this will exclude objects that have been marked non-extensible, by a call to Object.freeze, Object.seal, or Object.preventExtensions. Unless you plan to use those, I believe this does the job.
var arr = [
/* primitives: */
2, true, "str", null, undefined, NaN,
/* objects */
new Number(2), {a:1}, Object.create(null), [10], x=>x, new Date(), new Set()
];
var objects = arr.filter(Object.isExtensible);
console.log(objects);
The closest have been able to reach to requirement so far, also matches Object.create(null)
var res = []; for (let p of arr) /^\{?.+\}$/.test(JSON.stringify(p)) && res.push(p)

Acessing JSON Information by order

I am reading information from a JSON string, and when I execute
console.log(record.seenTime.time.seenEpoch)
it display the right information.
But when I use console.log(record.seenTime.time[0].seenEpoch), I get an error saying :
TypeError: Cannot read property 'seenEpoch' of undefined.
Here is an example set of data:
{
seenTimes: {
time: {
seenTime: '2014-09-10T20:18:32Z',
seenEpoch: 1410380312
}
}
}
Anyone know what am I doing wrong?
Thanks
record.seenTimes in this case is an Object, not an Array, you can verify that using
typeof record.seenTimes
Because of that, time[0] returns undefined.
seenEpoch is a property of the ONE AND ONLY time object, therefore, you access it using record.seenTimes.time.seenEpoch
For once, I'll recommend reading something from w3schools : JSON Syntax
It'll show you examples of what can be stored in JSON.
EDIT :
Your sample record.seenTimes will not be able to store multiple time objects, as it uses the curly brackets {} which indicate that it's meant to store an object , if you want to be able to store multiple time objects, ie: an Array, your JSON will have to look like :
record {
seenTimes: [
{
time: {
seenTime: '2014-09-10T20:18:32Z',
seenEpoch: 1410380312
}
},
{
time: {
seenTime: '2014-09-10T20:18:32Z',
seenEpoch: 1410380312
}
}
]
}
Note the square brackets that say that seenTime holds an array.
And as slebetman noted :
Also note that in javascript, an object defined as having multiple
identical keys are technically invalid. But most implementations take
the last definition. For example, the object: {a:1,a:2,a:3} is exactly
the same as {a:3}. So if you don't use an array then there is only one
time object even if it appears twice in the JSON string.

Is it always required to call an object all the way through the chain (or in order)?

I'm trying to look through reddit's API. I have seen a fiddle where they grab the image url from the site. However, I'm confused as to how they are getting the objects themselves. In theireach()statement, they used data.data.children and item.data.url, however I cannot find a data object right after another data object in the json here http://www.reddit.com/r/pics.json. I also do not see item.data.url. if I look from the very beginning (the two first objects are "kind" and "data"). What does this mean?
Given the code in the fiddle:
$.getJSON("http://www.reddit.com/r/pics/.json?jsonp=?", function(data) {
$.each(data.data.children, function(i,item){
$("<img/>").attr("src", item.data.url).appendTo("#images");
});
});
data and item are both function parameters, and their names have no relation to any named key within the JSON.
The parameter data represents the entire JSON structure, but as it's just a parameter whose name is not significant I shall call it foo instead to disambiguate it from the contents of that structure, hence foo.data refers to the child element named data within the first level of the JSON.
The item parameter represents each element in the array foo.data.children, so item.data.url for the first item would be equivalent to data.children[0].data.url within the JSON.
The structure of the JSON returned is:
{
data: {
after: "",
before: null,
children: [
{
data: {
url: ""
}
},
...
],
modhash: ""
},
kind: "Listing"
}
The name of the result variable is called data in the callback function parameters. So to get to the children you need to type:
data.data.children;
Next, in the $.each loop, each entry from the children array is assigned to an item variable in that callback function. It is from there where you drill down to the url. property (item.data.url).
You could name these whatever you want if data.data is confusing.

ngRepeat through entries in map and filter entries

I have an ngRepeat on a Map that gives me a "(key, value)" pair for each iteration. I now need to write a filter on this to limit some of the results I get back. I defined my filter to have two parameters. I pass one parameter in the ngRepeat call, so I should expect to get two parameters. The parameter I manually pass is a boolean. In the debugger both of those parameters were set, and the second parameter was "true", which is what I was passing, so I would expect the first parameter to correspond to my "(key, value)" pair. What I got for the first parameter was an essentially empty Object.
The reference in my HTML looks like this:
<div ng-repeat="(name, thing) in thingMap | limitThings:showOnlyFailed">
The "thingMap" is a map keyed by a "name" property, whose values are "thing" objects.
Here's my filter definition, representing what I expected to see in that first parameter:
thingModule.filter("limitThings", ['ThingsService', function(ThingsService) {
return function(entry, showOnlyFailed) {
return !showOnlyFailed || ThingsService.anyFailuresInList(entry.thing);
};
}]);
When I get into the debugger, the value of "entry" is just "Object {}".
You see thingMap as argument named entry. If you got an empty object, then you thing map is empty.
I've created a small plunk http://plnkr.co/edit/miipnB?p=preview where you can see that hash map of your things are passed corectly.
I think what just-boris is saying is correct, but I modified his example to make it a little clearer. When you use ng-repeat with an object, then the whole object is passed into the filter, not each entry.
I did some filtering with angular.forEach based on a 'failed' property in the value of the object.
http://plnkr.co/edit/B2WOiSm2vZiQBKS1wlmJ?p=preview
app.filter('limitThings', function() {
return function(entry, showOnlyFailed) {
console.log("Entry: " + entry + " Only Failed: " + showOnlyFailed);
var filteredMap = {};
angular.forEach(entry, function(value, key)
{
if(!showOnlyFailed || !value.failed)
{
filteredMap[key] = value;
}
});
return filteredMap;
}
});

How to create complex javascript objects

I'm trying to create a javascript object to send as a parameter.
I need to send it in this format:
params (Object) (defaults to: {}) —
Bucket — required — (String)
Delete — required — (map)
Objects — required — (Array<map>)
Key — required — (String) Key name of the object to delete.
How can I construct this object and fill it out?
I'm doing this:
var params = {
Bucket : data.bucket,
Delete: [{
Objects:[{ Key:""}] }]
};
for(i=0;i<data.keys.length;i++){
params.Delete[0].Objects.push({Key: data.keys[i]})
}
And I get an error message from the library saying that my object is missing the key Objects inside of Delete
When I console.log params I get
{ Bucket: 'ct.presentations',
Delete: [ { Objects: [Object] } ] }
What's the best way for creating objects like this?
As Alex pointed out below, map in Javascript, isn't a type of array like I thought it was, so instead of
Delete:[{
I should have done
Delete:{
You've made Delete an array containing an object that has Objects as a key. Sounds like it shouldn't be an array:
var params = {
Bucket : data.bucket,
Delete: {
Objects: []
}
};
for(i=0;i<data.keys.length;i++){
params.Delete.Objects.push({Key: data.keys[i]})
}
Also note that I removed the {Key: ""} from inside the [] in Objects (on the fourth line). If you really meant to have an object with an empty key as the first entry in the array, add that back, but I suspect you didn't.

Categories