<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mánu Fosela</title>
    <description>The latest articles on DEV Community by Mánu Fosela (@manufosela).</description>
    <link>https://dev.to/manufosela</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F386088%2F2e07a2cb-dc32-4fb0-9b26-fe7d57550519.png</url>
      <title>DEV Community: Mánu Fosela</title>
      <link>https://dev.to/manufosela</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/manufosela"/>
    <language>en</language>
    <item>
      <title>The Shifting Role of the Software Engineer</title>
      <dc:creator>Mánu Fosela</dc:creator>
      <pubDate>Tue, 11 Aug 2026 09:43:26 +0000</pubDate>
      <link>https://dev.to/manufosela/the-shifting-role-of-the-software-engineer-4ph8</link>
      <guid>https://dev.to/manufosela/the-shifting-role-of-the-software-engineer-4ph8</guid>
      <description>&lt;p&gt;This is the first of three articles about how I see AI adoption in software development within companies and how I'm pushing it forward at TRIBBU, my company.&lt;/p&gt;

&lt;p&gt;First, I want to talk about the change itself: what's happening to our work and why I think we're facing a change in the level of abstraction. In the second one I'll talk about how we can govern software development carried out by agents. And in the third, probably the most complicated one, about how to lead people through this transition.&lt;/p&gt;

&lt;p&gt;Because technology will probably be the easy part.&lt;/p&gt;

&lt;p&gt;We're living through a “turbulent” yet exciting period with the arrival of what we somewhat incorrectly call artificial intelligence into our lives.&lt;/p&gt;

&lt;p&gt;Although I think software development is where its adoption has gone deepest, little by little it's making its way into every discipline and more and more people are using it to make their day-to-day work easier and better.&lt;/p&gt;

&lt;p&gt;It's true that some people use it to do their work for them. Often badly, especially when that work requires judgment.&lt;/p&gt;

&lt;p&gt;And it's also true that if an AI can do your work because that work doesn't require judgment, then your job will, sooner or later, be replaced by AI.&lt;/p&gt;

&lt;p&gt;But that's not what I want to talk about.&lt;/p&gt;

&lt;p&gt;I want to focus on how to lead the transition towards software development with AI inside companies.&lt;/p&gt;

&lt;p&gt;And here I see two different problems.&lt;/p&gt;

&lt;p&gt;One is how to “evangelize”, more than convince, how to get them to convince themselves, to “convert”, and get developers to see the enormous benefits it can bring, leaving behind bad past experiences caused by using it without judgment or knowledge.&lt;/p&gt;

&lt;p&gt;The other one, much more complicated in my opinion, is &lt;strong&gt;how to do it well&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Because right now there's a lot of ignorance, very little accumulated experience and, above all, a huge disparity of opinion about how far we're willing to stop doing what until now we considered our job: writing code.&lt;/p&gt;

&lt;p&gt;I'm going to address both problems, but I want to start with the how.&lt;/p&gt;

&lt;p&gt;Because I think that if we can answer the how properly, solving the first problem will be much easier.&lt;/p&gt;

&lt;p&gt;It will be easier for a programmer to accept delegating an increasing part of their work to an AI if they can trust the system through which they do it.&lt;/p&gt;

&lt;p&gt;Because let's not fool ourselves: feeling that something artificial is beginning to do what you've spent years doing, what you're good at and, even worse, what you probably love doing, is hard. Very hard.&lt;/p&gt;

&lt;p&gt;But denying the evidence, what's happening, won't make it stop happening. Let's not be like little children who cover their faces and think nobody can see them.&lt;/p&gt;

&lt;p&gt;And let's be aware that an AI-native generation is taking shape, and we are responsible for training and educating it.&lt;/p&gt;

&lt;p&gt;This generation won't be made up of developers who first learned to program and then incorporated AI into their work. That's us.&lt;/p&gt;

&lt;p&gt;They will learn to develop with it from day one.&lt;/p&gt;

&lt;p&gt;And those who don't adapt will be overtaken, much sooner than we think.&lt;/p&gt;

&lt;h2&gt;
  
  
  When Was the Last Time You Looked at Assembly?
&lt;/h2&gt;

&lt;p&gt;Let me start with a question, and I hope the metaphor and the distance between the two things are clear.&lt;/p&gt;

&lt;p&gt;When was the last time you looked at the assembly generated by your compiler to check that it was managing registers, memory or loop efficiency properly?&lt;/p&gt;

&lt;p&gt;Probably never.&lt;/p&gt;

&lt;p&gt;And yet there was an entire generation of programmers who did. Who had to.&lt;/p&gt;

&lt;p&gt;Because early compilers generated worse code than a good assembly programmer could write. Trusting them blindly was simply reckless.&lt;/p&gt;

&lt;p&gt;Those programmers were right at that moment.&lt;/p&gt;

&lt;p&gt;The ones who were wrong were those who turned that temporary distrust into a permanent identity.&lt;/p&gt;

&lt;p&gt;Those who ten years later were still arguing that a good programmer had to write assembly while the rest of the world had moved up one level of abstraction.&lt;/p&gt;

&lt;p&gt;I think we're already inside that same kind of moment with generative AI.&lt;/p&gt;

&lt;p&gt;I'm not saying it's exactly the same.&lt;/p&gt;

&lt;p&gt;In fact, there are huge differences, as I said at the beginning.&lt;/p&gt;

&lt;p&gt;But conceptually, I see that we're facing another leap in abstraction.&lt;/p&gt;

&lt;p&gt;Until now we've been incorporating tools that helped us program. Editors. IDEs. Autocomplete. Frameworks. Stack Overflow. Copilot...&lt;/p&gt;

&lt;p&gt;All of them, in one way or another, allowed us to write code more easily or more quickly, with fewer errors or by failing earlier.&lt;/p&gt;

&lt;p&gt;But we were still writing the code.&lt;/p&gt;

&lt;p&gt;With agents, something different is starting to happen. More and more, we're moving away from saying “I want to write this code” and starting to say “I want this to happen”.&lt;/p&gt;

&lt;p&gt;This changes absolutely everything.&lt;/p&gt;

&lt;p&gt;Because the leap we're trying to make isn't simply from one tool to another, no. We're moving, with all the obvious differences, from assembly to the compiler, except this time the leap is several orders of magnitude bigger. An exponential leap.&lt;/p&gt;

&lt;p&gt;A compiler receives high-level code and generates low-level code. And yes, I know, following deterministic rules and within a bounded space. True. That's why I call it an exponential leap, because we're moving into an enormously more open space.&lt;/p&gt;

&lt;p&gt;But we're getting an AI to receive an idea, a need, a specification, some constraints or a conversation and produce software.&lt;/p&gt;

&lt;p&gt;And as I've already said, there's vastly more space between one thing and the other, and therefore vastly more things that can go wrong.&lt;/p&gt;

&lt;p&gt;And this is precisely one of the big differences compared with a compiler. A compiler is deterministic and verifiable. An agent isn't. It can make mistakes in subtle, plausible and difficult-to-detect ways.&lt;/p&gt;

&lt;p&gt;And the skeptic who says that the verification problem hasn't been solved is right. It hasn't.&lt;/p&gt;

&lt;p&gt;That's why I'm not saying that we can stop verifying what AI does. I'm saying that verifying it by reading every single line it generates can't be the solution either.&lt;/p&gt;

&lt;h2&gt;
  
  
  We Get Carried Away With AI
&lt;/h2&gt;

&lt;p&gt;At first the experience is spectacular. You ask it for a function. It does it.&lt;/p&gt;

&lt;p&gt;You ask it for an endpoint. Same thing.&lt;/p&gt;

&lt;p&gt;You explain a small feature and it changes four files, creates the tests and apparently everything works.&lt;/p&gt;

&lt;p&gt;And you think: “Holy shit.”&lt;/p&gt;

&lt;p&gt;Then you take another step. You give it something bigger. It starts touching things. Changes others. Interprets something differently from what you expected. Suddenly something doesn't add up. You tell it to fix it. It fixes that and breaks something else. You explain the new problem. It tries again. And shortly afterwards you have a mountain of useless, incomprehensible, unfixable and unmaintainable code.&lt;/p&gt;

&lt;p&gt;And you don't even really know when exactly it started fucking everything up.&lt;/p&gt;

&lt;p&gt;That's when a phrase we've heard quite a lot appears:&lt;/p&gt;

&lt;p&gt;“That's where you can tell whether you really know the fundamentals. If you know how things work, you can review what the AI has done and fix it.” Well, yes. Up to a point.&lt;/p&gt;

&lt;p&gt;Because let's be honest. There comes a point where not even Uncle Bob would understand a fucking thing about what it has done.&lt;/p&gt;

&lt;p&gt;And, besides, there's a much more important problem.&lt;/p&gt;

&lt;p&gt;If an AI can produce code much faster than I can read it, trying to control that AI by reading everything it generates simply doesn't scale.&lt;/p&gt;

&lt;p&gt;Some people talk about knowledge debt. But I don't think that's quite it. I think we're mixing two different things.&lt;/p&gt;

&lt;p&gt;It's like accepting the compiler but insisting on reviewing all the assembly it generates afterwards. It makes no sense. Especially with today's processors, whose assembly code very few humans are capable of understanding.&lt;/p&gt;

&lt;p&gt;Or, at least, it can't be the final solution.&lt;/p&gt;

&lt;p&gt;The fact that reviewing the code no longer scales doesn't mean the verification problem has been solved. It means exactly the opposite: we need another way to solve it.&lt;/p&gt;

