I'll talk about Lua 5.1 for now, since you're referring to (get/set)fenv() which aren't in any Lua past 5.1.
To set the environment of a function, you use
setfenv( f, env )
Where f is the function and env is the table environment.
Setfenv also works with levels, as well as functions, similar to error() and getfenv().
Spoiler
Level 1 is the current function, level 2 is the caller, level 3 is the caller's caller, and so on. Getfenv works like setfenv(). You can pass it a function (like I did in that screenshot) and it will return that function's environment, or you can pass in a level to get (something being called)'s environment, for example getfenv(2) being the caller's environment.
To set and get environments when the two functions are removed… well, depends. If you are the one loading the code, it's relatively easy. Otherwise, it's impossible. If there is a function object loaded in some environment you have no control over, there is no way to get/modify its environment without (get/set)fenv. However, if you are the one that loads it, you can give it a custom environment.
local environments = {}
local function newloadstring( str, src, bin, env )
local penv = setmetatable( {}, { __index = env } )
local f, err = load( str, src, bin, penv )
if not f then return nil, err end
environments[f] = penv
return f
end
local function newsetfenv( f, env )
if not environments[f] then error "that function was not loaded with newloadstring()" end
getmetatable( environments[f] ).__index = env
end
local function newgetfenv( f )
if not environments[f] then error "that function was not loaded with newloadstring()" end
return getmetatable( environments[f] ).__index
end
That code will allow you to set/get the environment of a function you've loaded with newloadstring(). Hopefully you can see how it works. The cool thing about this is that you can actually set a function environment to a function :o/>.