{"id":207,"date":"2009-02-18T16:05:46","date_gmt":"2009-02-18T15:05:46","guid":{"rendered":"http:\/\/www.hinnerup.net\/?p=207"},"modified":"2009-09-30T21:49:33","modified_gmt":"2009-09-30T20:49:33","slug":"self-modifying-javascript-code","status":"publish","type":"post","link":"https:\/\/www.hinnerup.net\/en\/permanent\/2009\/02\/18\/self-modifying-javascript-code\/","title":{"rendered":"Et par tricks med selvmodificerende JavaScript kode"},"content":{"rendered":"<p>JavaScript sproget er dynamisk, hvilket vil sige at mens ens script afvikles kan alt modificeres. Har man et objekt, er det muligt at tilf\u00f8je og fjerne <i>properties<\/i> p\u00e5 det. Sagt med andre ord er det muligt at modificere den kode der afvikles, b\u00e5de ved at tilf\u00f8je, fjerne og overskrive funktioner samt variable.<\/p>\n<div style=\"font-size:8pt;font-family:arial, sans-serif; padding-left:3em\"><b>Note:<\/b> I de efterf\u00f8lgende eksempler er der lagt v\u00e6gt p\u00e5 at illustrere den selvmodificerende kode, og ikke p\u00e5 at opstille gyldig HTML (doctype angivelser med videre er udeladt for overblikkets skyld), og tilsvarende anvendes blot &#8220;onload&#8221; istedet for en mere <a href=\"http:\/\/www.quirksmode.org\/js\/events_advanced.html\">korrekt cross browser metode<\/a>.<\/div>\n<p>De fleste kender til selvmodificerende javascript kode fra event handlers. N\u00e5r et DOM elements &#8220;onclick&#8221; s\u00e6ttes til at pege p\u00e5 en javascript funktion, udnyttes faktisk blot javascript sproget selvmodificerende egenskaber:<\/p>\n<pre>\r\n&lt;html&gt;\r\n&lt;body&gt;\r\n&lt;input type=\"button\" id=\"knap\" value=\"Tryk p\u00e5 mig\" \/&gt;\r\n&lt;script type=\"text\/javascript\"&gt;\r\nfunction haandterKnapKlik() {\r\n  alert(\"Hehe - det kilder!\");\r\n}\r\nvar knapObjekt = document.getElementById(\"knap\");\r\nknapObjekt.onclick = haandterKnapKlik;\r\n&lt;\/script&gt;\r\n&lt;\/body&gt;\r\n&lt;\/html&gt;<\/pre>\n<p><input type=\"button\" id=\"knap\" value=\"Tryk p\u00e5 mig\" \/><\/p>\n<p><script type=\"text\/javascript\">\nfunction haandterKnapKlik() {\n  alert(\"Hehe - det kilder!\");\n}\nvar knapObjekt = document.getElementById(\"knap\");\nknapObjekt.onclick = haandterKnapKlik;\n<\/script>I ovenst\u00e5ende simple eksempel s\u00e6ttes onclick eventhandler funktionen ved hj\u00e6lp af et inline script. Det samme resultat kan opn\u00e5es med dynamisk en tilf\u00f8jet funktion som her:<\/p>\n<pre>\r\n&lt;html&gt;\r\n&lt;body&gt;\r\n&lt;input type=\"button\" id=\"knap\" value=\"Tryk p\u00e5 mig\" \/&gt;\r\n&lt;script type=\"text\/javascript\"&gt;\r\nvar knapObjekt = document.getElementById(\"knap\");\r\nknapObjekt.onclick = function () {\r\n  alert(\"Hehe - det kilder osse!\");\r\n}\r\n&lt;\/script&gt;\r\n&lt;\/body&gt;\r\n&lt;\/html&gt;<\/pre>\n<p><input type=\"button\" id=\"knap2\" value=\"Tryk p\u00e5 mig\" \/><\/p>\n<p><script type=\"text\/javascript\">\nvar knapObjekt = document.getElementById(\"knap2\");\nknapObjekt.onclick = function () {\n  alert(\"Hehe - det kilder osse!\");\n};\n<\/script>Fordelen ved denne metode, er at global scopet ikke bliver &#8220;forurenet&#8221; med funktionsnavne og variable. Situationen kan nemt opst\u00e5 hvor der er sammenfald p\u00e5 navne af funktioner og variable, og det kan v\u00e6re ganske lumsk at debugge frem til hvor s\u00e5danne fejl er begravet, da det er helt legalt at overskrive en funktion til blot at v\u00e6re en simpel variabel (eller et objekt) og omvendt.<\/p>\n<p>N\u00e5r man skal sikre at kode kun k\u00f8res en gang, kan flere strategier anvendes. Typisk ser man implementationer svarende til:<\/p>\n<pre>\r\n&lt;html&gt;\r\n&lt;body onload=\"initialiser()\"&gt;\r\nvar initialiseret = false;\r\nfunction initialiser() {\r\n  if (initialiseret !== false) {\r\n    return;\r\n  }\r\n  \/\/ udf\u00f8r initialiseringen her ...\r\n  initialiseret = true;\r\n}\r\n&lt;\/body&gt;\r\n&lt;\/html&gt;<\/pre>\n<p>Der er flere problemer med ovenst\u00e5ende. Dels ligger funktionen &#8220;initialiser&#8221; og variablen &#8220;initialiseret&#8221; i global scopet og er dermed i fare for at blive overskrevet af andre inkluderede scripts p\u00e5 siden, og der er intet der forhindrer at variablen &#8220;initialiseret&#8221; senere s\u00e6ttes til false, hvorefter koden fint kan genafvikles.<\/p>\n<p>Istedet kan anvendes en anden strategi med selvmodificerende kode som angivet herunder:<\/p>\n<pre>\r\n&lt;html&gt;\r\n&lt;body onload=\"hinnerupnet.initialiser()\"&gt;\r\nvar hinnerupnet = {\r\n  initialiser: function () {\r\n    \/\/ udf\u00f8r initialiseringen her ...\r\n    delete this.initialiser;\r\n  },\r\n  variabelBar: \"Hejsa\",\r\n  metodeFoo: function () {\r\n    alert(this.variabelBar);\r\n  }\r\n};\r\n&lt;\/body&gt;\r\n&lt;\/html&gt;<\/pre>\n<p>Funktionen &#8220;initialiser&#8221; er her pakket ind i et objekt kaldet &#8220;hinnerupnet&#8221;. Kun selve objekt variablen &#8220;hinnerupnet&#8221; er placeret i global scope. B\u00e5de funktionen &#8220;initialiser&#8221;, &#8220;metodeFoo&#8221; og variablen &#8220;variabelBar&#8221; kan dermed kun tilg\u00e5es via objektet &#8220;hinnerupnet&#8221;. Chancerne for at andre scripts p\u00e5 siden skulle overskrive &#8220;hinnerupnet&#8221; objektet er minimale, og b\u00f8r v\u00e6re under programm\u00f8rens egen kontrol.<\/p>\n<p>Ved f\u00f8rste kald til &#8220;hinnerupnet.initialiser()&#8221; udf\u00f8res koden og der afsluttes med helt at slette funktionen fra objektet. Eventuelle efterf\u00f8lgende kald til funktionen leder til en exception:<\/p>\n<pre>\r\n&gt;&gt;&gt; hinnerupnet.initialiser is not a function<\/pre>\n<p>Et alternativ fremt for helt at slette en funktion er at modificere koden heri, for eksempel:<\/p>\n<pre>\r\n&lt;html&gt;\r\n&lt;body onload=\"hinnerupnet.initialiser()\"&gt;\r\nvar hinnerupnet = {\r\n  initialiser: function () {\r\n    \/\/ udf\u00f8r initialiseringen her ...\r\n    this.initialiser = function () {\r\n      alert(\"Fejl: 'hinnerupnet' objektet er allerede initialiseret!\");\r\n    };\r\n  }\r\n};\r\n&lt;\/body&gt;\r\n&lt;\/html&gt;<\/pre>\n<p>F\u00f8rste kald til &#8220;hinnerupnet.initialiser()&#8221; vil udf\u00f8re den tilt\u00e6nkte initialiseringskode, og slutteligt overskrive initialiseringsfunktionen s\u00e5ledes &#8220;hinnerupnet&#8221; objektet efterf\u00f8lgende er:<\/p>\n<pre>\r\nvar hinnerupnet = {\r\n  initialiser: function () {\r\n    alert(\"Fejl: 'hinnerupnet' objektet er allerede initialiseret!\");\r\n  }\r\n};<\/pre>\n<p>Leg selv videre med mulighederne, de er mange!<\/p>","protected":false},"excerpt":{"rendered":"<p>JavaScript sproget er dynamisk, hvilket vil sige at mens ens script afvikles kan alt modificeres. Har man et objekt, er det muligt at tilf\u00f8je og fjerne properties p\u00e5 det. Sagt med andre ord er det muligt at modificere den kode der afvikles, b\u00e5de ved at tilf\u00f8je, fjerne og overskrive funktioner samt variable. Note: I de [&hellip;]<\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8,4],"tags":[119,36],"class_list":["post-207","post","type-post","status-publish","format-standard","hentry","category-javascript","category-programming","tag-javascript","tag-self-modifying-code"],"_links":{"self":[{"href":"https:\/\/www.hinnerup.net\/en\/wp-json\/wp\/v2\/posts\/207","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.hinnerup.net\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.hinnerup.net\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.hinnerup.net\/en\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/www.hinnerup.net\/en\/wp-json\/wp\/v2\/comments?post=207"}],"version-history":[{"count":24,"href":"https:\/\/www.hinnerup.net\/en\/wp-json\/wp\/v2\/posts\/207\/revisions"}],"predecessor-version":[{"id":559,"href":"https:\/\/www.hinnerup.net\/en\/wp-json\/wp\/v2\/posts\/207\/revisions\/559"}],"wp:attachment":[{"href":"https:\/\/www.hinnerup.net\/en\/wp-json\/wp\/v2\/media?parent=207"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.hinnerup.net\/en\/wp-json\/wp\/v2\/categories?post=207"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.hinnerup.net\/en\/wp-json\/wp\/v2\/tags?post=207"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}