&lt;p&gt;Even more so as agents keep getting better and we give them more and more autonomy.&lt;/p&gt;

&lt;p&gt;We need rules. A harness. Guardrails. External mechanisms that the agent doesn't control and that allow us to let it work without constantly looking over its shoulder.&lt;/p&gt;

&lt;p&gt;Not to tell it exactly how it has to do things. We don't need that anymore. We need to set the limits, prevent certain actions and check that what it delivers meets what we expect.&lt;/p&gt;

&lt;p&gt;But I'll talk about that in the second part.&lt;/p&gt;

&lt;h2&gt;
  
  
  Having the Tool Doesn't Mean Getting Value From It
&lt;/h2&gt;

&lt;p&gt;And here another confusion appears that I see quite often.&lt;/p&gt;

&lt;p&gt;Having access to a tool is one thing and knowing how to get value from it is something very different.&lt;/p&gt;

&lt;p&gt;Today practically anyone can open ChatGPT, Claude, Copilot or any other agent and ask it to build something.&lt;/p&gt;

&lt;p&gt;That doesn't mean anyone can build a good product.&lt;/p&gt;

&lt;p&gt;In the same way that having an IDE doesn't make you a developer, having an AI capable of writing code doesn't automatically make you capable of creating software that delivers value.&lt;/p&gt;

&lt;p&gt;If writing code had really been the only barrier to creating good products, by now we should be seeing a massive explosion of disruptive applications.&lt;/p&gt;

&lt;p&gt;And I honestly don't see it.&lt;/p&gt;

&lt;p&gt;What I do see is a lot of vibe coders paying for advertising to try to sell, again and again, variations of the same worn-out product.&lt;/p&gt;

&lt;p&gt;Because code was never the product. The user doesn't want or need our code.&lt;/p&gt;

&lt;p&gt;They don't want our hexagonal architecture, our patterns, our framework or to know whether we use microservices or monoliths.&lt;/p&gt;

&lt;p&gt;They want to solve a problem.&lt;/p&gt;

&lt;p&gt;Code was, and still is, the means to achieve that. Or one of them.&lt;/p&gt;

&lt;p&gt;The difference is that this means has just become dramatically cheaper and more democratized.&lt;/p&gt;

&lt;p&gt;AI is making it extraordinarily cheap to &lt;strong&gt;plant software&lt;/strong&gt; (a brilliant analogy from the great eduferro).&lt;/p&gt;

&lt;p&gt;But planting isn't the same as having a good garden.&lt;/p&gt;

&lt;p&gt;Someone still has to decide what to plant, when to plant it and what for. Then it has to be watered, pruned, fertilized, whatever no longer serves a purpose has to be removed, and it has to be adapted when conditions change.&lt;/p&gt;

&lt;p&gt;Because software isn't something you build and finish. It's a living thing that evolves, and neglecting it is a great way to end up with a garden bed full of shit.&lt;/p&gt;

&lt;p&gt;Someone has to understand the problem. Know what's worth doing and what isn't. Choose between alternatives. Prioritize. Make decisions with incomplete information. Validate. Change their mind and iterate.&lt;/p&gt;

&lt;p&gt;And, above all, &lt;strong&gt;have judgment&lt;/strong&gt; to know whether what we've created actually delivers any value.&lt;/p&gt;

&lt;p&gt;The barrier to creating software is falling.&lt;/p&gt;

&lt;p&gt;The barrier to creating value, not necessarily.&lt;/p&gt;

&lt;h2&gt;
  
  
  Our Work Is Shifting
&lt;/h2&gt;

&lt;p&gt;That's why I don't think the conclusion is that AI is going to replace software development.&lt;/p&gt;

&lt;p&gt;I think our work is shifting, because that work, as it exists today, will be replaced.&lt;/p&gt;

&lt;p&gt;One level up.&lt;/p&gt;

&lt;p&gt;If before we spent a large part of our effort telling a machine &lt;strong&gt;how&lt;/strong&gt; it had to do something through a programming language, increasingly we'll spend more effort defining &lt;strong&gt;what&lt;/strong&gt; should happen, why, under what conditions and how we can know whether the result is correct.&lt;/p&gt;

&lt;p&gt;That requires judgment.&lt;/p&gt;

&lt;p&gt;Probably much more than we needed to implement many of the tasks we do today.&lt;/p&gt;

&lt;p&gt;And this, for me, is where the truly important change lies.&lt;/p&gt;

&lt;p&gt;We're not stopping developing software.&lt;/p&gt;

&lt;p&gt;We're starting to stop being necessarily the ones who write every single line of it.&lt;/p&gt;

&lt;h2&gt;
  
  
  And the Window Won't Stay Open Forever
&lt;/h2&gt;

&lt;p&gt;Every change in abstraction level opens a window of opportunity.&lt;/p&gt;

&lt;p&gt;It happened with version control, for example. With CI. With cloud. With infrastructure as code.&lt;/p&gt;

&lt;p&gt;For a while, those who adopted it well had a huge advantage over those who said: “We're fine like this.”&lt;/p&gt;

&lt;p&gt;Then it stopped being an advantage. It simply became the normal way of working.&lt;/p&gt;

&lt;p&gt;I think we're in one of those windows now.&lt;/p&gt;

&lt;p&gt;Except this time everything is happening much faster.&lt;/p&gt;

&lt;p&gt;Not adapting doesn't mean standing still. It means falling behind.&lt;/p&gt;

&lt;p&gt;Because while you keep working the same way, the bar for what we consider normal productivity keeps moving, but this time at a speed that makes it increasingly difficult to jump onto the train once it's already moving.&lt;/p&gt;

&lt;p&gt;Today, knowing how to work well with agents is a competitive advantage. Tomorrow it will simply be part of the job.&lt;/p&gt;

&lt;p&gt;But as I said before, first we have to solve an important problem, because if we're not going to review every single line produced by an AI...&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;how the hell do we know whether what it has done is actually right?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's what the second part will be about.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>leadership</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Karajan v3.0.0: a local-first multi-agent orchestrator that conducts AI CLIs like an orchestra</title>
      <dc:creator>Mánu Fosela</dc:creator>
      <pubDate>Wed, 03 Jun 2026 22:46:30 +0000</pubDate>
      <link>https://dev.to/manufosela/karajan-v300-a-local-first-multi-agent-orchestrator-that-conducts-ai-clis-like-an-orchestra-59fi</link>
      <guid>https://dev.to/manufosela/karajan-v300-a-local-first-multi-agent-orchestrator-that-conducts-ai-clis-like-an-orchestra-59fi</guid>
      <description>&lt;p&gt;&lt;code&gt;karajan-code@3.0.0&lt;/code&gt; is on npm. &lt;code&gt;nvm install 22.22.1 &amp;amp;&amp;amp; npm i -g karajan-code@3&lt;/code&gt; and you're done.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I built Karajan
&lt;/h2&gt;

&lt;p&gt;I love coding with AI. What I don't love is babysitting it.&lt;/p&gt;

&lt;p&gt;If you've spent any time with Claude Code, Codex, or Gemini, you know the loop:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You describe what you want.&lt;/li&gt;
&lt;li&gt;You watch the model work.&lt;/li&gt;
&lt;li&gt;You catch it skipping tests, hallucinating an API, or touching the wrong layer, even with a solid &lt;code&gt;CLAUDE.md&lt;/code&gt;/&lt;code&gt;AGENTS.md&lt;/code&gt; and SKILLs in place.&lt;/li&gt;
&lt;li&gt;You stop it, correct it, relaunch it.&lt;/li&gt;
&lt;li&gt;Repeat.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Fine for a one-off change. Doesn't scale to a real project with a known plan, real tests, and a real quality gate. You end up being the human stuck in the middle of an async loop you can't pause, retry, or measure.&lt;/p&gt;

&lt;p&gt;I wanted something different. A tool where I describe what I want once and, from there, a set of AI agents (a coder, a reviewer, a tester, a SonarQube gate, a security auditor) run the loop themselves and ping me when it's done. Reproducibly. Locally. Using the subscriptions I already pay for.&lt;/p&gt;

&lt;p&gt;That tool is Karajan.&lt;/p&gt;

&lt;p&gt;The name is a nod to Herbert von Karajan, the conductor who never played a single instrument but imposed a unified vision on dozens of musicians until they sounded like one. Karajan didn't replace the musicians: he coordinated them under a single guiding intent. Karajan Code does the same with your AI agents: none of them is in charge, all of them converge under a single baton that arbitrates and unifies.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Karajan actually is
&lt;/h2&gt;

&lt;p&gt;Karajan is a local-first multi-agent orchestrator written in vanilla JavaScript on Node 22.&lt;/p&gt;

&lt;p&gt;You describe a task (in a markdown file, a user story, or directly on the command line) and Karajan runs a role-based pipeline over it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;task
  → triage      (classifies complexity, decides route)
  → researcher  (reads existing code)
  → architect   (designs the change)
  → planner     (breaks it into steps)
  → coder       (writes code and tests)
  → SonarQube   (static analysis as a gate)
  → tester      (runs the real test suite)
  → reviewer    (independent agent reviews the diff)
  → security    (security pass)
  → commiter    (commit, push, opens PR)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each role is a CLI agent. The coder can be Claude, the reviewer can be Codex, the tester can be Aider. Karajan doesn't call &lt;code&gt;/v1/messages&lt;/code&gt;: it spawns &lt;code&gt;claude -p&lt;/code&gt;, &lt;code&gt;codex&lt;/code&gt;, &lt;code&gt;gemini&lt;/code&gt;, &lt;code&gt;aider&lt;/code&gt;, &lt;code&gt;opencode&lt;/code&gt; as child processes and reads their stdout/stderr. That single architectural decision unlocks two things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zero API cost.&lt;/strong&gt; Your existing Pro / Plus / Max subscriptions do the work. No new bills.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-provider routing.&lt;/strong&gt; A powerful coder + a strict reviewer + a cheap triage agent = the right model for each role, with automatic fallback when one hits its quota.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The whole system is TDD-first by default. The coder writes tests alongside the code, the tester runs them for real, the reviewer sees the diff. If something fails, the reviewer feeds back to the coder and the loop iterates, bounded by &lt;code&gt;maxIterations&lt;/code&gt; and &lt;code&gt;maxIterationMinutes&lt;/code&gt; so it can't spiral.&lt;/p&gt;

