document.querySelectorAll("body") returning undefined - javascript

I am using the following codes in the console of the firefox DevTools to extract book names from https://bookauthority.org/books/best-problem-solving-books
Code 1
var selects=document.querySelectorAll("div.book-header-title a.book-title h2.main");
for (i = 0; i < selects.length; ++i) {
console.log (selects[i].innerText);
}
Code 2
var selects=document.querySelectorAll("div.book-header-title a.book-title h2.main");
console.log(selects)
Even the following code is not working
var selects=document.querySelectorAll("body");
console.log(selects)
It only says undefined. What can I do?

querySelectorAll works just fine. The problem resides in that the specific webpage on which you're executing the code, has overriden the window.console.log method and the new implementation apparently does not print arguments to the console, as its native implementation does.
You can see this by issuing window.console.log (without parentheses), which usualy prints something like ƒ log() { [native code] } (at least in Chrome).
There are hacks how to acquire the native implementation. See, for example, this post: https://stackoverflow.com/a/11129588/4005175
Example:
// restore window.console.log method
var f = document.createElement("iframe");
f.style.display = "none";
document.documentElement.appendChild(f);
window.console.log = f.contentWindow.console.log;
// print book titles
var selects=document.querySelectorAll("div.book-header-title a.book-title h2.main");
for (i = 0; i < selects.length; ++i) {
console.log (selects[i].innerText);
}

Related

Console integration: get number of errors/warnings thrown?

