When does the javascript console evaluate the contents of a printed object? - javascript

I have found that when using console.log on a nested object the result seems to print after subsequent operations have performed, but only when logging an object with a depth of at least two.
Consider the following example:
function addNumbers(data) {
data.container.firstNumber++
console.log(data); // 3
data.container.firstNumber++
}
var numberData = {
container : {
"firstNumber": 1
}
};
console.log(numberData); // 3
addNumbers(numberData);
I assumed that with this example I would see numberData printed with the values 1 and then 2. In actuality, the value is 3, 3. My first thought was perhaps there is some race condition here where the values changes before the log operation can complete, but if you add more specific references to the object, you will get the value that matches the console.log's position in the code like this:
function addNumbers(data) {
data.container.firstNumber++
console.log(data.container); // 2
data.container.firstNumber++
}
var numberData = {
container : {
"firstNumber": 1
}
};
console.log(numberData.container); // 1
addNumbers(numberData);
Why doesn't the variable evaluate to its value relative to the position of the console.log in the first example, but does in the second example?
relevant fiddle

Most browsers only fetch the properties of an object logged to the console when you expand the object -- and often note this in a tooltip next to the object reference.
They also tend to only expand the object the first time and cache from then on, so the console is not a reliable way to inspect objects.
To get around this, browsers offer a watch panel that will update more frequently and can be used with breakpoints or stepping to get the current state of an object repeatedly.

Related

How to take value from the element in the Cypress tool?

I have a problem with taking value of the element like:
<div class="Test">Number 10</div>
Let say, that I have 10-20 classes with values like here, then I can use:
cy.get('.Test').invoke('text').as.('Field1')
to get proper value, but it is only possible in different test by using this.Field1.
How to get value in the same test without using:
then and .text()?
Is it possible? I have many fields and I would like do it in one single test to check proper values in the next view.
Did anyone has similar problem? Thanks
It sounds as though you may want to use .its
cy.get('selector').its(propertyName).should('contain', 'string')
its needs to be chained off a previous command like get. You can also use this in a function as per Cypress's example
Cypress shows an example for DOM elements
Get the length property of a DOM element
cy
.get('ul li') // this yields us a jquery object
.its('length') // calls 'length' property returning that value
.should('be.gt', 2) // ensure the length is greater than 2
})
You can access functions to then drill into their own properties
instead of invoking them.
// Your app code
// a basic Factory constructor
const Factory = (arg) => {
// ...
}
Factory.create = (arg) => {
return new Factory(arg)
}
// assign it to the window
window.Factory = Factory
cy
.window() // yields window object
.its('Factory') // yields Factory function
.invoke('create', 'arg') // now invoke properties on itv
You can drill into nested properties by using dot notation.
const user = {
contacts: {
work: {
name: 'Kamil'
}
}
}
cy.wrap(user).its('contacts.work.name').should('eq', 'Kamil') // true
For the full list of examples and rules check out Cypress.io documents https://docs.cypress.io/api/commands/its.html#Syntax

Is it possible to execute a Javascript function after a specific console.log() entry?

