Documentation
The documentation for what you are trying to do can be found under BaseAudioContext
, specifically the BaseAudioContext.createGain()
method.
The MDN documentation is lacking a little in that it only provides snippets that will not work as is. As such, an overly simplified example is given below, bearing in mind that this may not be best practice.
Explanation
The oscillator and gain control are both audio nodes. As such, you should picture them in a signal chain like that given below.

The oscillator node passes through the gain node which passes through to the audio context.
Solution
Using your current format, as self contain snippet is given below (see jsfiddle here)
<!DOCTYPE html>
<html>
<head>
<script>
var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
var gainNode = audioCtx.createGain();
gainNode.connect(audioCtx.destination);
var gain = 0.1;
//---------------------------------------------------------------------
gainNode.gain.setValueAtTime(gain, audioCtx.currentTime);
</script>
</head>
<!-- ===================================================================== -->
<body>
<div>
<button onclick="myFunction()">
Click me
</button>
</div>
<script>
function myFunction()
{
//---------------------------------------------------------------------
var duration = 0.5; // in seconds
//---------------------------------------------------------------------
var oscillator = audioCtx.createOscillator();
oscillator.type = 'square';
oscillator.frequency.value = 500;
oscillator.connect(gainNode);
oscillator.start(audioCtx.currentTime);
oscillator.stop(audioCtx.currentTime + duration);
//---------------------------------------------------------------------
}
</script>
</body>
<!-- ===================================================================== -->
</html>
Best practice
For best practice, I would suggest you should avoid recreating nodes over and over again. Rather, I would simply turn the gain up for a short period, then turn it back down, an example of which is given below.
As far as I can tell, there is no envelope generator node for WebAudio, but you could use .linearRampToValueAtTime()
if needed.
NOTE: This is not currently working in Safari.
(see jsfiddle here)
<!DOCTYPE html>
<html>
<head>
<script>
//---------------------------------------------------------------------
// Edit These
var gain = 0.1;
var duration = 1000;
//---------------------------------------------------------------------
var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
var gainNode = audioCtx.createGain();
//---------------------------------------------------------------------
var oscillator = audioCtx.createOscillator();
oscillator.type = 'square';
oscillator.frequency.value = 500;
//---------------------------------------------------------------------
oscillator.connect(gainNode);
gainNode.connect(audioCtx.destination);
//---------------------------------------------------------------------
gainNode.gain.setValueAtTime(0.0, audioCtx.currentTime); // turned off by default
oscillator.start(audioCtx.currentTime);
//---------------------------------------------------------------------
</script>
</head>
<!-- ===================================================================== -->
<body>
<div>
<button onclick="soundOn()">
Click me
</button>
</div>
<script>
function mute()
{
gainNode.gain.setValueAtTime(0.0, audioCtx.currentTime);
}
function soundOn()
{
gainNode.gain.setValueAtTime(gain, audioCtx.currentTime);
setTimeout(mute,duration);
}
</script>
</body>
<!-- ===================================================================== -->
</html>
Further Resources
If you are struggling with interacting with audio context in this was, I would suggest trying out a library such as p5.js and the p5.sound library.
Look at the https://p5js.org/reference/#/p5.Oscillator to see whether it is a more intuitive approach.