JavaScript Proxy
Just like one would expect from a proxy, the Proxy object in JavaScript acts as an intermediary between a caller and an intended target. As Proxy will intercept operations, one can alter or extend the original functionality for a given object.
Awesome! How does it work?
A proxy constructor accepts a target and a handler. In the following case we create a proxy with a person object as intended target and handler as the object that overrides the normal behavior of person.
We provide a custom implementation for get that will check if the property accessed is the name-property. If so, we do not give back that name, but hides it. If another property is accessed, we pass the call to the original behavior of the object by using built-in Reflect object.
let person = {name: "Jane", age: 18}; let handler = { get: function(target, prop, receiver) { if(prop === "name") return "Name is hidden"; return Reflect.get(...arguments) } }; let proxy = new Proxy(target, handler); console.log(proxy.name); // Name is hidden console.log(proxy.age); // 18
In the previous example the handler only has a get-property, meaning that it will only override get accessor for the object. Other properties on the object will still works as before.
To illustrate either further, a proxy provided with an empty object as handler will work just as the original object itself.
let person = {name: "Jane", age: 18}; let emptyHandler = {}; let proxy = new Proxy(target, emptyHandler); console.log(proxy.name); // Jane console.log(proxy.age); // 18
Real world scenario: Localization
Nowadays, a web site often needs to support multiple languages and as a business grows one might want to extend to new regions. Therefore, one would not insert language specific phrases directly in HTML, but somehow make this dynamic. During an expansion one would need to employ proficient translators to add support for more languages.
For the translators it would be hugely beneficial to see which language key is used where on a web site in order to fully grasp the context while translating. Comparing this to only working with a list of keys (e.g. welcome_header, welcome_info_text) we understand the huge benefit it can provide.
An example implementation in React is showcased below. The code shown has a custom hook that returns a dictionary object corresponding to the language set in current user settings.
import locales from "./all-locales"; // import all possible languages export const useLocalization(wordKey) => { // Get current language key from user settings const selectedLanguageKey = useSelector(state => state.userSettings.language); // return dictionary for given language return locales[selectedLanguage]; }
In turn, this would be consumed from within a React component like this
export const Welcome(wordKey) => { //Get current localization const localization = useLocalization(); return ( <div> <h1>{localization.welcome_header}</h1> <p>{localization.welcome_info_text}</p> </div> ) }
In order to control when to show keys we need a feature that allows users to toggle whether the key or translations should be shown. We would make the feature permission based so only translators are allowed to toggle.
Lastly, we would change useLocalization() to return a proxy instead of a dictionary object directly. The handler we provide to the proxy would check whether the setting to show word keys is turned on or not. Turned on, return the word key. Turned off, pass the operation along to original behavior. An example implementation can be seen below.
import locales from "./all-locales"; export const useLocalization(wordKey) => { const selectedLanguageKey = useSelector(state => state.userSettings.language); // Get settings to show word key const showIdsInsteadOfWord = useSelector(state => state.userSettings.showIdsInsteadOfWord); let handler = { get: function(target, prop, receiver) { // Given settings to show Ids is toggled on, return the key provided if(showIdsInsteadOfWord) return prop; return Reflect.get(...arguments) } }; return new Proxy(locales[selectedLanguage], handler); // return proxy }