I'm working with a very limited web platform which makes use of 3rd party Javascript libraries. Without listing the extraneous details of how and why it operates the way it does, I'm curious if it is possible to do something/anything (e.g. execute Javascript function) after a specific console.log entry appears. The system is very locked down but I'm trying to improve the overall user experience of the application.
A typical console log entry from this Javascript library usually looks like this:
data access_token=XXXXXXXXXXXXXXXX&type_name=user&attributes=["uuid","displayName","email"]
Googling yields a large amount of unrelated results. I found this which involves overwriting the console.log method but that's not my desired approached: How to get the console.log content as string in JavaScript
Any ideas? I'm assuming you convert the current contents into an array or string and parse for results.
You can override console.log() AND, keep it still logging to the console so you can both capture the output and leave logging in place.
Here's a way to do that:
var logEntries = [];
(function(oldLog) {
console.log = function(arg) {
// captures only first argument to console.log()
// could be expanded to concatenate all entries
logEntries.push(arg.toString());
// now call original console.log() with original arguments
return oldLog.apply(console, arguments);
};
})(console.log);
So, now at any given time, the logEntries variable will be an accumulated array of everything sent to console.log(). This is a simple version that does not expand objects or enumerate arrays. More features in that area could be added, but it appears you're just looking for a specific string.
You could also add any filtering before adding to the logEntries array if you only want to capture things containing "access_token", for example.
If you wanted to only capture the lines that contain "access_token=", then you could modify the above code like this:
var logEntries = [];
(function(oldLog) {
console.log = function(arg) {
if (typeof arg === "string" && arg.indexOf("access_token=") !== -1) {
logEntries.push(arg);
}
// now call original console.log() with original arguments
return oldLog.apply(console, arguments);
};
})(console.log);

Changing an array within an object (and vice versa) changes all references to that array before and after the change [duplicate]

This question already has answers here:
console.log() async or sync?
(3 answers)
Closed 6 years ago.
In JavaScript, it appears if I define an array, print that array to the console, then change the array, then print to the console again, the two printings will appear different. Same for objects. This makes sense to me - the first time I print it, it hasn't changed yet, and the second time it has been changed.
However, through testing I've found that if I define an object within an array, print it, change the object, then print again, both printings will be the same (they will both be the changed version). Similarly if I define an array within an object, print it, change the array, then print it again, both printings will be the same (they will both be the changed version).
I think this may be related to passing by reference or by value? But I'm unclear how to relate that concept here. Some articles that I think may be related to my answer:
(SO) Is JavaScript a pass-by-reference or pass-by-value language?
(SO) Javascript by reference vs. by value
http://snook.ca/archives/javascript/javascript_pass
If anyone could help explain I would be very appreciative. Here are the tests I wrote to exemplify what discrepancy I'm asking about:
// Testing changing an array
// RESULT: Array console.logs are DIFFERENT before and after the change.
var arr123 = [1,2,3];
console.log(arr123);
arr123[0] = 4;
arr123[1] = 5;
arr123[2] = 6;
console.log(arr123);
// Testing changing an object
// RESULT: Object console.logs are DIFFERENT before and after the change.
var obj123 = {
first: 1,
second: 2,
third: 3
};
console.log(obj123);
obj123.first = 4;
obj123.second = 5;
obj123.third = 6;
console.log(obj123);
// Testing changing an object inside of an array.
// RESULT: Array console.logs are THE SAME before and after the change, reflecting the change.
var arrOfAnObj = [
{first: 1, second: 2, third: 3}
];
console.log(arrOfAnObj);
arrOfAnObj[0].first = 4;
arrOfAnObj[0].second = 5;
arrOfAnObj[0].third = 6;
console.log(arrOfAnObj);
// Testing changing an array inside of an object.
// RESULT: Object console.logs are THE SAME before and after the change, reflecting the change.
var objOfAnArr = {
arr: [1, 2, 3]
};
console.log(objOfAnArr);
objOfAnArr.arr[0] = 4;
objOfAnArr.arr[1] = 5;
objOfAnArr.arr[2] = 6;
console.log(objOfAnArr);
In all your cases you are modifying the initial object, it's just related to how and when the browser reads the object you passed it through console.log().
Explanation
I executed your code in this repl and the results are always different there.
I executed in chrome and I could reproduce you case. So it has to do with when the browser reads your variable. Because in the first two cases the variable has only one level so chrome shows you the values inline, and therefore reads the object at the point where it is logged.
In the last two cases you have one more level so chrome reads the object reference when you expand the object in the console.
Also I noticed that chrome displays your logs differently whether you run your code while the dev tools are open or when you run your code before opening the dev tools.
If you run the code before opening the dev tools you get the following output:
Whereas if you open the dev tools before running the code you get the following output:

Jquery function - When called second time, not receiving fresh data, uses old?

