(See the best response by Multiverse7.)
user << browse(file,"window=[id]")
user << output(url_encode("hi"), "[id]:initialize")

Problem description:

Basically I want to call initialize("hi") in javascript but I can't seem to get it to work. I've tried params2list and it didn't work either unfortunately.

I've googled this several times and found results for it, but everything I tried does not work or does not apply to what I am doing. The documentation very lightly covers this but not with javascript commands. I'm at my wits end right now.

Best response
The id that you are using is the id of the window that contains the browser, so in the case of using the popup window form of browse(), the full id of the browser would actually be window_id.browser. Since the id of the browser control itself cannot be specified using browse(), we cannot give the browser a unique id.

Unfortunately, this leads to incompatibility with the "id:script" form of output(). The output() proc expects only the id of the browser control, without including the window. This means it will accept "unique_browser_id:scriptname", but not "window_id.browser_id:scriptname". I'm not sure if this is a limitation or a bug.

In any case, what this means is you will have to avoid using browse(), create your browser popup manually, and ensure that the browser control's id is unique.

Here is an example using your vars:
winclone(user, "window", id)
// Create a new window.

winshow(user, id)
// Show the window.

winset(user, "browser([id])", "parent=[id];type=browser;size=0x0;anchor1=0,0;anchor2=100,100")
// Create a browser control inside of the window.

// Sleep to make sure the interface has time to load.

user << output(file, "browser([id])")
// Send the file to the browser through output().

// Sleep to make sure the browser has time to load the file.

user << output("initialize(\"hi\");", "browser([id]):eval")
// Use eval() to call any arbitrary JavaScript code, which can reference the code that was already sent.

Without those sleep() calls, you can get the occasional failure. This is because Dream Seeker's interface is not synchronized with the server, so race conditions can occur. For large files, you may need to sleep for longer.

It would be nice if you could specify an existing browser with browse(), other than the default, or use a browser's full id in output() when calling JavaScript, but these procs are just not compatible, so this is the best we can do for now.
In response to Multiverse7
Thank you, I will try this.
If I were to send commands that resize the window, would I be sending this command through windset after the file is loaded?
In response to BurgerBB
You can resize the window with the winset() proc from the server (in DM), resize it as a result of specific changes to the skin by setting certain skin parameters to the .winset command, or even resize it very quickly from JavaScript by setting window.location to a byond://winset? url. This and many more things are documented in the controls and parameters guide.

You can resize the window at any point after it has been created. For an initial size or other changes to a window, the best time to do this would be after the winclone() and before the winshow(), so that none of it is seen until it's ready. You can even call winshow() after the browser has loaded everything, or not call it at all for an invisible browser control. To maximize responsiveness you can even cram what winshow() does into a winset() by simply setting the is-visible parameter, which does the same thing.