for(var k in {oops:null}){
// cool, got "k" here ...
// now how do I get
// the bloody "oops" value?
}
This quick post talks about above nonsense case providing a solution I will explain only if anybody will be interested about it, since (I am quite lazy and tired right now and ...) I think I've been able to solve the trick using almost every JavaScript bad practice :D
Runtime Assigned For In Loop
(function(self, Function){
// Another (C) WebReflection Silly Idea
"use strict"; // Mit Style Weirdness
var $o;
self.o = function o($){
if(!$)
self.o = $o;
else {
$o = self.o;
self.o = Function(
"$", "return function o(" +
new Array(($.length || 0) + 1).join(",k").slice(1) +
"){return $(arguments[0])}"
)(o);
for(var k in $)
self.o[k] = $[k]
;
};
return $;
};
})(this, Function);
WTF Is That
Above agglomerate of dynamic assignments/compositions let us perform a forIn without creating (virtually speaking) a variable. How?
for(var k in o({a:"b", c:"d"})){
alert([k, o[k]]);
};
In few words we don't need to define the "o" object in any place. The trick works as expected with blocked properties, as length is for a function, name, and whatever else was assigned to the object and even nested
for(var k in o({
length:123,
name:"test"
})){
alert([k, o[k]]);
// nested for in ...
for(var k in o({a:"b"}))
alert([k, o[k]])
;
o(); // back in town parent object
alert(o.name); // test
};
Isn't it cool? Even with Arrays!
for(var k in o([1, 2, 3])){
alert([k, o[k]]);
// 0,1
// 1,2
// 2,3
};
The good part is that break will work as expected and the changed object is quite static since it is a function, looped over original object properties.
Why This Abomination
Well, let's say with let and var we can do what we want in a generic for loop but we are kinda stuck with a single variable with a "for in" one.What would be truly nice in my opinion is the possibility to implement this kind of syntax:
for(var o = {a:"b"}, k; k in o){
// common loop with o and o[k]
};
Something similar to PHP world where we have:
foreach(array('a'=>'b') as $key => $value){
// do stuff and forget about the config variable
}
I am pretty much sure JavaScript will never implement above syntax but hey, that's why I have created a monster I'll probably never use in my programming life :P
The main trick about supported length property is described in this post.
Nice post :)
ReplyDeleteA couple of questions...
Does your implementation works with n-depth nested levels? I kind of tested it with this example and it doesn't seem to work:
for(var k in o({
length:123,
name:"test"
})){
alert([k, o[k]]);
// nested for in ...
for(var k in o({a:"b"})) {
alert([k, o[k]]);
for(var kk in o({'newkey':50})) {
alert([kk, o[kk]]);
}
o();
alert(["a", o.a]);
}
o();
alert(["len", o.length]);
};
I modified just a little bit the code and it seemed to work fine like this:
(function(self, Function){
// Another (C) WebReflection Silly Idea
"use strict"; // Mit Style Weirdness
var $o = [];
self.o = function o($){
if(!$)
self.o = $o.pop();
else {
$o.push(self.o);
self.o = Function(
"$", "return function o(" +
new Array(($.length || 0) + 1).join(",k").slice(1) +
"){return $(arguments[0])}"
)(o);
for(var k in $)
self.o[k] = $[k]
;
};
return $;
};
})(this, Function);
...but I'm not sure it's right.
Also, I kind of had a couple of problems with the "name" function property in the example. Does this have to do with the fact that "name" is a reserved property for Function objects?
Wow, that is some crazy stuff. I guess this is what you need the ECMAScript certification for... :D
ReplyDeleteI would not want to see that monstrosity in any production code though.
me neither ;)
ReplyDeleteWeeeeee! Thanks for the challenge Andrea, that was a fun lunch time effort for me.
ReplyDeletefor(var k in a = {oops:null}){
console.log(k);
console.log(a[k]);
}
Ok, I only tested it in Firefox, Opera, and Safari so it may barf in ie.
Josh, you have created a global "a" object in that way :-)
ReplyDeleteVery true, but it didn't let me scope it with a var in front.
ReplyDelete// This doesn't work.
for(var k in var a = {oops:null}){
console.log(k);
console.log(a[k]);
}
I guess the way around that is
var a = {oops:null};
for (var k in a) {
}
But that doesn't let you have a one line control statement.