I'm having trouble with a function that I'm calling multiple times. Every time I call it, it should receive fresh data (even if its the same as earlier) but somehow, next call to the function will result in what was expected output from the first call to the function.
The code:
$.calc=function(arrayName){
console.log(arrayName);
for(i=0;i<arrayName.length;i++){
if(i==2){
arrayName[i]="";
}
}
}
var arr=new Array();
arr[0]="saab";
arr[1]="saab";
arr[2]="saab";
arr[3]="saab";
arr[4]="volvo";
arr[5]="volvo";
//First run
$.calc(arr);
//Second run
$.calc(arr);
If you run the code (http://jsfiddle.net/76bme/) and open console logger/devtools you can see that I'm printing out the contents of the array that I passed along with the function, BEFORE doing anything with the array.
Next time I call the function, I pass the same array (arr) to the function as in the first call to the function, so I expect that console.log in the beginning to print out the same contents from the array. But now the array holds everything as earlier except at index 2 where I modified it to "" AFTER I printed it out with console.log. If it was the other way around I would get it (having console.log after the for-loop) but now I'm just confused!?
So what am I doing wrong?
That is because arrayName is a reference to your array object. So when you change something in that object, your arr is affected aswell. If you don't want this behaviour, you need to "create a copy" of your array :
$.calc=function(arrayName){
console.log(arrayName)
var myArr = Array.prototype.slice.call(arrayName); //Just here!
for(i=0;i<myArr.length;i++){
if(i==2){
myArr[i]="";
}
}
}
Fiddle : http://jsfiddle.net/76bme/5/
Change
console.log(arrayName);
to
console.log(arrayName.join(";"));
And you will see what you expect. The console [depending on state] does not show a snapshot of the object/array at the current time it was logged, sometimes it stores a reference to it so it will have the current values.

Array containing objects has wrong length

I have an array like:
errors = [ {...}, {...}, {...} ]
It's an instanceof array, yet it only returns 1 for .length?
Relevant code:
if(data.error){
errors.push({'element':ele,error:data.error});
}
//Above is looped a few times and there are N number of errors now inside
console.log(errors) //Returns 2+ objects like {...}, {...}
console.log(errors.length) //Returns 1
For Uzi and Muirbot, here's the errors array:
[
Object
element: b.fn.b.init[1]
error: "You must enter "example" into the field to pass"
__proto__: Object
,
Object
element: b.fn.b.init[1]
error: "Crap!"
__proto__: Object
It is correct, this code:
var errors = new Array();
errors.push({'element':'ele', error:'data.error'});
...adds ONE object to the array. The object has two properties.
It's possible your code is executing in an order other than what you're expecting. ie, when you log both errors and errors.length, errors does contain only 1 object. But after that you are adding to the errors array, and only after that are you looking at the console. At that point you could see a larger array in errors for two reasons - first, your actual code isn't logging errors but some object that contains errors. In that case the console display is live, and will show you not what was in errors at the time, but what is in it now. Alternatively, the console could just be taking some time to log errors.
Without more code I can't be sure if this is the case. But you could verify it by replacing console.log(errors); with console.log(errors[1]);. If errors is really only 1 long at the time, it will log undefined.
The problem was that Chrome's Web Inspector's console.log is an async event. So, the length was a property lookup so it gave that back instantly, but the object with two items inside was held off until the rest of the events had fired.
In the future I, and others with this issue, should use debugger; instead.
is it an Array object or something that resembles it?
arrays do work:
> a = [{a:1}, {b:2}]
[Object, Object]
> a.length
2
you'll have to provide more code.
and now that you've provided the relevant code, the correct answer is what Steve Wellens said (which was downvoted, by the way).
Array.push adds a single element, objects may have more than one key but they're still a single object so your real case was different from your original example, which of course works.
another possibility:
> a = []
[]
> a.length = 2
2
> a
[]
> a.length
2
> a instanceof Array
true

Categories

Resources