`Proxy` all of the things! Part 1: Counters

To celebrate the long-overdue death of Internet Explorer, I’m writing a series of articles on a massively useful and underused API that’s available in every other mainstream JavaScript environment: Proxy.

With a Proxy, you can “intercept and redefine …


This content originally appeared on DEV Community and was authored by lionel-rowe

To celebrate the long-overdue death of Internet Explorer, I'm writing a series of articles on a massively useful and underused API that's available in every other mainstream JavaScript environment: Proxy.

With a Proxy, you can "intercept and redefine fundamental operations" for an object, such as getters and setters.

Let's start with a simple example: counters with a default value.

Let's say you're implementing a simple algorithm to count the number of occurrences of each word in a text. In a language like Ruby, you could do that easily like this:

def word_counts(text)
    counters = Hash.new(0)

    text.split(/\W+/).each do |word|
        counters[word] += 1
    end

    counters
end

wc = word_counts 'a a a b b c' # {"a" => 3, "b" => 2, "c" => 1}
wc['a'] # 3
wc['d'] # 0

That Hash.new(0) is really neat: it gives us key-value pairs with a default value of 0 that we can increment from.

JavaScript objects, on the other hand, can't be given a default value. Passing a parameter to an Object constructor instead converts that value itself into an object: new Object(0) returns Number {0}, which isn't what we want at all.

However, we can easily mimic Ruby's Hash.new behavior with a proxy:

/**
 * @template T
 * @param {T} defaultVal
 * @returns {Record<string, T>}
 */
const hashWithDefault = (defaultVal) => new Proxy({}, {
    get(target, key) {
        return target[key] ?? defaultVal
    },
})

The target parameter passed to the getter is the proxied object itself — the first argument passed to the Proxy constructor. As we didn't override set, setting simply works as normal — the property is set on that same target.

Our JavaScript hashWithDefault(0) now works very similarly to Ruby's Hash.new(0). We can now easily and ergonomically write our word count function like this:

/** @param {string} text */
const wordCounts = (text) => {
    const counters = hashWithDefault(0)

    for (const word of text.split(/\W+/)) {
        counters[word]++
    }

    return counters
}

const wc = wordCounts('a a a b b c') // Proxy {a: 3, b: 2, c: 1}
wc.a // 3
wc.d // 0

Cool, no? In part 2, we'll look at using Proxy with a setter function as well.


This content originally appeared on DEV Community and was authored by lionel-rowe


Print Share Comment Cite Upload Translate Updates
APA

lionel-rowe | Sciencx (2021-08-26T23:54:46+00:00) `Proxy` all of the things! Part 1: Counters. Retrieved from https://www.scien.cx/2021/08/26/proxy-all-of-the-things-part-1-counters/

MLA
" » `Proxy` all of the things! Part 1: Counters." lionel-rowe | Sciencx - Thursday August 26, 2021, https://www.scien.cx/2021/08/26/proxy-all-of-the-things-part-1-counters/
HARVARD
lionel-rowe | Sciencx Thursday August 26, 2021 » `Proxy` all of the things! Part 1: Counters., viewed ,<https://www.scien.cx/2021/08/26/proxy-all-of-the-things-part-1-counters/>
VANCOUVER
lionel-rowe | Sciencx - » `Proxy` all of the things! Part 1: Counters. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2021/08/26/proxy-all-of-the-things-part-1-counters/
CHICAGO
" » `Proxy` all of the things! Part 1: Counters." lionel-rowe | Sciencx - Accessed . https://www.scien.cx/2021/08/26/proxy-all-of-the-things-part-1-counters/
IEEE
" » `Proxy` all of the things! Part 1: Counters." lionel-rowe | Sciencx [Online]. Available: https://www.scien.cx/2021/08/26/proxy-all-of-the-things-part-1-counters/. [Accessed: ]
rf:citation
» `Proxy` all of the things! Part 1: Counters | lionel-rowe | Sciencx | https://www.scien.cx/2021/08/26/proxy-all-of-the-things-part-1-counters/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.