&lt;p&gt;A few more pieces worth knowing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MCP server.&lt;/strong&gt; Karajan ships as an MCP server, so you can drive the full pipeline from inside Claude Code, Cursor, Codex, or any MCP host. &lt;code&gt;kj_run&lt;/code&gt;, &lt;code&gt;kj_plan&lt;/code&gt;, &lt;code&gt;kj_code&lt;/code&gt;, &lt;code&gt;kj_review&lt;/code&gt;, &lt;code&gt;kj_audit&lt;/code&gt;, &lt;code&gt;kj_rag_query&lt;/code&gt;: full pipeline access without leaving the conversation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Solomon, the AI judge.&lt;/strong&gt; An independent role the Brain orchestrator consults when there's a real dilemma (security vs. deadline, two reviewers disagreeing). Not on every loop; only when the Brain can't decide deterministically.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Story Board.&lt;/strong&gt; A small local web dashboard at &lt;code&gt;http://localhost:4000&lt;/code&gt; showing every user story, every session, every plan, every RAG metric. The single source of truth for the team.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Local RAG.&lt;/strong&gt; Each project gets its own embedded code index (&lt;code&gt;~/.karajan/rag.db&lt;/code&gt;). The pipeline retrieves real code before planning, so the architect sees what already exists. Six embedding providers (Ollama, OpenAI, Voyage, Cohere, Mistral, local ONNX). Tree-sitter-based chunkers for JS, TS, Python, Rust, Go, and Java.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;kj audit&lt;/code&gt;.&lt;/strong&gt; A deterministic-first audit command: dead code, unused dependencies, complexity growth, security findings (OSV, Semgrep, SonarQube), accessibility hints, Web Performance budgets, and an AI Harness Scorecard run via Docker that gives an objective 0-100 score for "how AI-friendly is this repo right now." Keeps a per-project history and draws sparkline trends.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What v3.0.0 brings
&lt;/h2&gt;

&lt;p&gt;v3.0.0 is a runtime alignment, not a feature drop.&lt;/p&gt;

&lt;p&gt;Node 20 hit EOL on 2026-04-30. The Active LTS line is Node 22. Three of Karajan's dependencies independently bumped to majors requiring Node 22+: &lt;code&gt;lint-staged&lt;/code&gt; 17, &lt;code&gt;commander&lt;/code&gt; 15, and &lt;code&gt;better-sqlite3&lt;/code&gt; 12.10. Rather than publishing four staggered minors patching each constraint separately, v3.0.0 bundles the runtime bump with the dep majors that depend on it.&lt;/p&gt;

&lt;p&gt;Migration is a single command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nvm &lt;span class="nb"&gt;install &lt;/span&gt;22.22.1 &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; nvm use 22.22.1
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; karajan-code@3
kj doctor    &lt;span class="c"&gt;# checks runtime + HW + tooling&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you were already on Node 22+ and your &lt;code&gt;~/.karajan/&lt;/code&gt; works, nothing changes. No public API changes: &lt;code&gt;kj run&lt;/code&gt;, &lt;code&gt;kj plan&lt;/code&gt;, MCP tools, role templates, RAG, Story Board, audit, telemetry, all intact. Existing sessions, plans, RAG index, and audit history are forward-compatible; nothing to migrate by hand.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why a major with no API changes?
&lt;/h3&gt;

&lt;p&gt;Semver. Bumping the minimum Node version is a breaking change for downstream consumers: an install that worked on Node 20 now hard-fails. That alone qualifies, and the three dep majors on board each qualify on their own semver. Cutting a single v3.0.0 surfaces the runtime change once instead of four times.&lt;/p&gt;

&lt;p&gt;The release also brings documentation polish: a new footprint and hardware requirements section in the README so you know what you're getting into before installing. &lt;code&gt;kj&lt;/code&gt; itself is 5.2 MB on npm and &lt;code&gt;~/.karajan/&lt;/code&gt; runs around 40 MB. Ollama (optional, 6.55 GB), SonarQube (optional, 1.47 GB), and the qmd cache (optional, ~2.2 GB) are the heavy optional layers. Three profiles: Minimal ~250 MB, Recommended ~8.5 GB, Full ~11 GB.&lt;/p&gt;

&lt;h2&gt;
  
  
  v1 to v3: how Karajan grew
&lt;/h2&gt;

&lt;p&gt;Karajan didn't start as a multi-agent orchestrator. It started as a shell script.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;v0.x: One script.&lt;/strong&gt; task → claude → diff → codex review → done. Hardcoded to two agents. No retry, no cost tracking, no SonarQube, no test integration. It worked, roughly, on a Tuesday afternoon.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;v1.0 to v1.1: Quality gates and roles.&lt;/strong&gt; SonarQube became a mandatory step between coder and reviewer. The TDD policy meant any code change required a test change. Then the monolithic script became a role-based pipeline: &lt;code&gt;BaseRole&lt;/code&gt;, &lt;code&gt;BaseAgent&lt;/code&gt;, 12 configurable roles, review profiles, Solomon escalation, budget tracking.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;v1.2 to v1.3: MCP server and extensibility.&lt;/strong&gt; The MCP server made Karajan callable from inside any MCP-speaking AI agent. The plugin system let users wrap their own CLIs as Karajan agents without forking. Planning Game integration connected the pipeline to project management. Git automation closed the loop with auto-commit, auto-PR, auto-rebase.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;v1.4 to v1.7: Resilience.&lt;/strong&gt; Rate-limit detection across all supported CLIs. Automatic fallback when the primary coder hits its quota. Smart model selection mapping triage complexity to model tier (trivial → Haiku, complex → Opus). Interactive checkpoints replacing the brittle hard timeout. In-process MCP execution so subprocess SIGKILLs stopped killing agents mid-work.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;v1.40 to v1.46: Sovereignty, OpenSkills, parallel stories.&lt;/strong&gt; The pipeline learned to defend its own decisions against host AI overrides (pipeline sovereignty guard). OpenSkills brought domain knowledge to coders, reviewers, and architects. Parallel user stories ran independent stories concurrently in git worktrees. First SEA binaries appeared: &lt;code&gt;kj&lt;/code&gt; running without Node installed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;v1.50 to v1.58: Telemetry, domain knowledge, i18n, WebPerf.&lt;/strong&gt; Telemetry (opt-out, no code or personal data) to finally measure what was happening. Domain knowledge files (&lt;code&gt;DOMAIN.md&lt;/code&gt;) injecting business context into every role. i18n letting the pipeline speak EN or ES end to end. Web Performance as a first-class quality gate (Core Web Vitals via Chrome DevTools MCP, inspired by Joan Leon's WebPerf Snippets).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;v2.0: Karajan Brain.&lt;/strong&gt; A central AI orchestrator deciding routing, enriching feedback, suggesting direct actions, and compressing outputs between roles. Solomon moved from "every loop" to "real dilemmas only." Tester and security became blocking gates. The proxy subsystem (which never worked well under SSE/WebSockets) was dropped in favor of RTK for token savings.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;v2.x: The "I use this daily" phase.&lt;/strong&gt; Too many releases to list, but the highlights: stack-aware audit (v2.9.0), Docker/shell installer (v2.10.0), Story Board hardening (v2.13.0), plan adherence scoring + golden tasks (v2.12.0), shared team Story Board (v2.31.0), editable config UI (v2.30.0), multi-language RAG with AST chunkers for Python/Rust/Go/Java (v2.34.0), retrieval quality harness (&lt;code&gt;kj rag eval&lt;/code&gt;, v2.34.0), and the AI Harness Scorecard golden metric integrated into &lt;code&gt;kj audit&lt;/code&gt; (v2.32.0-v2.33.0).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;v3.0.0: Runtime alignment.&lt;/strong&gt; No new features. Node 22 baseline, three dep majors, one migration command, zero public API change. The story of "boring releases that buy you a year of headroom."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That arc, compressed: a shell script → a role-based pipeline → an orchestrator with a brain → a local-first, MCP-driven, RAG-powered, multilingual, multi-provider, test-first team tool. The same idea throughout: many different AI agents, one baton that makes them converge.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;p&gt;Install:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nvm &lt;span class="nb"&gt;install &lt;/span&gt;22.22.1 &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; nvm use 22.22.1
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; karajan-code@3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Smoke test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kj &lt;span class="nt"&gt;--version&lt;/span&gt;           &lt;span class="c"&gt;# 3.0.0&lt;/span&gt;
kj doctor              &lt;span class="c"&gt;# checks Node, agents, Docker, SonarQube, RAG...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Initialize a project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;your-repo
kj init                &lt;span class="c"&gt;# autodetects stack, suggests agents, scaffolds .karajan/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run a task:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kj run &lt;span class="s2"&gt;"Add a /healthz endpoint with a unit test that returns 200"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--coder&lt;/span&gt; claude &lt;span class="nt"&gt;--reviewer&lt;/span&gt; codex
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or from inside Claude Code / Cursor / any MCP host, just call &lt;code&gt;kj_run&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Open the Story Board:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kj board start         &lt;span class="c"&gt;# http://localhost:4000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the loop. Describe what you want. Let the orchestra play.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to find it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;npm:&lt;/strong&gt; &lt;code&gt;karajan-code&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docs:&lt;/strong&gt; &lt;a href="https://karajancode.com/docs" rel="noopener noreferrer"&gt;https://karajancode.com/docs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repo:&lt;/strong&gt; github.com/manufosela/karajan-code&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;License:&lt;/strong&gt; AGPL-3.0&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Author:&lt;/strong&gt; &lt;a href="https://github.com/manufosela" rel="noopener noreferrer"&gt;@manufosela&lt;/a&gt;, built in the open.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you try it and something surprises you (good or bad), I want to know. Open an issue, reach out on GitHub, or reply here.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>javascript</category>
      <category>productivity</category>
    </item>
    <item>
      <title>I’ve tried RTK and it saves a lot of tokens, but I think Squeezr is on another level.</title>
      <dc:creator>Mánu Fosela</dc:creator>
      <pubDate>Sun, 05 Apr 2026 16:37:21 +0000</pubDate>
      <link>https://dev.to/manufosela/ive-tried-rtk-and-it-saves-a-lot-of-tokens-but-i-think-squeezr-is-on-another-level-2fjo</link>
      <guid>https://dev.to/manufosela/ive-tried-rtk-and-it-saves-a-lot-of-tokens-but-i-think-squeezr-is-on-another-level-2fjo</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/sergioramosv/i-was-burning-through-ai-tokens-without-realizing-it-heres-how-i-fixed-it-bn" class="crayons-story__hidden-navigation-link"&gt;I was burning through AI tokens without realizing it. Here's how I fixed it.&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/sergioramosv" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3862441%2F4095b39e-a525-4be1-bff2-26abcb1fa47a.jpg" alt="sergioramosv profile" class="crayons-avatar__image" width="96" height="96"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/sergioramosv" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Sergio Ramos Vicente
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Sergio Ramos Vicente
                
              
              &lt;div id="story-author-preview-content-3457029" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/sergioramosv" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3862441%2F4095b39e-a525-4be1-bff2-26abcb1fa47a.jpg" class="crayons-avatar__image" alt="" width="96" height="96"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Sergio Ramos Vicente&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/sergioramosv/i-was-burning-through-ai-tokens-without-realizing-it-heres-how-i-fixed-it-bn" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Apr 5&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/sergioramosv/i-was-burning-through-ai-tokens-without-realizing-it-heres-how-i-fixed-it-bn" id="article-link-3457029"&gt;
          I was burning through AI tokens without realizing it. Here's how I fixed it.
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/tooling"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;tooling&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/opensource"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;opensource&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/claude"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;claude&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/sergioramosv/i-was-burning-through-ai-tokens-without-realizing-it-heres-how-i-fixed-it-bn" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/raised-hands-74b2099fd66a39f2d7eed9305ee0f4553df0eb7b4f11b01b6b1b499973048fe5.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;3&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/sergioramosv/i-was-burning-through-ai-tokens-without-realizing-it-heres-how-i-fixed-it-bn#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            3 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
    </item>
    <item>
      <title>Over-Architecting in Web Design</title>
      <dc:creator>Mánu Fosela</dc:creator>
      <pubDate>Thu, 10 Oct 2024 05:01:23 +0000</pubDate>
      <link>https://dev.to/manufosela/on-architecture-in-web-design-367n</link>
      <guid>https://dev.to/manufosela/on-architecture-in-web-design-367n</guid>
      <description>&lt;p&gt;I recently read &lt;a href="https://x.com/justinfagnani/status/1844080475612270887" rel="noopener noreferrer"&gt;a post&lt;/a&gt; by &lt;a class="mentioned-user" href="https://dev.to/justinfagnani"&gt;@justinfagnani&lt;/a&gt; on X that says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Lit is not a framework. The browser is the framework."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This got me thinking about how we've been building for the web in recent years.&lt;/p&gt;

