First: A transistor acts as a switch - amplifier. Base gets token amount of electricity - Emitter starts emitting as much as is put into the collector.
Connect two transistors in a row - Collector of (1) to power, emitter of (1) to collector of (2). Emitter of (2) is "output". Apply voltage to bases of both, and it passes current, producing a "1". But remove any, and it's "0". That's an AND gate.
Now connect them in parallel instead. Two collectors to power, two emitters together to output. Any of them will output current into output line. You must disable both to produce a "0". That's OR.
Now connect a resistor and a transistor between power and ground. Tap into the point between the transistor and the resistor as "output". If you apply voltage to the base, the transistor passes all the current and voltage on 'output' drops to zero, connected through the open transistor to ground. Whatever comes through the resistor escapes through the path of least resistance. You have zero output on positive input. Now remove the base voltage and the transistor's resistance skyrockets. Now the resistor drives enough current from the power line to produce a clear '1' on output. That's NOT.
You can now combine these, connecting outputs to inputs, into a whole bunch of others. NAND = NOT A AND NOT B. XOR: A AND NOT B, OR B AND NOT A. XNOR: (A AND B) OR (NOT A AND NOT B). And so on.
Connect two XNOR gates in an X: one input pin of each as input, the other connected to output of the other.
There, this is one bit of memory. With a rather cumbersome writing (S=1: set to 1, R=1: set to 0, S=0,R=0 - hold value, S=1,R=1 - burst in flames, or at least produce nonsensical noise) but it can be made into a much more sensible thing with a couple other gates on input and output. Attach NAND and AND on input, one input on each from 'in', the other from 'write'. Attach a 3-state buffer on output, with 3rd state (high impedance) input marked 'read'. Now you can write or read this on demand, without 'read' it won't touch the bus you connect it to, without 'write' it won't change state no matter what appears on 'in'. You may connect 'in' and 'out' to the same line. If 'write' is active, it will read and remember what's on that line. If 'read' is active, it will drive that line.
That's a fully usable bit of memory.
Put 8 in a row, each output to one line. The 8 lines are a data bus. You have a byte of data.
Get other 8 lines (from now on known as Address Bus) and connect them to a demultiplexer. That's a construct of a mass of AND and NAND gates, that converts every possible combination of the states of the 8 lines into 256 different output lines.
Now put repeat the row of 8 bits 256 times, every row getting an AND between the one dedicated incoming line from the demultiplexer dedicated to it, and a single global 'Write', and one AND between the same demux line and the 'Read'. And you have a working 8KB bank of memory. Set the right combination of 8 bits on the address bus, state your intent: 'read=1' or 'write=1' and you'll either store the state of the data bus in given byte, or output it onto the data bus from that byte.
Add three-state buffer on all inputs and outputs (you have 18 of them so far, 8 data, 8 address, 1 read, 1 write), and activate them through 19th input: Chip Enable. Pack that into an integrated circuit and you have the 8KB RAM chip.
Want more RAM? A demultiplexer controlling 'Chip Enables' of multiple chips will let you switch between multiple dies.
Then, in the CPU, as the internal sequence moves to 'READ COMMAND', a register (just a byte, 8 RS flip-flops, set aside for a special purpose) named Program Counter is connected to the address line. Read is activated. Through the Data line the set of bits that corresponds to the new command returns to the CPU. It goes to 'command decoder' - which is just another demultiplexer. And that demultiplexer activates one line that activates a specific subsystem of a whole zoo of subsystems of the CPU - responsible for that specific instruction.
Say, the instruction is JMP. Jump to a different place in the program, marked by the value in memory immediately after the command. The set of gates activated through the Command decoder will activate the following operations in sequence: first, advance the program counter. Then output it onto the address bus. Activate 'Read', and then stuff the output from the data bus - right into Program Counter. Command done. The control returns to reading the next command - except 'next' is now pointed by the Program Counter which just got modified. That's what the JMP command worked.