diff options
Diffstat (limited to 'files/es/web/javascript/referencia/objetos_globales/proxy/index.html')
-rw-r--r-- | files/es/web/javascript/referencia/objetos_globales/proxy/index.html | 439 |
1 files changed, 0 insertions, 439 deletions
diff --git a/files/es/web/javascript/referencia/objetos_globales/proxy/index.html b/files/es/web/javascript/referencia/objetos_globales/proxy/index.html deleted file mode 100644 index 1469b1f138..0000000000 --- a/files/es/web/javascript/referencia/objetos_globales/proxy/index.html +++ /dev/null @@ -1,439 +0,0 @@ ---- -title: Proxy -slug: Web/JavaScript/Referencia/Objetos_globales/Proxy -translation_of: Web/JavaScript/Reference/Global_Objects/Proxy ---- -<div> -<div>{{JSRef}}</div> -</div> - -<p>El objeto <strong>Proxy</strong> se usa para definir un comportamiento personalizado para operaciones fundamentales (por ejemplo, para observar propiedades, cuando se asignan, enumeración, invocación de funciones, etc).</p> - -<h2 id="Terminología">Terminología</h2> - -<dl> - <dt><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/handler">handler</a></dt> - <dd>Objeto que gestiona las intercepciones a las propiedades del objeto proxy.</dd> - <dt>traps</dt> - <dd>Son los métodos interceptores que proveen acceso a las propiedades. Es análogo al concepto de <em>traps</em> en los sistemas operativos.</dd> - <dt>target</dt> - <dd>El objeto que virtualiza este objeto. Suele usarse como <em>backend</em> de almacenamiento del proxy. Invariantes (semántica que no acepta cambios) respecto a la no extensibilidad del objeto o propiedades no configurables se verifican contra este <em>target</em>.</dd> -</dl> - -<h2 id="Sintaxis">Sintaxis</h2> - -<pre class="syntaxbox notranslate">var p = new Proxy(target, handler); -</pre> - -<h3 id="Parámetros">Parámetros</h3> - -<dl> - <dt><code>target</code></dt> - <dd>Un objeto <em>target </em>(puede ser cualquier órden de objetos, incluyendo un array nativa, funcion o incluso otro proxy) o función que contenga el <code>Proxy</code></dd> - <dt><code>handler</code></dt> - <dd>Un objeto cuyas propiedades son funciones que definen el comportamiento del proxy cuando una operación es realizada en él.</dd> -</dl> - -<h2 id="Métodos">Métodos</h2> - -<dl> - <dt>{{jsxref("Proxy.revocable()")}}</dt> - <dd>Crea un objeto <code>Proxy</code> revocable</dd> -</dl> - -<h2 id="Métodos_del_objeto_handler">Métodos del objeto handler</h2> - -<p>The handler object is a placeholder object which contains traps for <code>Proxy</code>.</p> - -<div>{{page('/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/handler', 'Methods') }}</div> - -<h2 id="Ejemplos">Ejemplos</h2> - -<h3 id="Ejemplo_básico">Ejemplo básico</h3> - -<p>En este simple ejemplo el número <code>37</code> se devuelve como valor predeterminado cuando la propiedad <code>name</code> no se encuentra en el objeto. Se utilizando el manejador <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/handler/get">get</a></code>.</p> - -<pre class="brush: js notranslate">var handler = { - get: function(target, name){ - return name in target? - target[name] : - 37; - } -}; - -var p = new Proxy({}, handler); -p.a = 1; -p.b = undefined; - -console.log(p.a, p.b); // 1, undefined -console.log('c' in p, p.c); // false, 37 -</pre> - -<h3 id="No-op_forwarding_proxy">No-op forwarding proxy</h3> - -<p>In this example, we are using a native JavaScript object to which our proxy will forward all operations that are applied to it.</p> - -<pre class="brush: js notranslate">var target = {}; -var p = new Proxy(target, {}); - -p.a = 37; // operation forwarded to the target - -console.log(target.a); // 37. The operation has been properly forwarded -</pre> - -<h3 id="Validación">Validación</h3> - -<p>Con un <code>Proxy</code>, puedes validar fácilmente el valor puesto a un objeto. Este ejemplo usa el handler (manejador) <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/handler/set"><code>set</code></a>.</p> - -<pre class="brush: js notranslate">let validator = { - set: function(obj, prop, value) { - if (prop === 'age') { - if (!Number.isInteger(value)) { - throw new TypeError('The age is not an integer'); - } - if (value > 200) { - throw new RangeError('The age seems invalid'); - } - } - - // The default behavior to store the value - obj[prop] = value; - } -}; - -let person = new Proxy({}, validator); - -person.age = 100; -console.log(person.age); // 100 -person.age = 'young'; // Throws an exception -person.age = 300; // Throws an exception -</pre> - -<h3 id="Extending_constructor">Extending constructor</h3> - -<p>A function proxy could easily extend a constructor with a new constructor. This example uses the <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/handler/construct"><code>construct</code></a> and <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/handler/apply"><code>apply</code></a> handlers.</p> - -<pre class="brush: js notranslate">function extend(sup,base) { - var descriptor = Object.getOwnPropertyDescriptor( - base.prototype,"constructor" - ); - base.prototype = Object.create(sup.prototype); - var handler = { - construct: function(target, args) { - var obj = Object.create(base.prototype); - this.apply(target,obj,args); - return obj; - }, - apply: function(target, that, args) { - sup.apply(that,args); - base.apply(that,args); - } - }; - var proxy = new Proxy(base,handler); - descriptor.value = proxy; - Object.defineProperty(base.prototype, "constructor", descriptor); - return proxy; -} - -var Person = function(name){ - this.name = name; -}; - -var Boy = extend(Person, function(name, age) { - this.age = age; -}); - -Boy.prototype.sex = "M"; - -var Peter = new Boy("Peter", 13); -console.log(Peter.sex); // "M" -console.log(Peter.name); // "Peter" -console.log(Peter.age); // 13</pre> - -<h3 id="Manipular_nodos_del_DOM">Manipular nodos del DOM</h3> - -<p>A veces queremos cambiar el atributo clase de dos elementos diferentes. Aquí se muestra cómo usando el handler (manejador) <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/handler/set"><code>set</code></a>.</p> - -<pre class="brush: js notranslate">let view = new Proxy({ - selected: null -}, -{ - set: function(obj, prop, newval) { - let oldval = obj[prop]; - - if (prop === 'selected') { - if (oldval) { - oldval.setAttribute('aria-selected', 'false'); - } - if (newval) { - newval.setAttribute('aria-selected', 'true'); - } - } - - // The default behavior to store the value - obj[prop] = newval; - } -}); - -let i1 = view.selected = document.getElementById('item-1'); -console.log(i1.getAttribute('aria-selected')); // 'true' - -let i2 = view.selected = document.getElementById('item-2'); -console.log(i1.getAttribute('aria-selected')); // 'false' -console.log(i2.getAttribute('aria-selected')); // 'true' -</pre> - -<h3 id="Value_correction_and_an_extra_property">Value correction and an extra property</h3> - -<p>The <code>products</code> proxy object evaluates the passed value and convert it to an array if needed. The object also supports an extra property called <code>latestBrowser</code> both as a getter and a setter.</p> - -<pre class="brush: js notranslate">let products = new Proxy({ - browsers: ['Internet Explorer', 'Netscape'] -}, -{ - get: function(obj, prop) { - // An extra property - if (prop === 'latestBrowser') { - return obj.browsers[obj.browsers.length - 1]; - } - - // The default behavior to return the value - return obj[prop]; - }, - set: function(obj, prop, value) { - // An extra property - if (prop === 'latestBrowser') { - obj.browsers.push(value); - return; - } - - // Convert the value if it is not an array - if (typeof value === 'string') { - value = [value]; - } - - // The default behavior to store the value - obj[prop] = value; - } -}); - -console.log(products.browsers); // ['Internet Explorer', 'Netscape'] -products.browsers = 'Firefox'; // pass a string (by mistake) -console.log(products.browsers); // ['Firefox'] <- no problem, the value is an array - -products.latestBrowser = 'Chrome'; -console.log(products.browsers); // ['Firefox', 'Chrome'] -console.log(products.latestBrowser); // 'Chrome' -</pre> - -<h3 id="Finding_an_array_item_object_by_its_property">Finding an array item object by its property</h3> - -<p>This proxy extends an array with some utility features. As you see, you can flexibly "define" properties without using <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperties"><code>Object.defineProperties</code></a>. This example can be adapted to find a table row by its cell. In that case, the target will be <a href="/en-US/docs/DOM/table.rows"><code>table.rows</code></a>.</p> - -<pre class="brush: js notranslate">let products = new Proxy([ - { name: 'Firefox', type: 'browser' }, - { name: 'SeaMonkey', type: 'browser' }, - { name: 'Thunderbird', type: 'mailer' } -], -{ - get: function(obj, prop) { - // The default behavior to return the value; prop is usually an integer - if (prop in obj) { - return obj[prop]; - } - - // Get the number of products; an alias of products.length - if (prop === 'number') { - return obj.length; - } - - let result, types = {}; - - for (let product of obj) { - if (product.name === prop) { - result = product; - } - if (types[product.type]) { - types[product.type].push(product); - } else { - types[product.type] = [product]; - } - } - - // Get a product by name - if (result) { - return result; - } - - // Get products by type - if (prop in types) { - return types[prop]; - } - - // Get product types - if (prop === 'types') { - return Object.keys(types); - } - - return undefined; - } -}); - -console.log(products[0]); // { name: 'Firefox', type: 'browser' } -console.log(products['Firefox']); // { name: 'Firefox', type: 'browser' } -console.log(products['Chrome']); // undefined -console.log(products.browser); // [{ name: 'Firefox', type: 'browser' }, { name: 'SeaMonkey', type: 'browser' }] -console.log(products.types); // ['browser', 'mailer'] -console.log(products.number); // 3 -</pre> - -<h3 id="A_complete_traps_list_example">A complete <code>traps</code> list example</h3> - -<p>Now in order to create a complete sample <code>traps</code> list, for didactic purposes, we will try to proxify a <em>non native</em> object that is particularly suited to this type of operation: the <code>docCookies</code> global object created by <a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie/Simple_document.cookie_framework" title="https://developer.mozilla.org/en-US/docs/DOM/document.cookie#A_little_framework.3A_a_complete_cookies_reader.2Fwriter_with_full_unicode_support">the "little framework" published on the <code>document.cookie</code> page</a>.</p> - -<pre class="brush: js notranslate">/* - var docCookies = ... get the "docCookies" object here: - https://developer.mozilla.org/en-US/docs/DOM/document.cookie#A_little_framework.3A_a_complete_cookies_reader.2Fwriter_with_full_unicode_support -*/ - -var docCookies = new Proxy(docCookies, { - get: function (oTarget, sKey) { - return oTarget[sKey] || oTarget.getItem(sKey) || undefined; - }, - set: function (oTarget, sKey, vValue) { - if (sKey in oTarget) { return false; } - return oTarget.setItem(sKey, vValue); - }, - deleteProperty: function (oTarget, sKey) { - if (sKey in oTarget) { return false; } - return oTarget.removeItem(sKey); - }, - enumerate: function (oTarget, sKey) { - return oTarget.keys(); - }, - ownKeys: function (oTarget, sKey) { - return oTarget.keys(); - }, - has: function (oTarget, sKey) { - return sKey in oTarget || oTarget.hasItem(sKey); - }, - defineProperty: function (oTarget, sKey, oDesc) { - if (oDesc && "value" in oDesc) { oTarget.setItem(sKey, oDesc.value); } - return oTarget; - }, - getOwnPropertyDescriptor: function (oTarget, sKey) { - var vValue = oTarget.getItem(sKey); - return vValue ? { - value: vValue, - writable: true, - enumerable: true, - configurable: false - } : undefined; - }, -}); - -/* Cookies test */ - -console.log(docCookies.my_cookie1 = "First value"); -console.log(docCookies.getItem("my_cookie1")); - -docCookies.setItem("my_cookie1", "Changed value"); -console.log(docCookies.my_cookie1);</pre> - -<h2 id="Specifications">Specifications</h2> - -<table class="standard-table"> - <tbody> - <tr> - <th scope="col">Specification</th> - <th scope="col">Status</th> - <th scope="col">Comment</th> - </tr> - <tr> - <td>{{SpecName('ES2015', '#sec-proxy-objects', 'Proxy')}}</td> - <td>{{Spec2('ES2015')}}</td> - <td>Initial definition.</td> - </tr> - <tr> - <td>{{SpecName('ESDraft', '#sec-proxy-objects', 'Proxy')}}</td> - <td>{{Spec2('ESDraft')}}</td> - <td></td> - </tr> - </tbody> -</table> - -<h2 id="Browser_compatibility">Browser compatibility</h2> - -<p>{{CompatibilityTable}}</p> - -<div id="compat-desktop"> -<table class="compat-table"> - <tbody> - <tr> - <th>Feature</th> - <th>Chrome</th> - <th>Edge</th> - <th>Firefox (Gecko)</th> - <th>Internet Explorer</th> - <th>Opera</th> - <th>Safari</th> - </tr> - <tr> - <td>Basic support</td> - <td>{{CompatChrome(49.0)}}</td> - <td>13 (10586)</td> - <td>{{ CompatGeckoDesktop("18") }}</td> - <td>{{CompatNo}}</td> - <td>{{CompatUnknown}}</td> - <td>{{CompatUnknown}}</td> - </tr> - </tbody> -</table> -</div> - -<div id="compat-mobile"> -<table class="compat-table"> - <tbody> - <tr> - <th>Feature</th> - <th>Android</th> - <th>Chrome for Android</th> - <th>Firefox Mobile (Gecko)</th> - <th>IE Mobile</th> - <th>Opera Mobile</th> - <th>Safari Mobile</th> - </tr> - <tr> - <td>Basic support</td> - <td>{{CompatUnknown}}</td> - <td>{{CompatChrome(49.0)}}</td> - <td>{{ CompatGeckoDesktop("18") }}</td> - <td>13 (10586)</td> - <td>{{CompatUnknown}}</td> - <td>{{CompatUnknown}}</td> - </tr> - </tbody> -</table> -</div> - -<h2 id="Gecko_specific_notes">Gecko specific notes</h2> - -<ul> - <li>At present, <code>Object.getPrototypeOf(proxy)</code> unconditionally returns <code>Object.getPrototypeOf(target)</code>, because the ES6 getPrototypeOf trap is not yet implemented ({{bug(795904)}}, {{bug(888969)}}).</li> - <li><code>Array.isArray(proxy)</code> unconditionally returns <code>Array.isArray(target)</code> ({{bug(1096753)}}, {{bug(1111785)}}).</li> - <li><code>Object.prototype.toString.call(proxy)</code> unconditionally returns <code>Object.prototype.toString.call(target)</code>, because ES6 Symbol.toStringTag is not yet implemented ({{bug(1114580)}}).</li> -</ul> - -<h2 id="See_also">See also</h2> - -<ul> - <li><a class="external" href="https://www.youtube.com/watch?v=sClk6aB_CPk">"Proxies are awesome" Brendan Eich presentation at JSConf</a> (<a class="external" href="http://www.slideshare.net/BrendanEich/metaprog-5303821">slides</a>)</li> - <li><a class="external" href="http://wiki.ecmascript.org/doku.php?id=harmony:proxies">ECMAScript Harmony Proxy proposal page</a> and <a class="external" href="http://wiki.ecmascript.org/doku.php?id=harmony:proxies_semantics">ECMAScript Harmony proxy semantics page</a></li> - <li><a class="external" href="http://soft.vub.ac.be/~tvcutsem/proxies/">Tutorial on proxies</a></li> - <li><a href="/en-US/docs/JavaScript/Old_Proxy_API" title="/en-US/docs/JavaScript/Old_Proxy_API">SpiderMonkey specific Old Proxy API</a></li> - <li>{{jsxref("Object.watch()")}} is a non-standard feature but has been supported in Gecko for a long time.</li> -</ul> - -<h2 id="Licensing_note">Licensing note</h2> - -<p>Some content (text, examples) in this page has been copied or adapted from the <a class="external" href="http://wiki.ecmascript.org/doku.php">ECMAScript wiki</a> which content is licensed <a class="external" href="http://creativecommons.org/licenses/by-nc-sa/2.0/">CC 2.0 BY-NC-SA</a>.</p> |