&lt;p&gt;For quite some time now, if you know HTML, CSS, and JavaScript, you really don’t need a framework to build web applications. At most, you might use some libraries to simplify certain tasks, but even these are gradually being incorporated into the platform itself, like routing or state management.&lt;/p&gt;

&lt;p&gt;Our focus, however, has shifted towards learning frameworks, and now meta-frameworks, which do make it easier to build web environments. They optimize pages, automatically generate necessary files like &lt;code&gt;sitemaps.xml&lt;/code&gt;, optimize images, remove unused CSS, bundle, minify, and optimize JavaScript. They’re effective, yes. But they don't adhere to the standard.&lt;/p&gt;

&lt;p&gt;Meta-frameworks like Astro let you use standards, but they don’t exactly make it easy. Instead, they streamline using other frameworks or their own components in a more user-friendly, non-standard format to "simplify" component creation. They also employ techniques to facilitate SEO, loading, and indexing—depending on how you’ve implemented them.&lt;/p&gt;

&lt;p&gt;To me, this approach has two major issues:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cognitive overload&lt;/strong&gt;: Developers must learn to manage not only the framework itself but now also the meta-framework and its set of tools, which often adds unnecessary complexity to project architecture.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Detachment from the standard&lt;/strong&gt;: Focusing on frameworks means we’re not investing time in understanding the latest developments in the web itself, which are substantial. CSS, for example, is making a huge leap forward with features like &lt;code&gt;container queries&lt;/code&gt;. Meanwhile, JavaScript and HTML are also evolving, with HTML potentially introducing a new &lt;code&gt;&amp;lt;select&amp;gt;&lt;/code&gt; element that will allow HTML and CSS within &lt;code&gt;&amp;lt;option&amp;gt;&lt;/code&gt;, opening new and more flexible ways to create rich selectors.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In many frameworks, though, these innovations are implemented through their own components, so to developers, it can seem like these new features are framework inventions instead of standard advancements.&lt;/p&gt;

&lt;p&gt;I remember a few years ago, when these meta-frameworks were just emerging, a developer excitedly told me, “They’ve invented SSR (Server-Side Rendering); now we can generate HTML on the server, creating static pages.” I looked at him in surprise. He insisted, thinking I was just as impressed with this “novelty” saying, “Isn’t it incredible? What a fantastic idea.” The irony was that SSR has been around since the early days of the web.&lt;/p&gt;

&lt;p&gt;Today’s web developers, those studying web development and entering the field, often lack historical context. They don’t know how web development originally worked. They don’t understand the reasons we moved from server-side rendering to client-side rendering and started using frameworks. Somewhere along the line, when “Ajax” gained popularity, we lost our way—probably driven by the desire for standards to cover everything we needed, while big companies fought to impose their own criteria, tags, and languages in the browser (I still remember Microsoft’s infamous VisualBasicScript).&lt;/p&gt;

&lt;p&gt;Frameworks aren’t the problem. Not at all. They added power and value to web development. They allowed us to create applications for everyone, spurring the rise of hundreds of thousands of web developers and bootcamps.&lt;/p&gt;

&lt;p&gt;Frameworks and meta-frameworks aren’t the issue; they even helped democratize web development, enabling millions to create applications and fueling the bootcamp boom. But as the web platform matures and standards become more robust, framework creators have business incentives to retain and promote their tools. They’re not going to say, “Stop using my framework; you can do everything with standards now.” Plus, migrating applications built with these frameworks to the standard is nearly impossible, especially since, in my experience, most lack E2E or functional tests to ensure that migration maintains the original behavior.&lt;/p&gt;

&lt;p&gt;So, why aren’t we investing in tools that help us leverage today’s standards?&lt;/p&gt;

&lt;p&gt;There isn’t a meta-framework that “forces” you to use the standard, making it easier in the process.&lt;/p&gt;

&lt;p&gt;We need solutions that help us organize our projects efficiently and assist with build and optimization tasks if we want to do SSR, CSR, SSG, ISR, Hydration, create MPAs or SPAs. But we should be fully aware of our needs and the pros and cons of each choice. These tools should optimize images, JavaScript, CSS, and generate only the necessary files. They should allow the use of libraries that stick to the standard and adequately cover the platform’s remaining gaps. They should optimize and support SEO, loading, and indexing, facilitate testing, and harness the platform’s power.&lt;/p&gt;

&lt;p&gt;It’s time to reduce over-engineering and excessive architectural design in our web projects. Let’s keep learning, not just how to use a framework, but also how to appreciate and apply the incredible advancements in web standards.&lt;/p&gt;

&lt;p&gt;No excuses.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>beginners</category>
      <category>inspiration</category>
    </item>
    <item>
      <title>Desarrollo Web y Web Components</title>
      <dc:creator>Mánu Fosela</dc:creator>
      <pubDate>Tue, 29 Dec 2020 01:04:19 +0000</pubDate>
      <link>https://dev.to/manufosela/desarrollo-web-y-web-components-1j0g</link>
      <guid>https://dev.to/manufosela/desarrollo-web-y-web-components-1j0g</guid>
      <description>&lt;h1&gt;
  
  
  Disclaimer
&lt;/h1&gt;

&lt;p&gt;Lo que vierto en este post es mi opinión. Mi punto de vista. Mi percepción. Desde mi experiencia y mis sesgos. Y sobre todo desde mi ignorancia en muchos campos.&lt;/p&gt;

&lt;h1&gt;
  
  
  Sobre mi y mis inicios como desarrollador
