How to modify object property values while enumerating - javascript

An API call I'm making returns empty objects in lieu of null. Tedious doesn't like this, so before I save the API response I'm cleaning the data with the following function:
var object_to_return = input_object;
_.forOwn(object_to_return, function(key_value) {
if (_.isEmpty(key_value)) {
object_to_return[key_value] = null;
}
});
return object_to_return;
This isn't quite correct and I'm curious if anyone knows why and how I can fix it. I'm especially interested in the why and if I should bother with even returning a copy of the object (is it being passed in by reference, or...?)

_.forOwn exposes the key in the callback function; therefore, this worked:
module.exports.convertEmptyObjectsToNull = function(target_object) {
_.forOwn(target_object, function(property, key) {
if (_.isEmpty(property)) {
target_object[key] = null;
}
});
}
Also, as #apsillers mentioned, I wasn't doing much with my assignments, so this method just mutates the input object and doesn't attempt to clone it and return a copy.

Related

Return an array with the result of calling a method from underscore

I'm trying to recreate the functionality of the underscore _.invoke for learning purposes and I would like to really understand how it works as it seems to be something not too complicated.
The exercise is asking me to return an array with the result of calling "a" method to it. Ok, so here we start.
_.invoke = function (collection, methodName) {
let result = [];
// debugger;
if (Array.isArray(collection)) { // check if collection is an array.
for (let i = 0; i < collection.length; i++) { // iterate over collection
result.push(Array.prototype.methodName.call(collection[i]));
}
}
console.log('result:', result);
return result;
};
I don't know exactly what method is being past to methodName nor if it has any extra arguments to be forwarded (this I understand it would be used in case I'd use a method that requires args like .reduce for instance if I'm not wrong).
As I understand, when I use the .call method on methodName, it should return (push) the iterated element with the "function" applied onto it. Obviously there is something not right, I have used the debugger to see what it does on each step and once it runs the loop and arrives to the call, it quits the loop and runs to check whatever it is it does in the config file of the test.
I get this message in the error log of the HTML file:
_.invoke(mocks.arr, 'testCall').should.eql(mocks.arr);
_.invoke(mocks.obj, 'testCall').should.eql(mocks.objValuesArr);
argsArr = [mocks.arr, mocks.obj];
_.invoke(mocks.arr, 'testArgs', mocks.arr, mocks.obj);
called.should.be.true;
called = false;
argsArr = [mocks.obj, mocks.arr];
_.invoke(mocks.obj, 'testArgs', mocks.obj, mocks.arr);
called.should.be.true;
The this, thisArg and such are still a little hard for me to understand, can someone explain to me what am I missing here..?
So, after some digging, trial and error, I was totally wrong about my approach to the exercise, so I had to re-make the whole thing.
_.invoke = function (collection, methodName) {
// Spread all arguments into a variable.
let args = [...arguments];
// Since the arguments have been all passed to args, we don't need to call them as we normally would.
// Use an already defined function (_.map) with an iteratee to be passed as method.
return _.map(args[0], function (value) {
// Return the iterated value passed through the function of _.map
// and apply the rest of arguments to the element with the function from _.map if there are any.
return value[args[1]].apply(value, args.slice(2));
});
};
I don't know much about underscore.js, but I'm pretty sure _ isn't defined at all, so maybe do window._.invoke = ... instead to properly define it.

How destructure an object starting from a constant?

