Wednesday, June 15, 2011

Array.forEach imedemaa

Sattusin Twitteris nägema JavaScript: The Definitive Guide autori David flanagani postitust

And if your browser doesn’t have Array.forEach, use this mind-bender: Array.forEach = Function.prototype.call.bind(Array.prototype.forEach) link

Ilmnes et tegu on tõesti paraja mind-bender’iga, võttis tükk aega, enne kui suutsin selle rea dešifreerida. Milles siis asi?

Array.forEach = Function.prototype.call.bind(Array.prototype.forEach);

Antud rida lisab Array objekti uue meetodi forEach, mis käitub järgnevalt

Array.forEach(array, callback)

array on massiiv või massiivilaadne objekt (näiteks NodeList) ning callback on iteraator, mis saab ükshaaval parameetrina massivi elemendid.

Kuidas aga suudab rida Function.prototype.call.bind(Array.prototype.forEach) sellise asja tekitada?

Tuleb välja, et väga lihtsalt.

Esimene oluline osaline lauses on meetodi bind rakendamine. Antud meetod seob parameetrina saadud väärtuse endast vasakul oleva objekti (milleks hetkel on funktsioon call) kontektsimuutujaga this. Oluline on, et seda konteksti ei ole võimalik enam hiljem üle kirjutada!

Seega nüüd on meetodi call kontekstiks enam mitte Function.prototype vaid Array.prototype.forEach. Lihtsustatult võib seega sama lause kirjutada nii:

Array.forEach = Array.prototype.forEach.call

Tavaliselt peaks sellise tehte tulemusena kontekst jälle muutuma. Objekti Array uus meetod peaks selle lause järgi olema sama mis call kuid nüüd oleks kontekstiks juba Array

Array.forEach = Array.prototype.forEach.call ->  Array.__call__

Kuid see siiski pole nii, sest esimene bind juba sidus konteksti ära (selleks sai Array.prototype.forEach) ning see enam edasistes tehetes ei muutu.

Kokkuvõttes ongi tulemus selline, et järgmine lause

Array.forEach(array, callback)

On tegelikult täpselt sama, mis kirjutada

Array.prototype.forEach.call(array, callback)

Kuid ilmselgelt lühemas ja käepärasemas vormis.

  1. andrisreinman posted this