&lt;/h1&gt;

&lt;p&gt;Llevo programando para la web desde 1997.&lt;br&gt;
A parte de HTML, CSS y Javascript, he pasado por varios lenguajes: CGIs en C, ASP, JSP, PHP, Java, Perl y Ruby si no recuerdo mal. Algunos durante unos meses otros durante años.&lt;br&gt;
He trabajado con bases de datos MSSQL, MySQL, Oracle, IBMDb2 y MongoDB.&lt;br&gt;
Y he trabajado con servidores IIS, Apache, Tomcat y Nginx.&lt;br&gt;
Desde siempre Windows (era un mal necesario) y Linux (era un suplicio a principios de siglo)&lt;/p&gt;

&lt;p&gt;He visto cómo hemos pasado de que un desarrollador/equipo web fuera responsable de todo a la especialización más exquisita.&lt;br&gt;
Aprendí a hacer testing, TDD, metodología XP y pair programing en 2007. Hacia 2008 con el boom de Javascript y Jquery, empecé a especializarme más en Javascript, aunque no fue hasta 2010 cuando pasé a ser “oficialmente” FrontEnd Developer, a pesar de que mis dotes de diseño dejan mucho que desear.&lt;br&gt;
Y dejé de tocar la parte back y configuración de servidores. Dejé de subir a producción por FTP y empecé a usar control de versiones con CVS y Subversion.&lt;/p&gt;

&lt;p&gt;Luego empezaron a aparecer librerías como Backbone y arrancó el boom de los frameworks del front, las llamadas AJAX y el desarrollo de APIs que alimentaban esos frontales “mágicos”&lt;/p&gt;

&lt;p&gt;Por cierto, AJAX empecé a usarlo hacia 2007 cuando existía ¡¡desde 2002!! Y yo usando iframes ocultos, leyendo información y cargándola en la página principal, una “guarrada”... pero es que antes era otra epoca ;)&lt;/p&gt;

&lt;p&gt;En 2015 me enganché a los web-components, con Polymer en su versión 0.8 y a la espera de que los ansiados estándares vieran su primera versión que no llegó hasta 3 años después.&lt;br&gt;
Y aunque siempre he probado, y hecho alguna aplicación que otra, en todos los frameworks típicos, nunca me han entusiasmado en exceso.&lt;br&gt;
Sí. Mola. Facilitan. Ahorran tiempo (una vez les coges el punto). Unifican los grandes desarrollos. La curva de aprendizaje puede venir hecha al incorporarte a un equipo. Y sobre todo hacen mucha “magia” que se puede traducir en desarrollo mas rápido y menos dolores de cabeza, pero ¿necesitaba usarlos?&lt;/p&gt;

&lt;h1&gt;
  
  
  Empiezo la polémica
&lt;/h1&gt;

&lt;p&gt;Creo que en los proyectos grandes donde he trabajado, o he visto trabajar desde que ejerzo como manager, está plenamente justificado el uso de un framework, pero ¿Y en un blog? ¿Y en una web de contenidos? ¿Y en algunos juegos? En internet veo muchas webs que son contenidos y creo que no necesitan un framework para desarrollarlas.&lt;/p&gt;

&lt;p&gt;¿Que se pueden usar frameworks? Correcto. ¿Que no penaliza? Bueno, depende. A nivel de lo que es una página web, solo hace falta hacer “botón derecho” (lo siento no uso Mac), “ver código fuente de la página” y ver en dicho código fuente “atrocidades” que ni DreamWeaver en sus mejores momentos…&lt;br&gt;
Porque o bien no hay contenido, ya que se genera dinámicamente, y por tanto es contenido invisible a los crawlers de los buscadores, o bien lo que se escupe aparece “ofuscado”, cuando una web de contenido, justo lo que se tiene que leer perfectamente es el contenido, con sus tags HTML, usando la semántica de las etiquetas HTML (cuantos años luché al principio por una web Semántica)&lt;br&gt;
O eso creí entender allá por 1997 cuando leí mi primer libro de HTML.&lt;/p&gt;

&lt;p&gt;Y lo de que no es necesario usar un framework para generar contenido como un blog parece que se están dando cuenta la comunidad.&lt;br&gt;
Por eso ¿Qué está pasando últimamente? Que alguien “descubre” el SSR (Server Side Rendering)&lt;br&gt;
Y empiezan a aparecer frameworks sobre los frameworks para hacer lo que se hacía desde siempre, generar el contenido de la página desde en el servidor y que el navegador haga la petición y le envíe dicho contenido, eso sí, ahora usando toooooda la lógica del framework sobre otro framework. Volvemos a los inicios, pero complicándolo. &lt;br&gt;
¿Por qué? Quizás porque lo no sabemos hacer de otra manera. Es lo que nos han enseñado.&lt;/p&gt;

&lt;p&gt;Nos enseñan a usar algunas herramientas, pero &lt;strong&gt;no nos enseñan a pensar cuándo se deben usar dichas herramientas&lt;/strong&gt;.&lt;br&gt;
Como se suele decir: “Te enseñan a usar un martillo y todo son clavos”&lt;br&gt;
¿Te enseñan el framework AcojoJS? Todo son aplicaciones con AcojoJS. Sin pararnos a pensar si es la solución idónea para nuestro problema. Funciona, ¿no?&lt;/p&gt;

&lt;p&gt;Quizás porque no nos enseñan más.&lt;br&gt;
Quizás porque no nos ponemos a pensar.&lt;br&gt;
Quizás porque va todo tan deprisa que nos falta tiempo para aprender.&lt;/p&gt;

&lt;p&gt;Porque aprendemos a usar un martillo, es decir a programar, y ¡ale! a clavar todo lo que pille, aunque sea un tornillo o un cristal.&lt;/p&gt;

&lt;p&gt;Y es cierto. Aprendes lo suficiente para usar ese martillo con suficiente destreza. Pero nada más.&lt;br&gt;
Aunque seamos conscientes de que la caja de herramientas es gigante y la cantidad de herramientas casi infinita, nos quedamos con nuestro martillo.&lt;/p&gt;

&lt;p&gt;Pero sobre todo, creo que no se fomenta el buscar soluciones adecuadas a los problemas, si no a usar nuestra solución a cualquier problema.&lt;br&gt;
Es decir, &lt;strong&gt;adaptamos problemas a nuestras soluciones&lt;/strong&gt;, complicando más el problema.&lt;/p&gt;

&lt;p&gt;Esto me pasó en uno de mis equipos, cuando nos plantearon un proyecto en el que teníamos vía libre para utilizar lo que quisiéramos. Greenfield Project lo llaman.&lt;br&gt;
Pregunté:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;¿Qué usamos? 
Todos al unísono: &lt;/li&gt;
&lt;li&gt;Vue! Vue! Vue!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Mi pregunta era para implicar al equipo en el análisis del problema y buscar la solución adecuada, que facilitara el trabajo y la entrega a tiempo.&lt;br&gt;
Pero mi sorpresa fue mayúscula cuando con un mínimo de información sobre el proyecto, todos pedían a Barrabás, en este caso Vuerrabás :P&lt;br&gt;
Menos mal que en este caso no hice como Poncio Pilato, aunque si me lleve un Soponcio Parrato :P&lt;/p&gt;

&lt;p&gt;Este es solo un claro ejemplo de a lo que nos conduce el mundo del desarrollo actual, del que me siento parte y responsable.&lt;/p&gt;

&lt;h1&gt;
  
  
  WebComponents
&lt;/h1&gt;

&lt;p&gt;Y ya metidos en faena, quiero también reivindicar a los denostados, en algunos círculos, web-components estándar, incluidos en muchos frameworks, pero sin pertenecer a ninguno.&lt;/p&gt;

&lt;p&gt;Y sobre todo quiero plantear mi disconformidad con el uso que se hace de ellos con el “Atomic Design”, es decir, crear componentes atómicos, que pueden usarse solos o como parte de un componente de orden superior, conocidos como “moléculas”. Y que estos últimos a la vez puedan conformar “organismos” de componentes…&lt;/p&gt;

&lt;p&gt;No se. Me chirría. Siempre he visto los web-components como etiquetas HTML, como un &amp;lt;UL&amp;gt; o un &amp;lt;TABLE&amp;gt; o &amp;lt;DIV&amp;gt; solo que “haga más cosas”. Igual que crearon el tag &amp;lt;VIDEO&amp;gt;, que es realmente el concepto de un web-component aplicado: permite insertar vídeo en la web de manera sencilla, con su controlador del vídeo, la pantalla de vídeo, admitiendo diferentes formatos y fuentes…&lt;/p&gt;

&lt;p&gt;Y veo bien web-components que aporten “cosas” que no hay. Un lector de QR. Un campo de formulario para votar con estrellas. Un reloj digital. Un calendario. Un menú. Hay mil ejemplos de necesidades.&lt;/p&gt;

&lt;p&gt;¿Pero es un componente un ente formado por un &amp;lt;h1&amp;gt;, un &amp;lt;h2&amp;gt; y un &amp;lt;IMG&amp;gt; donde además ninguno de los 3 elementos tiene que aparecer siempre, pudiendo incluso llegar a ser solamente uno de ellos…?&lt;/p&gt;

&lt;p&gt;El argumento suele ser “es que se repite”, “es que así es flexible”, “es que si no ¿cómo lo hacemos?”&lt;/p&gt;

&lt;p&gt;Pues puede ser un componente web, cierto. Pero también puede no serlo. Si usas un framework quizás no te quede más remedio. O si no te han enseñado a cómo hacerlo sin que lo sea.&lt;/p&gt;

