0

How can I customize the console.log() function in JavaScript to retain its existing behavior but also adding custom functionality?

For Example: This button Prints the message in the console, which is its expected behaviour

<html>

<body>

  <h1>Button Element</h1>
  <button type="button" id="some-btn" onclick="console.log('Message')">Click Me</button>

</body>

</html>

But I want to add a custom functionality to console.log() while still being able to print message to console.

console.log = (arg) => {
  document.getElementById("some-btn").innerHTML = arg
}
<html>

    <body>

      <h1>Button Element</h1>
      <button type="button" id="some-btn" onclick="console.log('Message')">Click Me</button>

    </body>

    </html>

In the snippet above, I have the desired custom behaviour of the console.log() function but it loses its original function which is to Print the message in the console.

How can I keep both the old and the new functionality?

Manan Sharma
  • 507
  • 1
  • 5
  • 18
  • 2
    `const { log: oldLog } = console; console.log = (...args) => { oldLog(...args); /* do your fancy stuff*/}` – Yury Tarabanko Dec 23 '20 at 19:51
  • 2
    But also - DON'T do it ;) Just declare a normal function `function log() {}` that does what you need and also do `console.log` – Yury Tarabanko Dec 23 '20 at 19:52
  • 3
    Does this answer your question? [How to override a JavaScript function](https://stackoverflow.com/questions/5409428/how-to-override-a-javascript-function) – SuperStormer Dec 23 '20 at 21:56
  • Please take the time to read my answer, I probably spent too much time there. At least tell me what you think – Mister Jojo Dec 23 '20 at 22:16

2 Answers2

2

You can override the log function. But I would not recommend it:

const log = console.log;
console.log = (...args) => {
  log(...args);
  // your logic
}

Just do something like that:

const yourLog = (...args) => {
  console.log(...args);
  // your logic
}

You should never override builtin Functions etc.

Christian
  • 22,585
  • 9
  • 80
  • 106
  • I agree, but doesn't this fall in the realm of opinion? Maybe you could support your argument with specific reasons. – Matt Morgan Dec 23 '20 at 21:04
1

So, this what I done, a complete solution with example of code using.

the basic idea is to keep the reference on console.log then to redo its assignment as shown in the question.

It looks like this:

var consoleLogModus = 'original' // or 'custom'
var nativConsoleLog = console.log

console.log = (...args) =>
  {
  if (consoleLogModus === 'original' )
    {
    nativConsoleLog(...args)
    }
  else
    {
    //  your custom code for (console.log)
    }
  }

But as this gives a not very clean code, I prefer to put it all in an IIFE closure, with an object / method to control it.

If we want to go back to the original console.log rather than putting console.log back with its initial reference, I use a switch in its execution

The result is there, with a full interface to test it.

const consoleLogCommand = (function() // IIFE for control over console.log()
  {
  var nativConsoleLog = console.log
    , modusArr        = [ 'original', 'prefix', 'function' ]
    , prefix          = '>'        // default message
    , choose_modus    = modusArr[1] // default choice
    , redirect_fct    = () => {}    // default function
    , obj = 
      { setModus : modus =>
          {
          let n           = parseInt(modus) 
          if (isNaN(n)) n = modusArr.indexOf(modus)
          choose_modus    = modusArr[((n<0) ? 1 : n % 3)]
          }
      , getModus  : ()  => ({ lib:choose_modus, ref: modusArr.indexOf(choose_modus) })
      , setPrefix : inL => { let p = String(inL).trim(); prefix = (p.length) ? p : '>' }
      , getPrefix : ()  => prefix
      , redirect  : fct => { redirect_fct = fct }
      }
    ;
  window['console']['log'] = function(...args) // The new " console.log "
    {
    switch (choose_modus)
      {
      case modusArr[0]:               // 'natural':
        nativConsoleLog(...args)
        break;
      case modusArr[1]:               // 'prefix':
        console.clear()
        nativConsoleLog(prefix, ...args)
        break;
      case modusArr[2]:               // 'function':
        redirect_fct(...args)
        break;
      }
    }
  return obj
  } )()


/*------------------
  Test Interface :
-------------------*/

const myForm = document.forms['my-form'];
  
/* sample function 1 to replace console.log() */
function fct_one(...args) 
  {
  myForm['bt-4-fct1'].textContent = args.join('_')
  }

/* sample function 2 to replace console.log() */
function fct_two(...args) 
  {
  myForm['txt-4-fct2'].textContent = args.join('\n')
  }

/* summary of the possible functions for using the form interface */
const chooseFunction =
  { 'fct_one': fct_one
  , 'fct_two': fct_two
  }


const setRadioDefault = (rName, val) =>
  {
  myForm.querySelectorAll(`input[name="${rName}"]`).forEach(r=>
    {
    if (r.value === val) r.setAttribute('checked','checked')
    else                 r.removeAttribute('checked')
    })
  }
/* init...    */

  consoleLogCommand.setModus( 1 )
  setRadioDefault('modus', '1' )
  consoleLogCommand.redirect(fct_one)
  setRadioDefault('fct2Call', 'fct_one' )
  myForm.prefix.defaultValue   = consoleLogCommand.getPrefix()
myForm.reset()

myForm.oninput = e =>
  {
  switch(e.target.name)
    {
    case 'modus':    
        consoleLogCommand.setModus( myForm.modus.value )
        setRadioDefault('modus', myForm.modus.value )
        break;
    case 'prefix':   
        consoleLogCommand.setPrefix( myForm.prefix.value )
        myForm.prefix.defaultValue = consoleLogCommand.getPrefix()
        break;
    case 'fct2Call': 
        consoleLogCommand.redirect( chooseFunction[myForm.fct2Call.value] )
        setRadioDefault('fct2Call', myForm.fct2Call.value )
        break;
    }
  }
myForm.onsubmit = e =>
  {
  e.preventDefault()
  let args = [...myForm.arg].map(el=>el.value.trim()).filter(t=>t.length)
  console.log( ...args ) // finally
  }
.as-console-wrapper { max-height:100% !important; top:0; left:70% !important; width:30%; }
.as-console-row         { background-color: yellow; }
.as-console-row::after  { display:none !important; }
.as-console-row::before { content: 'log:'; font-size: .8em; }

body, textarea, input  {
  font-family : Helvetica, Arial sans-serif;
  font-size   : 14px;
  }
form {
  margin : 1em; 
  }
fieldset {
  width         : 40em;
  margin-bottom : .7em;
  border-radius : .6em;
  border-color  : turquoise;
  }
legend {
  padding      : 0 .5em;
  color        : darkblue;
  font-variant : small-caps;
  }
button {
  margin-left : 1.2em;
  }
label {
  display : inline-block;
  margin  : .7em 0 0 1.2em;
  }
textarea {
  vertical-align : top;
  margin-left    : .4em;
  padding        : .2em .4em;
  }
<form name="my-form">
  <h3> console.log Customazing ! </h3>
  <fieldset>
    <legend>Chose Mode : </legend>
    <label><input type="radio" name="modus" value="0"> original way  </label>
    <label><input type="radio" name="modus" value="1"> with prefix   </label>
    <label><input type="radio" name="modus" value="2"> call function </label>
  </fieldset>
  <fieldset>
    <legend>Parameters : </legend>
    <label> add Prefix : <input type="text" name="prefix" value="abc" placeholder="blah blah blah"> </label>
    <br>
    <label><input type="radio" name="fct2Call" value="fct_one"> call function 1 </label>
    <label><input type="radio" name="fct2Call" value="fct_two"> call function 2 </label>
  </fieldset>
  <fieldset>
    <legend> Arguments : </legend>
    <label> arg 1  : <input type="text" name="arg" value="" placeholder="console.log( arg1 )" > </label>
    <br>
    <label> arg 2  : <input type="text" name="arg" value="" placeholder="console.log( . , arg2 )" > </label>
    <br>
    <label> arg 3  : <input type="text" name="arg" value="" placeholder="console.log( . , . , arg3 )" > </label>
  </fieldset>
  <fieldset>
    <legend>Test Part : </legend>
    <label> function 1 = change this text button  : <button type="button" name="bt-4-fct1">text</button> </label>
    <br>
    <label> function 2 = change this text  : <textarea name="txt-4-fct2" placeholder="textarea"></textarea> </label>
  </fieldset>
  <button type="reset">reset console.log Arguments</button>
  <button type="submit">submit a console.log() </button>
</form>
 
Mister Jojo
  • 20,093
  • 6
  • 21
  • 40