JavaScript: Storing objects in an array [duplicate] - javascript

In Safari with no add-ons (and actually most other browsers), console.log will show the object at the last state of execution, not at the state when console.log was called.
I have to clone the object just to output it via console.log to get the state of the object at that line.
Example:
var test = {a: true}
console.log(test); // {a: false}
test.a = false;
console.log(test); // {a: false}

I think you're looking for console.dir().
console.log() doesn't do what you want because it prints a reference to the object, and by the time you pop it open, it's changed. console.dir prints a directory of the properties in the object at the time you call it.
The JSON idea below is a good one; you could even go on to parse the JSON string and get a browsable object like what .dir() would give you:
console.log(JSON.parse(JSON.stringify(obj)));

What I usually do if I want to see it's state at the time it was logged is I just convert it to a JSON string.
console.log(JSON.stringify(a));

Vanilla JS:
#evan's answer seems best here. Just (ab)use JSON.parse/stringify to effectively make a copy of the object.
console.log(JSON.parse(JSON.stringify(test)));
JQuery specific solution:
You can create a snapshot of an object at a certain point in time with jQuery.extend
console.log($.extend({}, test));
What is actually happening here is jQuery is creating a new object with the test object's content, and logging that (so it will not change).
AngularJS (1) specific solution:
Angular provides a copy function that can be used to the same effect: angular.copy
console.log(angular.copy(test));
Vanilla JS wrapper function:
Here is an function which wraps console.log but will make a copy of any objects before logging them out.
I wrote this in response to a few similar but less robust functions in the answers. It supports multiple arguments, and will not try to copy things if they are not regular objects.
function consoleLogWithObjectCopy () {
var args = [].slice.call(arguments);
var argsWithObjectCopies = args.map(copyIfRegularObject)
return console.log.apply(console, argsWithObjectCopies)
}
function copyIfRegularObject (o) {
const isRegularObject = typeof o === 'object' && !(o instanceof RegExp)
return isRegularObject ? copyObject(o) : o
}
function copyObject (o) {
return JSON.parse(JSON.stringify(o))
}
example usage: consoleLogWithObjectCopy('obj', {foo: 'bar'}, 1, /abc/, {a: 1})

That > Object in the console, isn't only showing the current state. It actually is deferring reading the object and it's properties until you expand it.
For example,
var test = {a: true}
console.log(test);
setTimeout(function () {
test.a = false;
console.log(test);
}, 4000);
Then expand the first call, it will be correct, if you do it before the second console.log returns

using Xeon06's hint, you may parse his JSON in an object, and here is the log function I now use to dump my objects :
function odump(o){
console.log($.parseJSON(JSON.stringify(o)));
}

There is an option to use a debugger library.
https://debugjs.net/
Just include the script into your web page and put log statements.
<script src="debug.js"></script>
Logging
var test = {a: true}
log(test); // {a: true}
test.a = false;
log(test); // {a: false}

I defined an utility:
function MyLog(text) {
console.log(JSON.stringify(text));
}
and when I want to log on console I simply do:
MyLog("hello console!");
It works very well!

You might want to log the object in a human readable way:
console.log(JSON.stringify(myObject, null, 2));
This indents the object with 2 spaces at each level.
How can I pretty-print JSON using JavaScript?

There's a new option as of late 2022:
Deep copy the object with the new DOM structuredClone method:
console.log(structuredClone(obj))
which uses the same cloning algorithm that's used to transfer messages between web workers.
This should be faster and work with more types of objects than the JSON.parse(JSON.stringify(obj)) technique.
See https://developer.mozilla.org/en-US/docs/Web/API/structuredClone for details.

I may be shot for suggesting this, but this can be taken one step further. We can directly extend the console object itself to make it more clear.
console.logObject = function(o) {
(JSON.stringify(o));
}
I don't know if this will cause some type of library collision/nuclear meltdown/rip in the spacetime continuum. But it works beautifully in my qUnit tests. :)

Simply refresh the page after you open the console or open the console before you submit the request to the targeted page....

Just print whole object on console.
console.log(object);

Related

Using [].push.call() to modify an object's length