&lt;p&gt;Bajo mi punto de vista, si usas web-components y estás generando páginas estáticas, aunque se alimente el contenido de una base de datos, al fin y al cabo, ese ente de &amp;lt;h1&amp;gt;&amp;lt;h2&amp;gt;&amp;lt;img&amp;gt; es simplemente una plantilla HTML.&lt;/p&gt;

&lt;p&gt;Y puedo tener plantillas con combinaciones de esos 3 elementos, si realmente se llaman a todas las combinaciones de los mismos, porque si no, emplear tiempo en tenerlo “por si acaso” es tontería. Ese es otro de los grandes problemas del mundo del desarrollo que da para otro post.&lt;/p&gt;

&lt;p&gt;Volviendo al problema planteado. Creo que siempre y cuando sean una simple presentación de tags HTML agrupados, sin ninguna funcionalidad, es una simple plantilla.&lt;br&gt;
Si tuviera funcionalidad, entonces sí podría tener sentido que fuera un web-component. O si tuviera un diseño especial, que pueda chocar con el diseño global y necesite encapsular dicho diseño, también podría ser un web-component.&lt;/p&gt;

&lt;p&gt;Es decir, creo que un web-component, la razón de crearlo es cuando:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Se puede reutilizar.&lt;/li&gt;
&lt;li&gt;Tiene una presentación que no existe ya en un tag HTML&lt;/li&gt;
&lt;li&gt;Tiene una funcionalidad que le da entidad y sentido.&lt;/li&gt;
&lt;li&gt;Tiene una parte de su presentación/diseño abstraído del entorno donde se use.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Si no cumple alguno de esos puntos, debo analizar si realmente necesito diseñar un web-component o tengo alguna alternativa.&lt;/p&gt;

&lt;p&gt;Y siguiendo esta premisa, por lo tanto para mi no tiene sentido un web-component no visual, que solo aporte funcionalidad, como a veces he visto los llamados “data managers”.&lt;/p&gt;

&lt;p&gt;Para mi eso es un tag HTML que ya existe. Se llama &amp;lt;script&amp;gt;. Creo una “librería” con la funcionalidad que necesito. El API que he convenido. Y todo el que lo necesite lo usa. No veo la necesidad de hacerlo mediante un web-component.&lt;/p&gt;

&lt;h1&gt;
  
  
  Comunicación entre web-components.
&lt;/h1&gt;

&lt;p&gt;Otra "unpopular opinion". Siempre se dice, yo de hecho lo he preguntado en alguna entrevista, ¿Cómo se comunican los componentes? Y quien se lo sabe, repite el mantra: “De padres a hijos mediante propiedades, de hijos a padres mediante eventos”&lt;/p&gt;

&lt;p&gt;Bueno, desde el “Atomic Design” quizás ese mantra sí tiene sentido.&lt;br&gt;
Pero si concibes los web-components cómo “tags” autónomos, que pueden convivir y estar anidados dentro de otros, pero independientes, la comunicación debería ser siempre mediante eventos. O mediante prospección.&lt;/p&gt;

&lt;p&gt;O sea, aunque puede haber dependencias entre web-components, como la hay en un &amp;lt;table&amp;gt; con un &amp;lt;tr&amp;gt; y este con un &amp;lt;td&amp;gt; o un &amp;lt;ul&amp;gt; con un &amp;lt;li&amp;gt;. Pero realmente puedes usarlos por separado, aunque su funcionamiento no sea el esperado o no sea correcto.&lt;/p&gt;

&lt;p&gt;Soy más partidario de un &lt;strong&gt;“Phenotypic Design”&lt;/strong&gt; para los web-components. Es decir, diseñar los web-components basándonos en el conjunto de características visibles como resultado de la interacción entre su tipo y el medio.&lt;/p&gt;

&lt;p&gt;Los tags HTML están clasificados por su tipo: Fundación, Formato, Formulario, Marco, Imagen, Audio, Enlace, Lista, Tabla, Estilo, Meta información y Programa.&lt;br&gt;
¿Por qué no seguir esta clasificación y ampliarla para los web-components si es necesario? &lt;/p&gt;

&lt;p&gt;Usando el concepto de “parientes” he visto siempre que ineludiblemente terminamos acoplando componentes padres, madres, hijos, sobrinas, abuelas y tíos todos entre sí, como buena familia. Pero ese no es el fin de los web-components, ya que solemos perder re-utilización fuera de la “familia”, creando verdaderas “mafias”.&lt;/p&gt;

&lt;p&gt;Un web-component, por estar anidado dentro de otro no tiene porque crear una relación padre-hijo. Para mi tienen que crear una relación simbiótica. Y las hay de muchos tipos. Pueden ser un alga-hongo, creando un web-component de más valor. Árbol-ardilla, donde uno usa al otro para darle “cobijo”. &lt;br&gt;
Creo que aporta una visión más amplia, menos limitante, donde es más fácil de mantener la individualidad, y por tanto la re-utilización de web-components en diferentes entornos, aplicaciones o webs.&lt;/p&gt;

&lt;h1&gt;
  
  
  Indexabilidad de los web-components
&lt;/h1&gt;

&lt;p&gt;Otro tema que me ha preocupado siempre es que la encapsulación que hace el shadow DOM en los web-components que hace que su contenido no sea indexable y por tanto desaparece al darle a “ver código fuente de la página”, siendo invisible para los crawlers.&lt;/p&gt;

&lt;p&gt;Pero esto creo que también es por un mal uso que le estamos dando a los web-components.&lt;/p&gt;

&lt;p&gt;Si tengo por ejemplo un web-component de un menú de navegación, que al final puede ser un tag &amp;lt;nav&amp;gt; al que le hemos dado una funcionalidad especial en base a unos requisitos, incluso diferente en diferentes resoluciones pantalla, y al que le hemos dado un diseño concreto.&lt;br&gt;
¿Por qué no utilizar el light-dom, es decir, el dom dentro del web-component, leer este en el ciclo de creación del mismo, y pintarlo conforme a los requisitos que necesitamos?&lt;br&gt;
Estaríamos dando el contenido al crawler y encapsulando maquetación, diseño y funcionalidad. ¡Voila!&lt;/p&gt;

&lt;p&gt;Porque otra aberración que veo bastante por ahí es pasar información a un web-component mediante un json ¡¡¡que insertamos como atributo!!! &lt;br&gt;
¿Por qué no generar esa información en el light-dom con HTML semántico, indexable y accesible y luego “darle forma” en el web-component?&lt;/p&gt;

&lt;p&gt;Es cierto que puede penalizar algo el tiempo de renderizado, pero no más si lo que tienes que leer es un json o una lista de elementos como atributo para pintarlos.&lt;br&gt;
Y ademaś existen técnicas para poner un “loader” o añadir una animación de fade-in después del primer renderizado.&lt;/p&gt;

&lt;p&gt;Por otro lado, si metemos el contenido del web-component en el light-dom, en el remoto caso de que no funcionara javascript, incluso podríamos asegurarnos de que la página tuviera contenido ya que el light-dom se renderiza, aunque probablemente se verá como “HTML feo” al no cargar el CSS de los componentes y no tener CSS para esos elementos HTML del light-dom.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://codepen.io/manufosela/pen/MWjrrEW" rel="noopener noreferrer"&gt;Ejemplo de componente nav-list&lt;/a&gt; &lt;br&gt;
En el repo de git se puede ver la evolución según versiones.&lt;/p&gt;

&lt;h1&gt;
  
  
  Mis conclusiones
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;No nos enseñan a buscar soluciones a los problemas, sino a usar las soluciones que conocemos ante cualquier problema.&lt;/li&gt;
&lt;li&gt;Crear un web-component cuando:

&lt;ul&gt;
&lt;li&gt;Se puede reutilizar.&lt;/li&gt;
&lt;li&gt;Tenga una presentación que no existe ya en un tag HTML&lt;/li&gt;
&lt;li&gt;Tenga una funcionalidad que le da entidad y sentido.&lt;/li&gt;
&lt;li&gt;Tenga necesidad de abstraer presentación/diseño del entorno donde se use.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Relación entre componentes simbiótica frente a la “familiar”&lt;/li&gt;

&lt;li&gt;Comunicación entre componentes mediante eventos.&lt;/li&gt;

&lt;li&gt;“Phenotypic Design” frente a “Atomic Design”&lt;/li&gt;

&lt;li&gt;Utilizar el light-dom cuando sea posible, para insertar contenido al web-component y hacerlo indexable&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Y si has leído hasta aquí ¡gracias! :)&lt;br&gt;
Nos vemos por la comunidad.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>webcomponents</category>
      <category>javascript</category>
      <category>html</category>
    </item>
    <item>
      <title>Javascript Proxy: algunos usos prácticos</title>
      <dc:creator>Mánu Fosela</dc:creator>
      <pubDate>Sun, 20 Sep 2020 01:10:05 +0000</pubDate>
      <link>https://dev.to/manufosela/javascript-proxy-algunos-usos-practicos-1hie</link>
      <guid>https://dev.to/manufosela/javascript-proxy-algunos-usos-practicos-1hie</guid>
      <description>&lt;p&gt;Este post está basado en una mezcla de la traducción de los post del &lt;a href="https://www.arbazsiddiqui.me/javascript-proxies-real-world-use-cases/" rel="noopener noreferrer"&gt;blog de Arbaz Siddiqui&lt;/a&gt;, y el &lt;a href="https://blog.logrocket.com/practical-use-cases-for-javascript-es6-proxies/" rel="noopener noreferrer"&gt;blog de Eslam Hefnawy&lt;/a&gt;, &lt;a href="https://javascript.info/proxy" rel="noopener noreferrer"&gt;javascrip.info&lt;/a&gt;&lt;br&gt;