So if you open up the inspector, you get this (if you're unlucky):
I'm building a tiny JS component which displays debugging information - is there any way to read the number of encountered errors and warnings so far?
A hacky solution I could come up with involves a bit of trickery by replacing the console.(error|log|warn) functions with my own, but I'm yet to test if it works for all cases (e.g. outside of code I own).
Is there a better way to do this?
As noted in this answer, it's generally not a good idea to change the behavior of native objects/methods. However, the following code should get you what you need in a fairly innocuous manner:
// Add this IIFE to your codebase:
(() => {
// Get all of the property names of the console:
const methodsToTrack = Object.keys(window.console);
// Create an object to collect total usage tallies in:
const usageRegistry = {};
for (let i = 0, j = methodsToTrack.length; i < j; i++) {
let methodName = methodsToTrack[i];
// If the property is not a method, don't touch it:
if(typeof window.console[methodName] !== 'function') {
continue;
}
// Cache the original console method here:
let consoleMethod = window.console[methodName];
// Overwrite console's method to increment the counter:
window.console[methodName] = function () {
// Defining registry properties here, so the registry only contains values for methods that were accessed:
usageRegistry[methodName] = usageRegistry[methodName] || 0;
// Execute the original method's behavior, capturing the returned value (if any) in a var, to return it at the end:
const returnedValue = consoleMethod(...arguments);
// Increment the usage registry for the executed method:
usageRegistry[methodName]++;
// Return the value the console's method would have returned, so the new method has the same signature as the old.
return returnedValue;
};
}
// Define a funciton to output the totals to a console log, then clean up after itself:
window.showConsoleTallies = function () {
window.console.log(usageRegistry);
usageRegistry['log']--;
}
})();
// Examples:
showConsoleTallies();
console.log('log 1');
console.error('error 1');
console.log('log 2');
console.warn('warn 1');
console.error('error 2');
console.log('log 3');
showConsoleTallies();
PS: That's the ECMA6 version, but feel free to run it through Babel if you'd like it to be compiled for use in older browsers.

Javascript: Basic for loop is not working

Is there any reason why the following would not work:
for (i=0;i < someArray.length;i++) {
if (someArray[i].indexOf("something") !== -1) {
//do something here
}
}
The most basic "for" loop possible. But it doesn't work. On the first line (declaration of the loop, not inside the loop), I get "Uncaught reference error; i is not defined."
I have this page open in one Chrome tab, and another earlier version of the page open in another tab. In the other tab, this loop works just fine; in the first tab, this code throws an error.
EDIT - July 2 2015
The response about strict mode was helpful. After reading up a bit and going through the code I've got a handle on what's going on.
The confusing bit was that both versions of the code look like this, with some minor differences (requirejs module):
define(
'viewModels/someViewModel',
['dependency1', 'dependency2', 'dependency3'],
function(dep1, dep2, dep3) {
"use strict";
function SomeViewModel(arg1, arg2) {
var self = this;
self.initialize();
self.removeRefinement = function(refinementString) {
var refinementArray = refinementString.split("&");
for (i=0;i < navigationArray.length;i++) { //<-- error
}
}
}
}
);
One version throws the reference error. One doesn't.
This is a large web application with many other pages and Javascript files. The only thing I could think of was that in one version of the code, maybe i had been inadvertently globally defined somewhere else in the app, where strict mode wasn't enabled. After running to the breakpoint and checking "window" I see that's exactly what's happening.
Thanks =D
If you are in strict mode, you'll get the error Uncaught reference error; i is not defined. If you're not in strict mode, you won't get the error.
This will throw the error
'use strict'
var someArray = ['aaa', 'bbb', 'ccc'];
for (i=0;i < someArray.length;i++) {
console.log(i)
if (someArray[i].indexOf("something") !== -1) {
//do something here
}
}
This won't
var someArray = ['aaa', 'bbb', 'ccc'];
for (i=0;i < someArray.length;i++) {
console.log(i)
if (someArray[i].indexOf("something") !== -1) {
//do something here
}
}
when you declare a variable it must be declared like this var i = 0;
a for loop looks like this:
JavaScript
for(var i = 0; i == 10; i++)
{
}

Extending htmloptionscollection

I have a code to extend the htmloptionscollection object:
HTMLOptionsCollection.prototype.contains = HTMLOptionsCollection.prototype.contains ||
function(otherOption) {
for (var i = 0; i < this.length; i++) {
if (this[i].value === otherOption.value) {
return true;
}
}
return false;
};
It works well on firefoxa dn in Opera but does not work in IE9 and in Google Chrome it shows:
"Uncaught ReferenceError: HTMLOptionsCollection is not defined"
How can I solve this problem. Am I doing anything wrong? If I am, how can I solve it?
If you do something wrong then the wrong thing is that you assume that the whole DOM is supported by any browser. For example IE: I don't see any prototype for HTMLOptionsCollection on MSDN

JavaScript method begins w/ variables assigned?? very confused

this is my first post, but i'm excited to join this community. I have a question regarding JavaScript which I am completely stumped about.
I'm writing a JavaScript application which pulls data from a server using ajax and adds it to a chart. I'm using Jquery and Highcharts as the framework and then writing my own JavaScript 'wrapper' around Highcharts to produce the interface.
When the processData function get called back with the jSON response, it begins with i=1, even though i shouldn't even be initialized or even declared yet. Other variables are set as well. (I know this from using chrome developer tools to debug). This makes my loop not execute and none of my data gets added to the chart.
I don't know how much code to show, but these are the most relevant parts. I can add more if needed.
function getData(series, min, max, numpts) {
if (series === undefined) {
console.log("error on getData");
return;
}
var request = {};
request.series = series;
if (min !== undefined) {
request.start = min;
} //in seconds
if (max !== undefined) {
request.end = max;
}
if (numpts !== undefined) {
request.numpts = numpts;
}
$.getJSON('/data', request, processData);
return;
}
function processData(data) {
// handle the data after it comes back from an ajax request
var curSeries,
chartSeries,
curPoint;
for (var i = 0; i < data.length; i ++) {
curSeries = data[i];
chartSeries = chart.get(curSeries.name);
if (chartSeries === null) {
//alert("oops");
chart.addSeries(curSeries);
} else {
for (var j = 0; j < curSeries.data.length; j ++) {
curPoint = curSeries.data[j];
chartSeries.addPoint(curPoint, false);
}
}
}
chart.redraw();
}
These are both methods of a class I declared called graph.
Thanks if anyone has any ideas!
-Matt P
I'd console inspect your data object to make sure it's what you expect, as that loop should be working fine even if i is pre-declared: you're assigning 0 to it at the beginning of the loop, anyway.
The only reason I can think of that i would be defined and initialized before you defined and initialized it is if somewhere else in your codebase you don't initialize the i with the var keyword. Doing that would dump it into the global scope (the window object), making it available via closure to any and every function in your codebase.
If it's not in one of your files, it may be in the highcharts graphing library (in which case run very quickly away from said library).

How to trace Javascript events (Stack Trace )?

In any programming language, I can trace any function and know which function is called by other. But in Javascript , I don't know how, since the code is not written by me and Firebug does not give this feature - as far as I know.
An example :
I want to display the function names of each function that is called when clicking on XYZ Element, and display them in order.
Found this: A javascript stacktrace in any browser, James says they have a github account now
function printStackTrace() {
var callstack = [];
var isCallstackPopulated = false;
try {
i.dont.exist+=0; //doesn't exist- that's the point
} catch(e) {
if (e.stack) { //Firefox
var lines = e.stack.split('\n');
for (var i=0, len=lines.length; i<len; i++) {
if (lines[i].match(/^\s*[A-Za-z0-9\-_\$]+\(/)) {
callstack.push(lines[i]);
}
}
//Remove call to printStackTrace()
callstack.shift();
isCallstackPopulated = true;
}
else if (window.opera && e.message) { //Opera
var lines = e.message.split('\n');
for (var i=0, len=lines.length; i<len; i++) {
if (lines[i].match(/^\s*[A-Za-z0-9\-_\$]+\(/)) {
var entry = lines[i];
//Append next line also since it has the file info
if (lines[i+1]) {
entry += " at " + lines[i+1];
i++;
}
callstack.push(entry);
}
}
//Remove call to printStackTrace()
callstack.shift();
isCallstackPopulated = true;
}
}
if (!isCallstackPopulated) { //IE and Safari
var currentFunction = arguments.callee.caller;
while (currentFunction) {
var fn = currentFunction.toString();
var fname = fn.substring(fn.indexOf("function") + 8, fn.indexOf('')) || 'anonymous';
callstack.push(fname);
currentFunction = currentFunction.caller;
}
}
output(callstack);
}
function output(arr) {
// Output however you want
alert(arr.join('\n\n'));
}
You can see the stack trace of any error with the stack() function call (on Firefox). Creating a simple function to print a stack trace could look like this:
function getStackTrace() {
try {
unusedVariable++; // This creates an error we can trace
}
catch (e) {
return e.stack;
}
}
Other browsers have different ways of printing the stack trace, but this should get you what you need for Firefox.
Hope this helps.
DynaTrace AJAX has some of the features like that. Not exactly what you are looking for but gives you the events and functions bound on an element and helps your troubleshooting. Had a free download, check it.
If you simply want to debug your code, your best option is to get a debugger plug-in for your browser. The Firebug plug-in does provide stack traces. (see here)
If you want to do it from within your code, there is no standard language feature of JavaScript that allows you to do this. Different browsers may implement non-standard extensions, but you shouldn't rely on them.
As "Casablanca" mentions... please note from the site of the aforementioned js-stack-trace (
http://www.eriwen.com/javascript/js-stack-trace/ ) that in FireFox and Chrome:
Obvious easy way: Firebug, Chrome Dev Tools, Dragonfly etc.
You can easily get a stack trace at any time by calling
console.trace() in your Javascript or in the Firebug console.
Since it sounds like you want to inspect the stack and take pieces of the information (the function names), sounds like you need
stackinfo
which was built exactly for that purpose.

Categories