I have a utils/constant.js file with:
// Key of total elements in remote collection
export const TOTAL_ELEMENTS = "totalElements";
I need to access to totalElements via the constant.
import { TOTAL_ELEMENTS } from "./constants.js";
[...]
let data = {
content: "foo",
totalElements: 54
};
if(TOTAL_ELEMENTS in data) {
// pseudocode, of course it doesn't work.
// of course in my case need to return 54
const { TOTAL_ELEMENTS } = data;
return TOTAL_ELEMENTS;
}
Edit:
As #pilchard mentioned, using Object.prototype.hasOwnProperty is a better way of doing this in case the value is falsy:
if (data.hasOwnProperty(TOTAL_ELEMENTS)) {
return data[TOTAL_ELEMENTS]
}
Original answer:
While the answer #jsN00b provided works and is closer to OP's #sineverba code, there's an issue here since the in operator checks for the specified property in both the specified object AND its prototype chain.
This means that, for example, if datas prototype is Object.prototype, something like 'toString' in data would work as well.
For that reason, you could use something like the following to only check for the 'totalElements' key in the object itself, and avoid destructuring:
if (data[TOTAL_ELEMENTS]) {
return data[TOTAL_ELEMENTS]
}
The desired objective is:
use the constant TOTAL_ELEMENTS (& not directly the prop-name)
check if data has the corresponding prop
if found, then return the value of the prop
The below code-sample may be one solution to achieve the desired objective:
if (TOTAL_ELEMENTS in data) return data[TOTAL_ELEMENTS];
NOTE
The above does not de-structure the data. It access the corresponding prop directly without the need to destructure.

Defining which method can be chained