y del post en español de &lt;a href="https://www.todojs.com/introduccion-a-proxy-de-es6/" rel="noopener noreferrer"&gt;TodoJS&lt;/a&gt; y por su puesto de la documentación oficial en &lt;a href="https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Proxy" rel="noopener noreferrer"&gt;MDN&lt;/a&gt; &lt;/p&gt;
&lt;h1&gt;
  
  
  Introducción a Proxy
&lt;/h1&gt;

&lt;p&gt;En términos de programación, proxy es cualquier entidad que actúa en nombre de alguna otra entidad. Un servidor proxy se encuentra entre un cliente y un servidor y actúa como cliente para el servidor y viceversa. El trabajo de cualquier proxy es interceptar las solicitudes / llamadas entrantes y reenviarlas en sentido ascendente. Esta intercepción permite que el proxy agregue lógica y cambie el comportamiento de las solicitudes entrantes y salientes.&lt;/p&gt;

&lt;p&gt;El proxy Javascript es algo muy similar, se encuentra entre su objeto real y el código que intenta acceder a este objeto.&lt;br&gt;
Nos permite hacer metaprogramación dinámica (metaprogramación: programas que escriben o manipulan otros programas).&lt;/p&gt;

&lt;p&gt;Va a permitirnos interceptar las operaciones con objetos y sus propiedades de tal forma que podemos redefinir el comportamiento para cada una de estas acciones&lt;/p&gt;

&lt;p&gt;De acuerdo con los documentos web de MDN:&lt;/p&gt;

&lt;p&gt;El objeto Proxy se usa para definir comportamientos personalizados para operaciones fundamentales (por ejemplo, búsqueda de propiedades, asignación, enumeración, invocación de funciones, etc.).&lt;/p&gt;
&lt;h1&gt;
  
  
  Terminologías
&lt;/h1&gt;

&lt;p&gt;Hay tres términos que necesitamos saber antes de poder implementar un proxy:&lt;/p&gt;
&lt;h3&gt;
  
  
  Objetivo (target)
&lt;/h3&gt;

&lt;p&gt;Target es el objeto real que nuestro proxy interceptará. Este puede ser cualquier objeto de JavaScript.&lt;/p&gt;
&lt;h3&gt;
  
  
  Manejador (handler)
&lt;/h3&gt;

&lt;p&gt;El manejador es un objeto donde viven todas las trampas. &lt;br&gt;
Cada elemento de este objeto tiene como valor una función que implementa una trampa.&lt;/p&gt;
&lt;h3&gt;
  
  
  Trampas (trap)
&lt;/h3&gt;

&lt;p&gt;Las trampas son métodos que interceptarán la llamada al destino cuando se llama a una propiedad o método. Hay muchas trampas definidas que se pueden implementar.&lt;br&gt;
Los métodos que se pueden usar como trampas son:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Object methods:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;getPrototypeOf()&lt;/li&gt;
&lt;li&gt;setPrototypeOf()&lt;/li&gt;
&lt;li&gt;isExtensible()&lt;/li&gt;
&lt;li&gt;preventExtensions()&lt;/li&gt;
&lt;li&gt;getOwnPropertyDescriptor()&lt;/li&gt;
&lt;li&gt;ownKeys()&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Property getters/setters:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;has()&lt;/li&gt;
&lt;li&gt;get()&lt;/li&gt;
&lt;li&gt;set()&lt;/li&gt;
&lt;li&gt;deleteProperty()&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Function methods:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;apply()&lt;/li&gt;
&lt;li&gt;construct()&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Ejemplo básico:
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;//movie is a target&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;movie&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Pulp Fiction&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;director&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Quentin Tarantino&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;//this is a handler&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;//get is a trap&lt;/span&gt;
    &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prop&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;director&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;God&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;

    &lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prop&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;actor&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;John Travolta&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;movieProxy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Proxy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;movie&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;movieProxy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;director&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;//God&lt;/span&gt;

&lt;span class="nx"&gt;movieProxy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;actor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Tim Roth&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;movieProxy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;actress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Uma Thurman&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;movieProxy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;actor&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;//John Travolta&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;movieProxy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;actress&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;//Uma Thurman&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;El resultado de la ejecución del código anterior será:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;God
John Travolta
Uma Thurman
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En este ejemplo, nuestro objeto target era movie, implementamos un manejador con dos trampas: un get y un set.&lt;br&gt;
Agregamos la lógica de que si estamos accediendo a la clave director, deberíamos devolver la cadena en God en lugar del valor real.&lt;br&gt;
Del mismo modo, agregamos una trampa en el método set que interceptará todas las escrituras en el objeto de destino y cambiará el valor a John Travolta si la clave es actor.&lt;/p&gt;

&lt;p&gt;Las posibilidades son infinitas&lt;/p&gt;
&lt;h1&gt;
  
  
  Casos de uso del mundo real
&lt;/h1&gt;

&lt;p&gt;Aunque no es tan conocido como otras características de ES2015, Proxy tiene muchos usos. &lt;br&gt;
Veremos escenarios del mundo real donde podemos usar proxies.&lt;/p&gt;
&lt;h2&gt;
  
  
  Validaciones
&lt;/h2&gt;

&lt;p&gt;Como podemos interceptar las escrituras en un objeto, podemos hacer una validación del valor que estamos tratando de establecer en el objeto.&lt;br&gt;&lt;br&gt;
Por ejemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;houses&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Stark&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Lannister&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prop&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;house&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;houses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`House &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; does not belong to allowed &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;houses&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;gotCharacter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Proxy&lt;/span&gt;&lt;span class="p"&gt;({},&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;gotCharacter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Jamie&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;gotCharacter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;house&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Lannister&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;gotCharacter&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;gotCharacter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Oberyn&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;gotCharacter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;house&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Martell&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La ejecución del código anterior dará como resultado lo siguiente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{ name: 'Jamie', house: 'Lannister' }
Error: House Martell does not belong to allowed Stark,Lannister
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En este ejemplo, restringimos que el valor permitido para la propiedad &lt;strong&gt;house&lt;/strong&gt; solo pueda ser una de las casas permitidas. Incluso podemos usar este enfoque para crear objetos de solo lectura, todo lo que necesitamos hacer es lanzarlo dentro de la trampa set.&lt;/p&gt;

&lt;h2&gt;
  
  
  Efectos secundarios
&lt;/h2&gt;

&lt;p&gt;Podemos usar proxies para crear efectos secundarios en una propiedad de lectura / escritura. La idea es activar alguna función si se accede o se escribe una propiedad en particular. &lt;/p&gt;

&lt;p&gt;Por ejemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sendEmail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sending email after task completion&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prop&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;status&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;complete&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;sendEmail&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Proxy&lt;/span&gt;&lt;span class="p"&gt;({},&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// ...otras tareas que al final llevan a poner un estado...&lt;/span&gt;
&lt;span class="nx"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;complete&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La ejecución del código anterior dará como resultado el siguiente resultado:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sending email after task completion
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aquí estamos interceptando la escritura de la propiedad 'status' y si status está completa, estamos ejecutando una función de efectos secundarios.&lt;/p&gt;

&lt;h2&gt;
  
  
  Almacenamiento en caché
&lt;/h2&gt;

&lt;p&gt;Como podemos interceptar el acceso a las propiedades del objeto, podemos construir en cachés de memoria para devolver solo valores de un objeto si no ha caducado. &lt;/p&gt;

&lt;p&gt;Por ejemplo :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cacheTarget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ttl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CREATED_AT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isExpired&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;CREATED_AT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ttl&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;isExpired&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Proxy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;cacheTarget&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La ejecución del código anterior dará como resultado el siguiente resultado:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;25
25 // a los 4 segundos
undefined // a los 6 segundos
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aquí hemos creado una función que devuelve un Proxy. El manejador de ese Proxy primero comprueba si el objeto ha caducado o no. Podemos ampliar esta funcionalidad para tener TTL basados ​​en cada clave.&lt;br&gt;
Otra aproximación puede ser usar ese TTL para pedir a una API (fetch) los datos una vez caducado.&lt;/p&gt;
&lt;h2&gt;
  
  
  Observar cambios en objetos
&lt;/h2&gt;

&lt;p&gt;Como podemos interceptar el acceso a las propiedades del objeto, podemos crear nuevos elementos en DOM y renderizarlos cuando detectamos que una propiedad cambia o si se añade una nueva.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// NOTA IMPORTANTE!! &lt;/span&gt;
&lt;span class="c1"&gt;// En el DOM tenemos un div con id=“salida”&lt;/span&gt;
&lt;span class="c1"&gt;//&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;salida&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;salida&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;salida&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;innerText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;observables&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;handlerObservables&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;observable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;Reflect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;observable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nf"&gt;deleteProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;observable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;elem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;elem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parentNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;elem&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nb"&gt;Reflect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deleteProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;observable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;observables&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Proxy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handlerObservables&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;observables&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;prueba&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;valor&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// observables['otro'] = 'otro valor';&lt;/span&gt;
&lt;span class="c1"&gt;// delete observables['prueba'];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Si añadimos al objeto observables nuevos elementos, estos se irán añadiendo en el DOM dentro de la capa con id salida.&lt;br&gt;
Si eliminamos del objeto elementos, estos se irán eliminando también del DOM.&lt;/p&gt;
&lt;h2&gt;
  
  
  Data binding
&lt;/h2&gt;

&lt;p&gt;El enlace de datos suele ser difícil de lograr debido a su complejidad. El uso de proxies para lograr un enlace de datos bidireccional se puede ver en algunas “librerías” MVC en JavaScript, donde un objeto se modifica cuando el DOM sufre un cambio.&lt;/p&gt;

&lt;p&gt;En pocas palabras, el binding de datos es una técnica que une varias fuentes de datos para sincronizarlas.&lt;/p&gt;

&lt;p&gt;Supongamos que hay un con el id de username.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type = &lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;id = &lt;/span&gt;&lt;span class="s"&gt;"username"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;    
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Digamos que se desea mantener el valor de esta entrada sincronizado con una propiedad de un objeto.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;inputState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  &lt;span class="na"&gt;id&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;nombre de usuario&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;valor&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Es bastante fácil modificar el valor de inputState cuando el valor del input cambia escuchando el evento ‘change’ del input y luego actualizando el valor de inputState. Sin embargo, lo contrario, actualizar el input cuando el valor de inputState se modifica, es más complicado a priori.&lt;/p&gt;

&lt;p&gt;Un Proxy puede ayudar a lograrlo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#username&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;username&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nb"&gt;Reflect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`#&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;proxy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Proxy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;inputState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;proxy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;John Doe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;proxy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="c1"&gt;// 'John Doe' will be printed for both&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;De esta manera, cuando haya cambio en inputState, el input reflejará el cambio que se ha realizado.&lt;br&gt;
Combinado con escuchar el evento ‘change’, esto producirá doble data binding simple de input e inputState.&lt;/p&gt;

