Re:JavaScript TC39 implementing hashmark private class fields
by hajile on Friday August 04, 2017 @10:24PM
(#14933888)
When you execute a function, you set the program to execute the new function, but first, you take care of the related bookkeeping. A very important part of that is the function scope(s).
I'll first explain prototypical inheritance (because the two have close parallels). When you access a property in an object, a method runs behind the scenes. It does something like: search all the keys in the given object. If there is a matching key, return the value. If no such key exists, check for a __proto__ key. If it contains a value, call this function recursively on that object (and return whatever it gives back). If there is no __proto__ value, return `undefined`.
Let's assume an interpreter (to make it easy). Before we call a function, we need to setup the closure. The closure is an object with the names of all the variables you defined plus a few builtin things.
As we parse the function, any params, `var` or `function` statement creates an entries in the object. The values for the params are then pre-defined from the stuff provided by the caller. All the function statements are also pre-compiled. We add internal values for the return value, the parent closure (we'll call it __closure__), and some other things.
As the function runs, we come across a variable name. We then call a method to get it. That method searches the current scope for the name and returns the value. If none is found, it returns the result of calling itself on the __closure__ object. If no such object exists, it returns a `ReferenceError`.
Modern JITs do many fancy things with closures (just like they do with objects), but this basic mental model should cover most things.
I'll first explain prototypical inheritance (because the two have close parallels). When you access a property in an object, a method runs behind the scenes. It does something like: search all the keys in the given object. If there is a matching key, return the value. If no such key exists, check for a __proto__ key. If it contains a value, call this function recursively on that object (and return whatever it gives back). If there is no __proto__ value, return `undefined`.
Let's assume an interpreter (to make it easy). Before we call a function, we need to setup the closure. The closure is an object with the names of all the variables you defined plus a few builtin things.
As we parse the function, any params, `var` or `function` statement creates an entries in the object. The values for the params are then pre-defined from the stuff provided by the caller. All the function statements are also pre-compiled. We add internal values for the return value, the parent closure (we'll call it __closure__), and some other things.
As the function runs, we come across a variable name. We then call a method to get it. That method searches the current scope for the name and returns the value. If none is found, it returns the result of calling itself on the __closure__ object. If no such object exists, it returns a `ReferenceError`.
Modern JITs do many fancy things with closures (just like they do with objects), but this basic mental model should cover most things.