I created a class that supports chaining by making use of return this;, and
now I need to make the current method tell what methods can be chained. Example:
class MyClass {
constructor(path) {
this.path = path;
}
method1() {
// some code here...
// i must make something here to only allow channing if it's method
// blabliblu
return this;
}
blabliblu() {
// some code here...
// same thing here, if the channing is with the method ar_2, it's ok.
return this;
}
ar_2() {
// And so on...
return this;
}
}
So, i can do: method1().blabliblu(), but i can't do method1().ar_2(). Is there lib to help me achieve this?
What you have asked for is not possible in Javascript. When you do:
return this;
in your methods, you are returning the same object. Any public method can be called on the object that is returned and there is no way to specify that because the object was returned from a method it should somehow not allow some methods to be called.
So, using the code in your example where you return this in .method1(), there's no difference between this:
obj.method1();
obj.ar_2();
and this:
obj.method1().ar_2();
That's because the chained version is essentially this internal to the JS interpreter:
let temp = obj.method1();
temp.ar_2();
So, if temp is the same as obj which it is when you return this from method1(), then obj.method1().ar_2(); is just the same as obj.method1(); obj.ar_2(); (with a little less typing). Thus, you can't prevent the calling of .ar_2().
Both just call .method1() and then .ar_2() on the same object. So you can't prevent one scheme, but allow the other. ar_2 is either a public method or it isn't. You can't have it callable in one place and not callable in another on the same object.
Now, you could make obj.method1() return a different object. If you did that, then that different object could have different methods on it and could be an object that does not have a .ar_2() method.
When you chain array methods like this:
let result = [1,2,3].map(...).filter(...);
Each step in that chain is returning a different object (they are not doing a return this, but are creating a new object and returning it. In this specific Array example, these are returning different objects, but of the same type, but you could return different objects of different types. For example:
let result = ["a","b","c"].join("").toUpperCase();
Here, .join() is an Array method, but returns a string object which you can then only call string methods on. So, you could do something like that where you return a different type of object.

Storing a pointer in javascript

Is it possible to keep an object reference without using an holder object in javascript?
Currently when an object gets overridden I sometimes lose the reference to the "current" object state illustrated in the snippet below;
Is there a way to put a "pointer" in an array or not?
EDIT
To the questions asked:
What I have in the objects I have are references to form fields. Some of these are text fields, some of them are textareas, some of them checkboxes.
I wish to keep a map next to the direct referene of what type they are.
basicaly it would be
obj {
this.text1 = createTextField();
this.text1.datepicker();
this.text2 = createTextField();
this.area1 = createArea();
this.check = createCheck();
this.datefields = [this.text1];
this.checkboxes = [this.check];
}
So I can use the datefields/checkboxes array as a checkpoint to validate against which type a field is/should behave.
Currently I use
function datefields() { return [this.text1]; };
But I'd like to know if there's a better way to do this than to intantiate a new array when I need to check it.
I know there is a way with observers to mimic pointer behaviour, and i've fiddled with those and have some good results with that, i'm just curious if there are other ways i'm not aware of.
function myObject() {
this.myvalue = null;
this.arr = [this.myvalue];
}
myObject.prototype.alter = function() {
this.myvalue = "hello";
}
var x = new myObject();
var elem = document.getElementById('results');
function log(message) {
elem.appendChild(document.createTextNode(message));
elem.appendChild(document.createElement('br'));
}
log("x.myvalue = "+x.myvalue);
log("x.arr[0] = "+x.arr[0]);
log("calling alter");
x.alter();
log("x.myvalue = "+x.myvalue);
log("x.arr[0] = "+x.arr[0]);
<div id="results"></div>
Simple answer: Only objects (including all subtypes) are passed by reference in JS. All other simple values are copied.
For a bit more detail I would recommend reading You Don't Know JS: Types & Grammer but specifically the section Value vs Reference in Chapter 2:
In JavaScript, there are no pointers, and references work a bit differently. You cannot have a reference from one JS variable to another variable. That's just not possible.
Quoting further on:
Simple values (aka scalar primitives) are always assigned/passed by value-copy: null, undefined, string, number, boolean, and ES6's symbol.
Compound values -- objects (including arrays, and all boxed object wrappers -- see Chapter 3) and functions -- always create a copy of the reference on assignment or passing.
There are plenty of examples included to show these points. I would highly recommend reading through to get a better understanding of how values/references work in JS.
There is no pointers in Javascript, though you could cheat a little using a wrapper object. Here is a minimal implementation of such an object:
var Wrapper = function (value) {
this.value = value;
};
Wrapper.prototype.valueOf = function () {
return this.value;
};
Then you may use it in place of the original value:
function myObject() {
this.myvalue = new Wrapper(null); // wrapper
this.arr = [this.myvalue];
}
myObject.prototype.alter = function() {
this.myvalue.value = "hello"; // notice the ".value"
}
The rest of your code needs no tweaks.

javascript: Only return if not false

Scenario: I'm searching for a specific object in a deep object. I'm using a recursive function that goes through the children and asks them if I'm searching for them or if I'm searching for their children or grandchildren and so on. When found, the found obj will be returned, else false. Basically this:
obj.find = function (match_id) {
if (this.id == match_id) return this;
for (var i = 0; i < this.length; i++) {
var result = this[i].find(match_id);
if (result !== false) return result;
};
return false;
}​
i'm wondering, is there something simpler than this?:
var result = this[i].find(match_id);
if (result) return result;
It annoys me to store the result in a variable (on each level!), i just want to check if it's not false and return the result. I also considered the following, but dislike it even more for obvious reasons.
if (this[i].find(match_id)) return this[i].find(match_id);
Btw I'm also wondering, is this approach even "recursive"? it isn't really calling itself that much...
Thank you very much.
[edit]
There is another possibility by using another function check_find (which just returns only true if found) in the if statement. In some really complicated cases (e.g. where you don't just find the object, but also alter it) this might be the best approach. Or am I wrong? D:
Although the solution you have is probably "best" as far as search algorithms go, and I wouldn't necessarily suggest changing it (or I would change it to use a map instead of an algorithm), the question is interesting to me, especially relating to the functional properties of the JavaScript language, and I would like to provide some thoughts.
Method 1
The following should work without having to explicitly declare variables within a function, although they are used as function arguments instead. It's also quite succinct, although a little terse.
var map = Function.prototype.call.bind(Array.prototype.map);
obj.find = function find(match_id) {
return this.id == match_id ? this : map(this, function(u) {
return find.call(u, match_id);
}).filter(function(u) { return u; })[0];
};​
How it works:
We test to see if this.id == match_id, if so, return this.
We use map (via Array.prototype.map) to convert this to an array of "found items", which are found using the recursive call to the find method. (Supposedly, one of these recursive calls will return our answer. The ones which don't result in an answer will return undefined.)
We filter the "found items" array so that any undefined results in the array are removed.
We return the first item in the array, and call it quits.
If there is no first item in the array, undefined will be returned.
Method 2
Another attempt to solve this problem could look like this:
var concat = Function.prototype.call.bind(Array.prototype.concat),
map = Function.prototype.call.bind(Array.prototype.map);
obj.find = function find(match_id) {
return (function buildObjArray(o) {
return concat([ o ], map(o, buildObjArray));
})(this).filter(function(u) { return u.id == match_id })[0];
};
How it works:
buildObjArray builds a single, big, 1-dimensional array containing obj and all of obj's children.
Then we filter based on the criteria that an object in the array must have an id of match_id.
We return the first match.
Both Method 1 and Method 2, while interesting, have the performance disadvantage that they will continue to search even after they've found a matching id. They don't realize they have what they need until the end of the search, and this is not very efficient.
Method 3
It is certainly possible to improve the efficiency, and now I think this one really gets close to what you were interested in.
var forEach = Function.prototype.call.bind(Array.prototype.forEach);
obj.find = function(match_id) {
try {
(function find(obj) {
if(obj.id == match_id) throw this;
forEach(obj, find);
})(obj);
} catch(found) {
return found;
}
};​
How it works:
We wrap the whole find function in a try/catch block so that once an item is found, we can throw and stop execution.
We create an internal find function (IIFE) inside the try which we reference to make recursive calls.
If this.id == match_id, we throw this, stopping our search algorithm.
If it doesn't match, we recursively call find on each child.
If it did match, the throw is caught by our catch block, and the found object is returned.
Since this algorithm is able to stop execution once the object is found, it would be close in performance to yours, although it still has the overhead of the try/catch block (which on old browsers can be expensive) and forEach is slower than a typical for loop. Still these are very small performance losses.
Method 4
Finally, although this method does not fit the confines of your request, it is much, much better performance if possible in your application, and something to think about. We rely on a map of ids which maps to objects. It would look something like this:
// Declare a map object.
var map = { };
// ...
// Whenever you add a child to an object...
obj[0] = new MyObject();
// .. also store it in the map.
map[obj[0].id] = obj[0];
// ...
// Whenever you want to find the object with a specific id, refer to the map:
console.log(map[match_id]); // <- This is the "found" object.
This way, no find method is needed at all!
The performance gains in your application by using this method will be HUGE. Please seriously consider it, if at all possible.
However, be careful to remove the object from the map whenever you will no longer be referencing that object.
delete map[obj.id];
This is necessary to prevent memory leaks.
No there is no other clear way, storing the result in a variable isn't that much trouble, actually this is what variables are used for.
Yes, that approach is recursive:
you have the base case if (this.id==match_id) return this
you have the recursive step which call itself obj.find(match_id) { ... var result = this[i].find(match_id); }
I don't see any reason, why storing the variable would be bad. It's not a copy, but a reference, so it's efficient. Plus the temporary variable is the only way, that I can see right now (I may be wrong, though).
With that in mind, I don't think, that a method check_find would make very much sense (it's most probably basically the same implementation), so if you really need this check_find method, I'd implement it as
return this.find(match_id) !== false;
Whether the method is recursive is hard to say.
Basically, I'd say yes, as the implementations of 'find' are all the same for every object, so it's pretty much the same as
function find(obj, match_id) {
if (obj.id == match_id) return obj;
for (var i = 0; i < obj.length; ++i) {
var result = find(obj[i], match_id);
if (result !== false) return result;
}
}
which is definitely recursive (the function calls itself).
However, if you'd do
onesingleobjectinmydeepobject.find = function(x) { return this; }
I'm not quite sure, if you still would call this recursive.

Categories