&lt;p&gt;Si bien este es un caso de uso válido, generalmente no se recomienda por performance.&lt;/p&gt;
&lt;h2&gt;
  
  
  Convertir un array de objetos en agrupable
&lt;/h2&gt;

&lt;p&gt;Este quizás sea el ejemplo más complejo, donde se anidan dos Proxy para poder agrupar por el campo que indiquemos.&lt;/p&gt;

&lt;p&gt;Partimos del siguiente json con datos sobre características de procesadores:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;procesadores&lt;/span&gt;&lt;span class="mi"&gt;2020&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"procesador"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Athlon 200GE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"nucleos"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"hilos"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"frecuencia-min"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"3.2GHz"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"frecuencia-max"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"3.2GHz"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"precio"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"66.18 €"&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"procesador"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Core i3-9100F"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"nucleos"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"hilos"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"frecuencia-min"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"3.6 Ghz"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"frecuencia-max"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"4.2 Ghz"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"precio"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"67.99 €"&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"procesador"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ryzen 3 3100"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"nucleos"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"hilos"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"8"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"frecuencia-min"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"3.6 Ghz"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"frecuencia-max"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"3.9 Ghz"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"precio"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"105.58 €"&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"procesador"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ryzen 5 2600X"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"nucleos"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"6"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"hilos"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"12"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"frecuencia-min"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"3.6 Ghz"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"frecuencia-max"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"4.2 Ghz"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"precio"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"136.35 €"&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"procesador"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Core i5-10400F"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"nucleos"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"6"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"hilos"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"12"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"frecuencia-min"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2.9 Ghz"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"frecuencia-max"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"4.3 Ghz"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"precio"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"149.89 €"&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"procesador"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ryzen 5 3600"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"nucleos"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"6"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"hilos"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"12"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"frecuencia-min"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"3.6 Ghz"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"frecuencia-max"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"4.2 Ghz"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"precio"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"200.80 €"&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"procesador"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ryzen 7 2700X"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"nucleos"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"8"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"hilos"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"16"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"frecuencia-min"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"3.7 Ghz"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"frecuencia-max"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"4.3 Ghz"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"precio"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"207.59 €"&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"procesador"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Core i7-10700K"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"nucleos"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"8"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"hilos"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"16"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"frecuencia-min"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"3.8 Ghz"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"frecuencia-max"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"5.1 Ghz"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"precio"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"384.90 €"&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"procesador"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ryzen 7 3700X"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"nucleos"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"8"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"hilos"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"16"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"frecuencia-min"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"3.6 Ghz"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"frecuencia-max"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"4.4 Ghz"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"precio"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"309.95 €"&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"procesador"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Core i9-10850K"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"nucleos"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"10"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"hilos"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"20"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"frecuencia-min"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"3.6 Ghz"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"frecuencia-max"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"5.2 Ghz"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"precio"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"486.00 €"&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"procesador"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ryzen 9 3900X"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"nucleos"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"12"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"hilos"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"24"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"frecuencia-min"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"3.8 Ghz"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"frecuencia-max"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"4.6 Ghz"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"precio"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"443.90 €"&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"procesador"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ryzen 9 3950X"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"nucleos"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"16"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"hilos"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"32"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"frecuencia-min"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"3.5 Ghz"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"frecuencia-max"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"4.7 Ghz"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"precio"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"758.87 €"&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"procesador"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ryzen Threadripper 3970X"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"nucleos"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"32"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"hilos"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"64"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"frecuencia-min"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"3.7 Ghz"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"frecuencia-max"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"4.5 Ghz"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"precio"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2099.00 €"&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Si queremos poder agrupar por los campos de los objetos del array este sería el código.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;groupable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="c1"&gt;// Comprueba que la colección sea un array&lt;/span&gt;
 &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;collection&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TypeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;The input collection is not an Array&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;

 &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;grouped&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
 &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;defineProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;groupBy&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="na"&gt;configurable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="na"&gt;enumerable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="na"&gt;writable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
 &lt;span class="p"&gt;});&lt;/span&gt;

 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Proxy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;property&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;groupBy&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Proxy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="c1"&gt;// si la propiedad a agrupar no existe devolver []&lt;/span&gt;
           &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;hasOwnProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
             &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;no encontrado&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
             &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
           &lt;span class="p"&gt;}&lt;/span&gt;
           &lt;span class="c1"&gt;// caso contrario, agrupar por la propiedad&lt;/span&gt;
           &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
           &lt;span class="nx"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;groupBy&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
           &lt;span class="nx"&gt;grouped&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
           &lt;span class="nx"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
             &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;]]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
               &lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
             &lt;span class="p"&gt;}&lt;/span&gt;
             &lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;]].&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
             &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
           &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
           &lt;span class="nx"&gt;grouped&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
           &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;grouped&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
         &lt;span class="p"&gt;}&lt;/span&gt;
       &lt;span class="p"&gt;});&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;
     &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Reflect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;datasource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;groupable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;procesadores2020&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;datasource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;groupBy&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hilos&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;datasource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;groupBy&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;frecuencia-max&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cuando declaramos el array como “groupable” llamando a la función con el mismo nombre y pasandole el array, lo primero que hace es crear una nueva propiedad llamada “groupBy”, convirtiendo el array y devuelve un Proxy que intercepta el get del array.&lt;br&gt;
Podemos decir que hemos ampliado los métodos del array.&lt;/p&gt;

&lt;p&gt;De esta manera si llamamos a cualquier propiedad 0, 1, 2… devolverá el objeto correspondiente a esa posición. &lt;br&gt;
Si llamamos a groupBy nos devuelve otro Proxy que tiene otra trampa en get de manera que a partir del campo que recibe, recorre el array y los agrupa por el campo pasado  y devuelve el array agrupado.&lt;/p&gt;

&lt;p&gt;Esta manera es la manera de añadir funcionalidad a objetos de javascript sin tener que tocar su 'prototipo'.&lt;/p&gt;

&lt;p&gt;Por ejemplo, en String tenemos el método toLowercase() y toUppercase() pero no tenemos el método capitalize(). Si queremos añadir a String el método capitalize podemos hacerlo modificando la cadena protypica del tipo primitivo string:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;capitalize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
     &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; 
     &lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;toUpperCase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; 
     &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;buenos días&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;capitalize&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// Buenos días&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;De esta manera, todos los String que se creen a partir de esa declaración tendrán un nuevo método 'capitalize' que convierte la primera letra en mayúscula.&lt;/p&gt;

&lt;p&gt;Si esto lo hacemos mediante Proxy, al no ser String un objeto sino un tipo primitivo, tenemos que convertir el String en Object, con lo que perdemos los métodos de String:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;addCapitalize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;arrStr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="nx"&gt;arrStr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;capitalize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;arrStr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;arrStr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;toUpperCase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;arrStr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Proxy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arrStr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arrStr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;property&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;capitalize&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;saludo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;addCapitalize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;buenos días&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;saludo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;capitalize&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;saludo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toUpperCase&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// ERROR: perdemos el resto de métodos de String...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Con lo que está no parece ser la manera de ampliar métodos en tipos primitivos.&lt;/p&gt;

&lt;h3&gt;
  
  
  Inconvenientes de los Proxies
&lt;/h3&gt;

&lt;p&gt;Si bien los proxies son bastante “mágicos”, hay algunos inconvenientes con ellos por que debemos tener cuidado.&lt;/p&gt;

&lt;p&gt;El rendimiento puede tener un impacto drástico cuando se usan muchos proxies y, por lo tanto, debe evitarse al escribir un código donde el rendimiento sea crítico.&lt;br&gt;
Dado un objeto, no hay forma de saber si se trata de un objeto Proxy u objetivo.&lt;br&gt;
Por último, los servidores Proxy no necesariamente conducen a un código muy limpio y fácil de entender.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusión
&lt;/h2&gt;

&lt;p&gt;Los proxies son increíblemente poderosos y se pueden usar y abusar para una amplia gama de cosas.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>es6</category>
      <category>frontend</category>
    </item>
  </channel>
</rss>