Cannot reproduce MDN's example («Using an object in an array-like fashion»).
let obj = {
length: 0,
addEl: function (element) {
[].push.call(this, element);
};
};
// Node REPL still expect me to do something, so there's an error. Why?
Could you, guys, explain what's wrong here? Also it seems that I don't get the point with the mechanics here:
// from the example:
obj.addElem({});
obj.addElem({});
console.log(obj.length);
// → 2
What if we call the function with some different agrument, not {}, will it work? And if it won't, then why we should use {} exactly? What is the this context here: addEl method or the object itself? If the second, why not addEl function: it's not an array function, so it should have its own this (and, I guess, I'd use something like objThis = this; property).
One more related question is here.
The code in your post has some typos:
let obj = {
length: 0,
addEl: function (element) {
[].push.call(this, element);
};
^ syntax error
};
// Node REPL still expect me to do something, so there's an error. Why?
As you suspected in your comment in the code,
there is a syntax error, which I marked for you.
Remove that semicolon.
And then, when trying the example you wrote obj.addElem,
but in the above object literal you have addEl.
The example should work just fine, if you simply copy-paste it.
var obj = {
length: 0,
addElem: function addElem(elem) {
// obj.length is automatically incremented
// every time an element is added.
[].push.call(this, elem);
}
};
// Let's add some empty objects just to illustrate.
obj.addElem({});
obj.addElem({});
console.log(obj.length);
// → 2
What if we call the function with some different argument, not {}, will it work?
Sure it will. Why wouldn't it? An array in JavaScript can contain values of different types.
It doesn't need to be homogeneous,
so yes, you can insert other things than {}.
What is the this context here: addEl method or the object itself?
It's the object on which the method is called. So it's obj.
This is how method invocation works.
When you call obj.something(), the this inside something will be the obj.
If you still have some doubts about this example, feel free to drop a comment.
Since an object is not an array, but can behave like an array you need to borrow push from the Array object.
But in this case this refers to the array object created with the shorthand []. So we need to change this into the scope for obj using call.
Because there is a length property defined, push will update this value.
An empty object is passed as an element {}, but any other will do:
let obj = {
length: 0,
addEl: function(element) {
Array.prototype.push.call(this, element); //also borrowing push from the array.prototype prevents an extra array to be made in memory every time we call upon this function.
} //« fixed the typo here
};
obj.addEl({});
obj.addEl(1);
obj.addEl('a');
obj.addEl(true);
console.log(obj);
var array = {
length: 0,
push: function(obj){
this[this.length] = obj;
this.length++;
}
}
array.push(23);
You can try this, this solves your problrm i guess.

Why is my simple, pure JavaScript, shallow clone function not working as I expect?

I need a clone function for JavaScript literal objects, which doesn't even needs to clone recursively for now. The function needs to be pure JavaScript no libraries could be used. I've done some research and as some of the most simplified answers to this question suggests, all I need in this case is "for in" loop with hasOwnProperty check. The problem is that the supposedly copied object is behaving as if I've copied the references to the original properties in the new object. That is not my goal. The clone function in a way that any change of the source object does not affect the destination object and vice versa.
Here is the code:
...
function clone(from,to){
for (var key in from){
if(from.hasOwnProperty(key)){
to[key]=from[key];
}
}
return to;
}
...
var newComponent = clone(component,{});
var defaultComponentDrawParams = clone(component.drawParams,{});
if(params.type==="button"){
console.info('new component');
component.drawParams.subType="chinga chunga";
console.info(defaultComponentDrawParams.subType);
console.info(newComponent.drawParams.subType);
}
And the console displays:
new component
saveFile
chinga chunga
If I've understood correctly both outputs after "new component" should be "undefined" because my goal is when changing component.drawParams to not change newComponent.drawParams.
Please tell me what am I missing.
My guess is that you've got multiple components one of them being a "saveFile" component. And the problem is that your clone isn't cloning the objects/arrays, it's simply creating references to them. So when you update one component, all components that have a reference to those same objects are also getting updated.
Below is an example of the type of detection you may need to add in. However this may not be an absolutely complete answer that catches all scenarios.
function clone(from,to){
for (var key in from){
if(from.hasOwnProperty(key)){
var val = from[key];
if(typeof val === 'object') {
to[key] = clone(from[key], {});
} else {
to[key] = from[key];
}
}
}
return to;
}
I hesitate to suggest this but another option would be to use a javascript library such as Underscore.js: http://underscorejs.org/
It's extremely lightweight (5kb, not nearly as big as jQuery) and has a lot of these types of things figured out for you.

Arbitrary object methods and properties in JavaScript

I'm sure this has definitively been answered before, and I've tried to search for it.. maybe my search terms are wrong...
Basically I have an object myObject, and I have a set of defined properties and methods for it. What I want to do is be able to handle calls/references to properties and methods that I have not defined.
For example, let's say I have this:
var myObject = {
someProperty : 'foobar',
someFunction : function () { /* Do stuff */ }
}
Currently, if someone tries to make a call to myObject.someOtherFunction(), JavaScript yells and screams about it. What I want to do is setup a way to automatically handle that. So for example, instead of JavaScript throwing an error, my object just returns false. Is this possible?
Another way to look at it is this:
var myObject = {
someFunction : function () { /* Do stuff */ }
magicBucket : function () { /* Do stuff */ }
}
If I call myObject.someFunction(), well that is defined and does something. What I want to happen is if I were to for instance call myObject.someOtherFunction(), instead of JavaScript throwing an error, it would call myObject.magicBucket().
The reason is that I have a client that uses a third-party library on their site. They want to discontinue using it, but completely removing it is going to take a lot of time and effort. So as a short-term solution, they wanted to know if I could make a dummy file that basically does nothing. Well, this library uses several objects that has lots of methods. I could go through everything and make dummy objects, but I thought maybe there might be some easy "catch-all" method to do this.
Some have mentioned checking if the method exists first, wrapping it in a condition or try..catch, etc. Well, the point of this is that at this time I can't touch the actual calls to the methods. And since the overall goal is to eventually remove the coding altogether, it's not even applicable.
There's a special property called __noSuchMethod__ which does precisely what you just described. However it's a non-standard property. It only works in Firefox. Here's how you use it:
var o = {
__noSuchMethod__: function (name, args) {
alert(name); // prints the name of the method
alert(args); // prints the array of arguments
}
};
o.abc(1, 2, 3); // OUTPUT: abc 1,2,3
The future however are proxy objects. The following is a short tutorial on proxies: Proxy Tutorial
No, you can't have arbitrary getters in JavaScript. You can test if a function exists before calling it to prevent the error though:
if (myObject.someOtherFunction)
myObject.someOtherFunction();
Or, better, if you don't know that it's necessarily a function:
if (typeof myObject.someOtherFunction == 'function')
myObject.someOtherFunction();
An update on Proxies, here is an infinite array:
$ var squares = new Proxy([], {get:(target,key) => key*key});
$ squares[2]
4
$ Array.isArray(squares)
true
Unfortunately:
$ squares.length
NaN // Want Infinity.
And a dummy object:
$ x = new Proxy({}, {get:(target,key) => console.error("The computer says no", key)})
$ x.laugh
The computer says no laugh
This latter would help the OP make a dummy object, although it would take a bit of black magic to divine what sort of dummy to return.
An up-to date reference: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Proxy
You could create a wrapper function like so:
function callFunction(fn, args) {
var funct = this[fn];
return (typeof funct == "function")
? funct.apply(this, args)
: false;
}
And call with:
callFunction("blah", [1, 2, 3]);
>>> false
An example:
this.foo = function(a, b) {
console.log(a);
return b;
}
callFunction("foo", [1, 2, 3]);
>>> 1
>>> 2 # return value
With Proxy the following works:
function createPseudoObject() {
return new Proxy(new Function(), { get() { return createPseudoObject() } })
}
Eg. createPseudoObject().foo.bar.toString() does not throw error and returns undefined. By using new Function() as a base for the dummy object I can reference not just any property, but call any function on the dummy object.
Maybe there are some edge cases that are not covered by this, but something like this should work.

Prototype.js 1.6.x toJSON misbehaves

In Prototype.js 1.6.x try and do
Object.toJSON([{"nodeType":1}])
it should yield
'[{"nodeType":1}]'
as the output string. However it yields '[]'. It appears to skip objects that have nodeType==1. It has something to do with them being DOM elements. Is there a work around to get the correct output?
jsFiddle: http://jsfiddle.net/xPVnr/
EDIT:
Looking at the source it appears toJSON just returns if isElement(obj) is true which is in turn true if obj.nodeType == 1 :(
Use JSON.stringify but with following tweak to get correct output (in case of Arrays):
var _json_stringify = JSON.stringify;
JSON.stringify = function(value) {
var _array_tojson = Array.prototype.toJSON;
delete Array.prototype.toJSON;
var r=_json_stringify(value);
Array.prototype.toJSON = _array_tojson;
return r;
};
This takes care of the Array toJSON incompatibility with JSON.stringify and also retains toJSON functionality as other Prototype libraries may depend on it.

Equivalent of Python's dir in Javascript

when I write Python code from the interpreter I can type dir() to have a list of names defined in the current scope. How can achieve to have the same information, programmatically, when I develop Javascript code from a browser using an interactive console like firebug, chrome console, etc?
There is keys method in Object, for example:
Object.keys(object)
But this return object's own properties and methods only.
To list all properties and methods of an object I know 2 possibilities:
console.dir(object) method in firebug console for Firefox and
dir(object) method in Google Chrome development tools.
This may work for you, if you need a simple solution:
function dir(object) {
stuff = [];
for (s in object) {
stuff.push(s);
}
stuff.sort();
return stuff;
}
There are a couple of functions which do just this in the code for ChatZilla, you'll have to check the licence properly to see if you can just rip them out and use them wherever.
The relevant functions can be found at
http://hg.mozilla.org/chatzilla/file/59b46c0bf716/js/lib/utils.js#l136
dumpObject and dumpObjectTree
The Google Chrome developer tools console has a predefined dir: https://developers.google.com/chrome-developer-tools/docs/console
Firebug has console.dir: http://getfirebug.com/logging
There are a couple of functions that you you can use to get the data that you need.
Object.keys()
This function will return all enumerable, owned properties that are not Symbols.
> let person = {name: 'John Doe', age: 25, [Symbol('Test')] : 'value'}
> Object.keys(person);
['name'] // Note that the Symbol('Test') is not in the returned array!
Object.getOwnPropertyNames()
This function will return all properties that both enumerable and non-enumerable which are not Symbols.
> Object.getOwnPropertyNames(Set)
[ 'length', 'name', 'prototype' ]
Why is this function useful when we have Object.keys()?
> Object.keys(Set)
[] // Because keys doesn't give you non-enumerable properies
As an aside, why doesn't Object.getOwnPropertyNames(Set) doesn't give you the methods on Set like add, has, etc., ? Because they are on Set.prototype. Object.getOwnPropertyNames(Set.prototype) will yield a much better result.
Object.getOwnPropertySymbols()
This will return all the owned properties that are Symbols in the Object you pass it to.
> let person = {x: 10, Symbol('Test'): 'Test-value' };
> Object.getOwnPropertySymbols(person);
[Symbol(Test)]
Reflect.ownKeys()
This will return all the owned properties that are strings/Symbols in the object you pass it to.
> let person = {x: 1, [Symbol('Test')]: 'Test-value'};
> Reflect.ownKeys(person);
[ 'x', Symbol(Test) ]
Bonus:
Object.getPrototypeOf()
This will return the Prototype of the Object that is passed to it.
> let nameable = { name: 'name' };
> let ageable = Object.create(nameable);
> ageable.age = 0;
> let person = Object.create(ageable);
> let proto_of_person = Object.getPrototypeOf(person);
> proto_of_person === ageable;
true
> let proto_of_ageable = Object.getPrototypeOf(proto_of_person);
> proto_of_ageable === nameable
true
Using this we can enumerate all the properties of an object and its prototype chain recursively.
The global variables are kept in an easily accessible object (window) and so you can inspect/iterate over them easily. (Using something like the functions suggested by Glenjamin)
On the other hand, I don't know of any way to inspect local variables defined in functions or closures - if this is possible I'd at least guess it would be highly browser/console specific.
well you can see object contains like its own properties only : By
it can work in any console not only google chrome web browser look for the img enter image description here
console.dir(obj);
here link: https://developers.google.com/web/tools/chrome-devtools/console/console-reference
(just to see that list)
you can use the operator ".", for example:
> var a = "asdfg";
> a. // -> show the list
in the chrome console it will show you the list of options for autocompletion
in node.js console you can do the same and press tab twice to see the list
The Real Solution
First, create a function that lists out all the properties of an object:
function dir(object) {
props = [];
for (prop in object) {
props.push(prop);
}
props.sort();
return props;
}
Then, as easy as it is, call the function like console.log(dir(console))

Categories