I have this simple function which will prepend a desired string to the beginning of each line. I have this working with streams, but in some cases it's also convenient using a console.log() type of construct.
Here is the function:
// takes a string to prepend, and a stream to prepend to:
exports.lp = function (str, strm) {
return function prependLog() {
var args = Array.from(arguments);
var hasNonWhitespace = args.some(function (a) {
var str = String(a);
return str.length > 0 && /\S/g.test(str);
});
if (hasNonWhitespace) {
strm.write(str);
}
args.forEach(function (s, i) {
String(s).split('\n').forEach(function (s, i) {
if (i < 1) {
strm.write(s + ' ');
}
else {
strm.write('\n' + str + s);
}
});
});
strm.write('\n');
};
};
Here is the use:
const {lp} = require('log-prepend');
const fn = lp(' [foobar] ', process.stdout);
fn('\n');
fn();
fn();
fn('','','');
fn('log1', 'log2\n3',4,5 + '\n55');
fn('a','b','c');
and here is the output from the above:
[foobar]
[foobar] log1 log2
[foobar] 34 5
[foobar] 55
[foobar] a b c
the problem is that for empty lines with no non-whitespace character, it usually works, but when I include a newline character, it outputs [foobar] even though there is nothing on that line.
I can't figure out why my function doesn't omit [foobar] for lines with no non-whitespace. So to be exact, it is the first instance of [foobar] above that is mystifying me.
Having a little trouble following the logic here but is it because you are expecting to use the index variable from the first forEach function, when it's actually using it from the second? Renaming the initial variables might help.
I think I made a good fix like so:
exports.lp = function (str, strm) {
return function prependLog() {
var args = Array.from(arguments);
var hasNonWhitespace = args.some(function (a) {
var str = String(a);
return str.length > 0 && /\S/g.test(str);
});
if (hasNonWhitespace) {
strm.write(str);
}
args.forEach(function (s, i) {
String(s).split('\n').forEach(function (s, i) {
if (i < 1) {
strm.write(s + ' ');
}
else {
// => here is the fix, add the following if/else
if (/\S/g.test(s)) {
strm.write('\n' + str + s);
}
else {
strm.write('\n' + s);
}
}
});
});
strm.write('\n');
};
};
but if anyone has a better way to do this, please let me know.
Related
i am trying to count how many times a letter appear in a string. This is my code:
var myFunc = function(inside) {
count = 0;
for (var i=0;i<inside.length;i++) {
if(inside[i]==="a") {
count+=1;
}
return count;
};
};
console.log(myFunc("hai, okay"));
var myFunc = function(inside) {
count = 0;
for (var i=0;i<inside.length;i++) {
if(inside[i]=="a") {
count+=1;
}
//return should not come here
};
return count;
};
console.log(myFunc("hai, okay"));
or u can use this also
var myFunc = function(inside) {
return (inside.match(new RegExp("a", "g"))).length;
}
console.log(myFunc("hai, okay"));
Your code is not giving correct result since it has a return statement inside a for loop so it will return after first iteration and will return 0. You can simply put the return outside for loop to make it work.
You can also simply change your method to
var myFunc = function(inside, character)
{
return inside.split( character ).length - 1;
};
console.log(myFunc("hai, okay"), "a");
How many letters? As in "Abba" would be 2 letters, namely "a" and "b"?
var letter_counts = function(txt) {
var res = {};
for (var i=0;i<txt.length;i++) {
var c = txt[i].toLowerCase();
res[c] = ( res[c] ? res[c] : 0 ) + 1;
};
return res;
};
var letter_cnts = letter_counts("Abba");
// Object {a: 2, b: 2}
letter_cnts["a"]; // == 2
letter_cnts["b"]; // == 2
What about
var countAs = inside.replace(/[^a]/g, '').length;
Reason: elminate all char's unwanted and take the length of the rest.
Warpped:
function howMany(inside, theChar)
{
var reg = new RegExp("[^" + theChar + "]","g");
return inside.replace(reg, '').length;
}
How can I detect the CSV separator from a string in Javascript/NodeJS?
Which is the standard algorithm?
Note that the separator is not a comma always. The most common separators being ;, , and \t (tab).
A possible algorithm for getting the likely separator(s) is pretty simple, and assumes the data is well-formed:
For every delimiter,
For every line,
Split the line by the delimiter, check the length.
If its length is not equal to the last line's length, this is not a valid delimiter.
Proof of concept (doesn't handle quoted fields):
function guessDelimiters (text, possibleDelimiters) {
return possibleDelimiters.filter(weedOut);
function weedOut (delimiter) {
var cache = -1;
return text.split('\n').every(checkLength);
function checkLength (line) {
if (!line) {
return true;
}
var length = line.split(delimiter).length;
if (cache < 0) {
cache = length;
}
return cache === length && length > 1;
}
}
}
The length > 1 check is to make sure the split didn't just return the whole line. Note that this returns an array of possible delimiters - if there's more than one item, you have an ambiguity problem.
Another solution is using the detect method from the csv-string package:
detect(input : String) : String Detects the best separator.
var CSV = require('csv-string');
console.log(CSV.detect('a,b,c')); // OUTPUT : ","
console.log(CSV.detect('a;b;c')); // OUTPUT : ";"
console.log(CSV.detect('a|b|c')); // OUTPUT : "|"
console.log(CSV.detect('a\tb\tc'));// OUTPUT : "\t"
function delimiter(csvText) {
t = t.split("\n")[0];
let delArray = [',', ';', '|', ' '];
let comma = samiclon = pipe = tab = 0;
delArray.forEach((e, i) => {
if (i === 0) {
comma = t.split(e).length;
} else if (i === 1) {
samiclon = t.split(e).length;
} else if (i === 2) {
pipe = t.split(e).length;
} else if (i === 3) {
tab = t.split(e).length;
}
});
let tmpArray1 = [comma, samiclon, pipe, tab]
let tmpArray = [comma, samiclon, pipe, tab];
let maxLen = tmpArray.sort((a, b) => b - a)[0];
let delimiter_i = 0;
tmpArray1.forEach((e, i) => {
if (maxLen === e) {
delimiter_i = i;
}
});
if (delimiter_i === 0) {
return ',';
} else if (delimiter_i === 1) {
return ';'
} else if (delimiter_i === 2) {
return '|'
} else if (delimiter_i === 3) {
return ' '
}
}
This solution allows to detect the csv separator only for the top lines and handles quoted fields by using csv-parse.
It can be useful for large csv file to avoid reading the whole file several times.
const parse = require('csv-parse/lib/sync');
const fs = require('fs')
function detectCsvDelimiter(file, maxLineCount, delimiters = [',', ';', '\t']) {
return new Promise((resolve, reject) => {
// Read only maxLineCount lines
let stream = fs.createReadStream(file, {
flags: 'r', encoding: 'utf-8', bufferSize: 64 * 1024 });
let lineCounter = 0;
let data = '';
stream.on("data", (moreData) => {
data += moreData;
lineCounter += data.split("\n").length - 1;
if (lineCounter > maxLineCount + 1) {
stream.destroy();
// Remove invalid last line
resolve(data.split('\n').slice(0, maxLineCount));
}
});
stream.on("error", (err) => reject(err));
stream.on("end", () => resolve(data.split("\n")));
}).then(lines => {
return new Promise(resolve => {
const csvData = lines.join("\n");
const validDelimiters = delimiters.filter(delimiter => {
let isValid = true;
// csv-parse throw error by default
// if the number of columns is inconsistent between lines
try {
const rows = parse(csvData, {delimiter});
isValid = rows.some(row => row.length > 1);
} catch (e) {
isValid = false;
}
return isValid;
});
resolve(validDelimiters);
});
});
}
I found Zirak's answer good in theory, but in practice it failed in many particular places.
Here are some examples that would fail and thus the method would return no delimiter :
a trailing delimiter (by mistake) : test,test1,test2,
missing cells without delimiters: test,test1
This is the most convenient and elegant solution :
let columnData = row.split(/,|;|\|| /);
What sucks here is if there is two delimiters that appear in a row, then this fails.
Say you want to seperate this data: "test,tes|t1,test2".
The above code produces an array that looks like this :
[test, tes, t1, test2]... No good.
Here is a more robust solution I wrote that was inspired by "the programmers" answer:
const rowSplitChars = this.determineCSVLineBreak(text);
const columnSplitChars = this.determineCSVDelimiter(text, rowSplitChars);
private determineCSVLineBreak(text: any): string {
try {
const delArray = ["\r\n", "\n", "\r"];
const rnrnArray =
[text.match(/\r/g).length
,text.match(/\n/g).length
,text.match(/\r\n/g).length];
return delArray[this.getMaxIndexInArray(rnrnArray)];
} catch {
this.handleError('Error determining CSV file line break character.');
return '';
}
}
private determineCSVDelimiter(text: any, rowSplitChars: string): string {
const t = text.split(rowSplitChars)[0];
const delArray = [',', ';', '|', ' '];
const countArray =
[t.split(delArray[0]).length
,t.split(delArray[1]).length
,t.split(delArray[2]).length
,t.split(delArray[3]).length];
return delArray[this.getMaxIndexInArray(countArray)];
}
private getMaxIndexInArray(countArray: any[]) {
let max = countArray[0];
let maxIndex = 0;
for (let i = 1; i < countArray.length; i++) {
if (countArray[i] > max) {
maxIndex = i;
max = countArray[i];
}
}
return maxIndex;
}
In JavaScript, is it possible to insert a line into a function that already exists? I want to create a function that inserts a line at a specific position in a function:
function insertLine(theFunction, lineToInsert, positionToInsert){
//insert a line into the function after the specified line number
}
For example, would it be possible to programmatically insert the line checkParameterTypes(min, "string", max, "string"); before the first line of this function?
function getRandomInteger(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
If you want something to happen at the beginning of a function, you can use the following. You do have access to this and the arguments from your injected function. So it will still work for functions that require a specific context.
function inject(before, fn) {
return function(){
before.apply(this, arguments);
return fn.apply (this, arguments);
}
}
For example
function add(a, b) {
return a + b;
}
function concat(a, b) {
return a + b;
}
/**
* You can repeat index and type to check multiple arguments
*/
function createArgumentChecker(index, type /**index, type, ... */) {
var originalArgs = arguments;
return function() {
for (var i=0; i < originalArgs.length; i+=2) {
var index = originalArgs[i],
requestedType = originalArgs[i+1],
actualType = typeof arguments[index];
if (typeAtIndex != actualType) {
console.log("Invalid argument passed at index " + index +
". Expected type " + requestedType + "but it's " + actualType );
}
}
}
}
function logArguments() {
console.log(this, arguments);
}
// Inject an argument checker
add = inject(add, createArgumentChecker(0,"number", 1, "number"));
concat = inject (concat, createArgumentChecker(0, "string", 1, "string"));
// You can even do it multiple times, inject an argument logger;
add = inject(add, logArguments);
concat = inject(concat, logArguments);
JSfiddle
This can be handy when debugging websites that you can't modify the source code, I wouldn't use it do parameter checking unless you can strip it our for the production version.
Yes you can but using eval is always evil ;)
function insertInbetween (arr, value, index) {
var inserted, i, newarr = [];
for (i = 0; i < arr.length; i++) {
if(i == index && !inserted) {
newarr[i] = value;
inserted = true;
}
newarr.push(arr[i]);
}
return newarr;
}
function test (a, b) {
console.log(a,b);
}
var fstrarr = test.toString().split('\n');
eval(insertInbetween(fstrarr, "console.log('injected!');", 1).join('\n'));
Edit:
As mentioned in the comments to your question you'll loose scope by doing so.
Let's say you have the following function
var action = (function () {
var a = 42;
var b = 2;
function action(c) {
return a + 4 * b + c;
}
return action;
}());
// how would you parse action into it's serialized LISP / AST format?
var parsed = parse(action);
Is it possible to have a function that takes a reference to the function action and outputs say the LISP format (lambda (c) (plus (plus 42 (multiply 4 2)) c))
We're allowed to put some restrictions on what action can be.
the body should only be a single expression
it should be a pure function
any free variables are constants
The main question is given a function you can invoke with a range of inputs and it's source code can you discover the correct value to substitute the free variables with?
For the above example you know that a and b are constant and you could intellectually plot the output for a few values and see the pattern and then just know what the constants are.
Question:
How would you write a function that takes a function reference and it's source code and produces some form of AST for the function with any free variables substituted for their run-time values.
An example of an AST format would be the LISP equivalent of the code.
I basically want to serialize and deserialize the function and have it behave the same
It should be noted that the problem becomes trivial if you pass { a: a, b: b } to the analysis function. That would be cheating.
Use-case:
I want to generate a language agnostic form of a pure JavaScript function so I can effectively pass it to C++ without requiring the user of my library to use a DSL to create this function
Let's imagine you had a database driver
var cursor = db.table("my-table").map(function (row) {
return ["foo", row.foo]
})
You want to determine at run-time what the function is and convert it into an AST format so that you can use your efficient query builder to convert it into SQL or whatever query engine your database has.
This means you don't have to write:
var cursor = db.table("my-table").map(function (rowQueryObject) {
return db.createArray(db.StringConstant("foo"), rowQueryObject.getProperty("foo"))
})
Which is a function the DB library can execute with a query object and have you build the query object transformation without verbose methods.
Here is a full solution (using catalog of variables which is accessible by the parse function):
var CONSTANTS = {
a: 42,
b: 2,
c: 4
};
function test() {
return a + 4 * b + c;
}
function getReturnStatement(func) {
var funcStr = func.toString();
return (/return\s+(.*?);/g).exec(funcStr)[1];
}
function replaceVariables(expr) {
var current = '';
for (var i = 0; i < expr.length; i += 1) {
while (/[a-zA-Z_$]/.test(expr[i]) && i < expr.length) {
current += expr[i];
i += 1;
}
if (isNumber(CONSTANTS[current])) {
expr = expr.replace(current, CONSTANTS[current]);
}
current = '';
}
return expr;
}
function isNumber(arg) {
return !isNaN(parseInt(arg, 10));
}
function tokenize(expr) {
var tokens = [];
for (var i = 0; i < expr.length; i += 1) {
if (isWhitespace(expr[i])) {
continue;
} else if (isOperator(expr[i])) {
tokens.push({
type: 'operator',
value: expr[i]
});
} else if (isParentheses(expr[i])) {
tokens.push({
type: 'parant',
value: expr[i]
});
} else {
var num = '';
while (isNumber(expr[i]) && i < expr.length) {
num += expr[i];
i += 1;
}
i -= 1;
tokens.push({
type: 'number',
value: parseInt(num, 10)
});
}
}
return tokens;
}
function toPrefix(tokens) {
var operandStack = [],
operatorStack = [],
current,
top = function (stack) {
if (stack) {
return stack[stack.length - 1];
}
return undefined;
};
while (tokens.length) {
current = tokens.pop();
if (current.type === 'number') {
operandStack.push(current);
} else if (current.value === '(' ||
!operatorStack.length ||
(getPrecendence(current.value) >
getPrecendence(top(operatorStack).value))) {
operatorStack.push(current);
} else if (current.value === ')') {
while (top(operatorStack).value !== '(') {
var tempOperator = operatorStack.pop(),
right = operandStack.pop(),
left = operandStack.pop();
operandStack.push(tempOperator, left, right);
}
operatorStack.pop();
} else if (getPrecendence(current.value) <=
getPrecendence(top(operatorStack).value)) {
while (operatorStack.length &&
getPrecendence(current.value) <=
getPrecendence(top(operatorStack).value)) {
tempOperator = operatorStack.pop();
right = operandStack.pop();
left = operandStack.pop();
operandStack.push(tempOperator, left, right);
}
}
}
while (operatorStack.length) {
tempOperator = operatorStack.pop();
right = operandStack.pop();
left = operandStack.pop();
operandStack.push(tempOperator, left, right);
}
return operandStack;
}
function isWhitespace(arg) {
return (/^\s$/).test(arg);
}
function isOperator(arg) {
return (/^[*+\/-]$/).test(arg);
}
function isParentheses(arg) {
return (/^[)(]$/).test(arg);
}
function getPrecendence(operator) {
console.log(operator);
switch (operator) {
case '*':
return 4;
case '/':
return 4;
case '+':
return 2;
case '-':
return 2;
default:
return undefined;
}
}
function getLispString(tokens) {
var result = '';
tokens.forEach(function (e) {
if (e)
switch (e.type) {
case 'number':
result += e.value;
break;
case 'parant':
result += e.value;
break;
case 'operator':
result += getOperator(e.value);
break;
default:
break;
}
result += ' ';
});
return result;
}
function getOperator(operator) {
switch (operator) {
case '+':
return 'plus';
case '*':
return 'multiplicate';
case '-':
return 'minus';
case '\\':
return 'divide';
default:
return undefined;
}
}
var res = getReturnStatement(test);
console.log(res);
res = replaceVariables(res);
console.log(res);
var tokens = tokenize(res);
console.log(tokens);
var prefix = toPrefix(tokens);
console.log(prefix);
console.log(getLispString(prefix));
I just wrote it so there might be some problems in the style but I think that the idea is clear.
You can get the function body by using the .toString method. After that you can use regular expression to match the return statement
(/return\s+(.*?);/g).exec(funcStr)[1];
Note that here you must use semicolons for successful match! In the next step all variables are transformed to number values using the CONSTANTS object (I see that you have some parameters left so you may need little modifications here). After that the string is being tokenized, for easier parsing. In next step the infix expression is transformed into a prefix one. At the last step I build a string which will make the output looks like what you need (+ - plus, - - minus and so on).
Since I'm not sure you're able to get the method's body after having invoked it, here is an alternative solution:
var a = 42;
var b = 2;
function action(c) {
return a + 4 * b + c;
}
/**
* get the given func body
* after having replaced any available var from the given scope
* by its *real* value
*/
function getFunctionBody(func, scope) {
// get the method body
var body = func.toString().replace(/^.*?{\s*((.|[\r\n])*?)\s*}.*?$/igm, "$1");
var matches = body.match(/[a-z][a-z0-9]*/igm);
// for each potential var
for(var i=0; i<matches.length; i++) {
var potentialVar = matches[i];
var scopedValue = scope[potentialVar];
// if the given scope has the var defined
if(typeof scopedValue !== "undefined") {
// add "..." for strings
if(typeof scopedValue === "string") {
scopedValue = '"' + scopedValue + '"';
}
// replace the var by its scoped value
var regex = new RegExp("([^a-z0-9]+|^)" + potentialVar + "([^a-z0-9]+|$)", "igm");
var replacement = "$1" + scopedValue + "$2";
body = body.replace(regex, replacement);
}
}
return body;
}
// calling
var actionBody = getFunctionBody(action, this);
// log
alert(actionBody);
Prints:
return 42 + 4 * 2 + c;
DEMO
You would then have to implement your own function toLISP(body) or any function else you may need.
Note that it won't work for complex scoped variables such as var a = {foo: "bar"}.
I'd like to use console.log() to log messages without appending a new line after each call to console.log(). Is this possible?
No, it's not possible. You'll have to keep a string and concatenate if you want it all in one line, or put your output elsewhere (say, another window).
In NodeJS you can use process.stdout.write and you can add '\n' if you want.
console.log(msg) is equivalent to process.stdout.write(msg + '\n').
Yes, it's possible (check out the demo below) -- by implementing your own virtual console on top of the native browser console, then syncing it to the real one.
This is much easier than it sounds:
maintain a display buffer (e.g. an array of strings representing one line each)
call console.clear() before writing to erase any previous contents
call console.log() (or warn, error, etc) to fill the console with the contents from your display buffer
Actually, I've been doing this for some time now. A short, rudimentary implementation of the idea would be something along the following lines, but still capable of animating the console contents:
// =================================================
// Rudimentary implementation of a virtual console.
// =================================================
var virtualConsole = {
lines: [],
currentLine: 0,
log: function (msg, appendToCurrentLine) {
if (!appendToCurrentLine) virtualConsole.currentLine++;
if (appendToCurrentLine && virtualConsole.lines[virtualConsole.currentLine]) {
virtualConsole.lines[virtualConsole.currentLine] += msg;
} else {
virtualConsole.lines[virtualConsole.currentLine] = msg;
}
console.clear();
virtualConsole.lines.forEach(function (line) {
console.log(line);
});
},
clear: function () {
console.clear();
virtualConsole.currentLine = 0;
}
}
// =================================================
// Little demo to demonstrate how it looks.
// =================================================
// Write an initial console entry.
virtualConsole.log("Loading");
// Append to last line a few times.
var loadIndicatorInterval = setInterval(function () {
virtualConsole.log(".", true); // <- Append.
}, 500);
// Write a new line.
setTimeout(function () {
clearInterval(loadIndicatorInterval);
virtualConsole.log("Finished."); // <- New line.
}, 8000);
It sure has its drawbacks when mixing with direct console interaction, and can definitely look ugly -- but it certainly has its valid uses, which you couldn't achieve without it.
You can put as many things in arguments as you'd like:
console.log('hi','these','words','will','be','separated','by','spaces',window,document)
You'll get all that output on one line with the object references inline and you can then drop down their inspectors from there.
The short answer is no.
But
If your use-case involves attempting to log perpetually changing data while avoiding console-bloat, then one way to achieve this (in certain browsers) would be to use console.clear() before each output.
function writeSingleLine (msg) {
console.clear();
console.log(msg);
}
writeSingleLine('this');
setTimeout( function () { writeSingleLine('is'); }, 1000);
setTimeout( function () { writeSingleLine('a'); }, 2000);
setTimeout( function () { writeSingleLine('hack'); }, 3000);
Note that this would probably break any other logging functionality that was taking place within your application.
Disclaimer: I would class this as a hack.
collect your output in an array and then use join function with a preferred separator
function echo(name, num){
var ar= [];
for(var i =0;i<num;i++){
ar.push(name);
}
console.log(ar.join(', '));
}
echo("apple",3)
check also Array.prototype.join() for mode details
var elements = ['Fire', 'Wind', 'Rain'];
console.log(elements.join());
// expected output: Fire,Wind,Rain
console.log(elements.join(''));
// expected output: FireWindRain
console.log(elements.join('-'));
// expected output: Fire-Wind-Rain
If your only purpose to stop printing on many lines, One way is to group the values if you don't want them to fill your complete console
P.S.:- See you browser console for output
let arr = new Array(10).fill(0)
console.groupCollapsed('index')
arr.forEach((val,index) => {
console.log(index)
})
console.groupEnd()
console.group
console.groupCollapsed
Something about #shennan idea:
function init(poolSize) {
var pool = [];
console._log = console.log;
console.log = function log() {
pool.push(arguments);
while (pool.length > poolSize) pool.shift();
draw();
}
console.toLast = function toLast() {
while (pool.length > poolSize) pool.shift();
var last = pool.pop() || [];
for (var a = 0; a < arguments.length; a++) {
last[last.length++] = arguments[a];
}
pool.push(last);
draw();
}
function draw() {
console.clear();
for(var i = 0; i < pool.length; i++)
console._log.apply(console, pool[i]);
}
}
function restore() {
console.log = console._log;
delete console._log;
delete console.toLast;
}
init(3);
console.log(1);
console.log(2);
console.log(3);
console.log(4); // 1 will disappeared here
console.toLast(5); // 5 will go to row with 4
restore();
A simple solution using buffered output. Works with deno and should work with node.js. (built for porting pascal console programs to javascript)
const write = (function(){
let buffer = '';
return function (text='\n') {
buffer += text;
let chunks = buffer.split('\n');
buffer = chunks.pop();
for (let chunk of chunks)
{console.log(chunk);}
}
})();
function writeln(text) { write(text + '\n'); }
To flush the buffer, you should call write() at the end of program.
If you mix this with console.log calls, you may get garbage output.
if you want for example console log array elements without a newline you can do like this
const arr = [1,2,3,4,5];
Array.prototype.log = (sep='') => {
let res = '';
for(let j=0; j<this.lengthl j++){
res += this[j];
res += sep;
}
console.log(res);
}
// console loging
arr.log(sep=' '); // result is: 1 2 3 4 5
Useful for debugging or learning what long chained maps are actually doing.
let myConsole = (function(){
let the_log_buffer=[[]], the_count=0, the_single_line=false;
const THE_CONSOLE=console, LINE_DIVIDER=' ~ ', ONE_LINE='ONE_LINE',
PARAMETER_SEPARATOR= ', ', NEW_LINE = Symbol();
const start = (line_type='NOT_ONE_LINE') => {
the_log_buffer=[[]];
the_count=0;
the_single_line = line_type == ONE_LINE;
console = myConsole;
}
const stop = () => {
isNewline();
console = THE_CONSOLE;
};
const isNewline = a_param => {
if (the_single_line && a_param==NEW_LINE) return;
const buffer_parts = the_log_buffer.map(one_set=> one_set.join(PARAMETER_SEPARATOR))
const buffer_line = buffer_parts.join(LINE_DIVIDER);
if (the_single_line) {
THE_CONSOLE.clear();
}
THE_CONSOLE.log( buffer_line );
the_log_buffer = [[]];
the_count=0;
}
const anObject = an_object => {
if (an_object instanceof Error){
const error_props = [...Object.getOwnPropertyNames(an_object)];
error_props.map( error_key => an_object['_' + error_key] = an_object[error_key] );
}
the_log_buffer[the_count].push(JSON.stringify(an_object));
}
const aScalar = a_scalar => {
if (typeof a_scalar === 'string' && !isNaN(a_scalar)) {
the_log_buffer[the_count].push("'" + a_scalar + "'");
} else {
the_log_buffer[the_count].push(a_scalar);
}
}
const notNewline = a_param => typeof a_param === 'object' ? anObject(a_param):aScalar(a_param);
const checkNewline = a_param => a_param == NEW_LINE ? isNewline(a_param) : notNewline(a_param);
const log = (...parameters_list) => {
the_log_buffer[the_count]=[];
parameters_list.map( checkNewline );
if (the_single_line){
isNewline(undefined);
}else{
const last_log = parameters_list.pop();
if (last_log !== NEW_LINE){
the_count++;
}
}
}
return Object.assign({}, console, {start, stop, log, ONE_LINE, NEW_LINE});
})();
function showConcatLog(){
myConsole.stop();
myConsole.start();
console.log('a');
console.log('bb');
console.dir({i:'not', j:'affected', k:'but not in step'})
console.log('ccc');
console.log([1,2,3,4,5,'6'], {x:8, y:'9'});
console.log("dddd", 1, '2', 3, myConsole.NEW_LINE);
console.log("z", myConsole.NEW_LINE, 8, '7');
console.log(new Error("error test"));
myConsole.stop();
}
myConsole.start(myConsole.ONE_LINE);
var stop_callback = 5;
function myCallback(){
console.log(stop_callback, 'Date.now()', myConsole.NEW_LINE, Date.now());
stop_callback--;
if (stop_callback>0){
window.setTimeout(myCallback, 1000);
}else{
showConcatLog();
}
}
window.setTimeout(myCallback, 1000);
You can use a spread operator to display output in the single line. The new feature of javascript ES6. see below example
for(let i = 1; i<=10; i++){
let arrData = [];
for(let j = 1; j<= 10; j++){
arrData.push(j+"X"+i+"="+(j*i));
}
console.log(...arrData);
}
That will print 1 to 10 table in single line.
// Source code for printing 2d array
window.onload = function () {
var A = [[1, 2], [3, 4]];
Print(A);
}
function Print(A) {
var rows = A.length;
var cols = A[0].length;
var line = "";
for (var r = 0; r < rows; r++) {
line = "";
for (var c = 0; c < cols; c++) {
line += A[r][c] + " ";
}
console.log(line);
}
}