-
-
Save jed/1400363 to your computer and use it in GitHub Desktop.
// usage: newOperator(constructor, [arg1, arg2, ...]) | |
// example: newOperator(Date, [1995, 11, 24]) | |
// => should be identical to new Date(1995, 11, 24) | |
function newOperator(constructor, args) { | |
var i = args.length + 1 | |
, params = [] | |
, fn | |
while (i--) params[i] = "$" + i | |
params.push("return new $0(" + params.slice(1) + ")") | |
fn = Function.apply(null, params) | |
params = params.concat.apply(constructor, args) | |
return fn.apply(null, params) | |
} |
with caching:
function newOperator(ctor, args) {
var l = args.length
, fn = newOperator[l]
, body, i
if (!fn) {
for (i = 0; i < l; i++) {
i ? body += "," : body = "return new ctor("
body += "args[" + i + "]"
}
fn = newOperator[l] = Function("ctor", "args", body + ")")
}
return fn(ctor, args)
}
holy cow, you can put commas in the argument string? does that work universally?
sure it does ;-)
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function
Names to be used by the function as formal argument names. Each must be a string that corresponds to a valid JavaScript identifier or a list of such strings separated with a comma; for example "x", "theValue", or "a,b".
with cache ...
function newOperator(g, o, l, f) {
return ((f = newOperator)[l = (o || []).length] || (f[l] = Function(
"g,o,l",
"return new g(" +
Array(l + 1).join(",o[l++]").slice(1)
+ ")"
)))(g, o, 0);
}
bravo, @WebReflection. i'm probably going to go with something like this:
function newOperator(ctor, args) {
var l = args.length + 1
, fn = newOperator[l]
fn || (fn = newOperator[l] = Function(
"a,b,c",
"return new a(" +
Array(l).join(",b[c++]").slice(1) +
")"
))
return fn(ctor, args, 0)
}
does not fit into 140 bytes ... shame of us :D
actually, it's 129 bytes: https://gist.github.com/1400834
you changed function name, if it's d of course it's smaller ... I would still leave the (a||[]).length to make newOperator(Array) possible, as example
good point, fixed it.
a non-golfed version:
function newOperator(ctor, args) {
var length, fn
args || (args = [])
length = args.length + 1
fn = newOperator[length]
fn || (fn = newOperator[length] = Function(
"ctor", "args", "i",
"return new ctor(" +
Array(length).join(",args[i++]").slice(1) +
")"
))
return fn(ctor, args, 0)
}
jed, no need to b=b||[] ... just b||[] because if length is zero Array(1).join("whatever") will be an empty string (join works with at least length 2 between 0 and 1) so the b, even if undefined, will be untouched ;-)
function d(
a, // constructor function
b, // arguments
c // placeholder for length
){
return( // return the result of
d[c=b?-~b.length:1] || ( // the cached function or
d[c] = Function( // a new function that takes
"a,b,c", // a constructor, arguments, and an index
"return new a(" + // and returns a new instance of the constructor
Array(c) // with
.join(",b[c++]") // the inline arguments
.slice(1) + // (sliced to remove leading comma)
")"
)
)
)(a,b,0) // called with the constructor and arguments
}
in that case, why define the array at all if args
has no length? can we use this?
var length = args ? args.length + 1 : 0
[EDIT] so something like this:
function newOperator(ctor, args) {
var length = args ? -~args.length : 0
, fn = newOperator[length]
fn || (fn = newOperator[length] = Function(
"ctor", "args", "i",
"return new ctor(" +
Array(length).join(", args[i++]").slice(1) +
")"
))
return fn(ctor, args, 0)
}
the minus tilde does not give us much more than +1, 2 readable chars with no necessary int cast.
I agree the creation of an empty Array per each call without arguments is way too redundant and also bigger than this solution:
d[c=b?b.length+1:1]
I have edited and as result 2 chars less and faster "no arguments" execution ;-)
doesn't leaving out the number cast mean that the length property could be used to inject code? i'm thinking where args
is {length: "throw 'neener neener'"}
.
well, the initial trick does not solve a thing here ... if you want to screw up functions that would work even with native arrays methods ...
uh .. wait, I know what you mean ... so yes, minus tilde then, updated :D
right, I guess we both missed the whole point then ... too bad