Help me understand why I can't do the following:
function rgb(r = 0, g = 0, b = 0) {
this.r = r % 255
this.g = g % 255
this.b = b % 255,
this.str = function() {
return `rgb(${this.r}, ${this.g}, ${this.b})`
}
}
function rect(w, h, x, y, rgb = new rgb()) {
this.dim = {
w: w,
h: h
}
this.pos = {
x: x,
y: y
}
this.rgb = rgb
}
I get the following error (when calling rect()
):
ReferenceError: can't access lexical declaration `rgb' before initialization
function rgb(r = 0, g = 0, b = 0) {
this.r = r % 255
this.g = g % 255
this.b = b % 255,
this.str = function() {
return `rgb(${this.r}, ${this.g}, ${this.b})`
}
}
function rect(w, h, x, y, rgb = new rgb()) {
this.dim = {
w: w,
h: h
}
this.pos = {
x: x,
y: y
}
this.rgb = rgb
}
const r = new rect(1, 2, 3, 4);
Both rgb
and rect
are defined in the same file, and rgb
is defined before rect
.
Your variable names are conflicting. You have a rgb
function on the top level, but you also have a rgb
parameter in rect
's parameter list. When inside a parameter list, when referencing a variable name, the interpreter will try to find what the variable name binds to - if the parameter list already has that variable name, it will reference that binding. So new rgb()
is referencing the parameter rgb
, which hasn't been initialized yet.
This isn't exactly what's happening, but the scope of a parameter list looks a bit like if the parameter names are declared with let
, and then assigned values, eg the scope of
const fn = (a, b, c = 'bar') => {
console.log('fn invoked');
};
is similar to:
const fn = (argA, argB, argC) => {
let a;
let b;
let c;
a = argA;
b = argB;
c = argC === undefined ? 'bar' : argC;
fnBody(a, b, c);
};
const fnBody = (a, b, c) => {
console.log('fn invoked');
}
So doing rgb = new rgb()
is like
let rgb;
rgb = argRGB === undefined ? new rgb() : argRGB
// ^^^ reference to un-initialized variable
For similar reasons, you can do:
const fn = (a, b = a) => {
console.log(a, b);
};
fn('foo');
Also similarly, when declaring a variable, you can't reference the name of the variable you're declaring until the variable has finished initializing:
const foo = null || foo;
Precise function names can help prevent bugs as well. Consider changing to something like:
function makeColors(r = 0, g = 0, b = 0) {
this.r = r % 255;
this.g = g % 255;
this.b = b % 255;
this.str = function() {
return `rgb(${this.r}, ${this.g}, ${this.b})`
};
}
function rect(w, h, x, y, colors = new makeColors()) {
this.dim = {
w: w,
h: h
}
this.pos = {
x: x,
y: y
}
this.colors = colors
}
const r = new rect(3, 4, 5, 6);
console.log(r);