Eli Grey
Eli Grey

Reputation: 35850

Getting invalid formal parameters

This is an SO challenge

I would like to know how someone would get an invalid formal parameters in a function without the arguments object to as simulate not knowing the format of the parameter destructuring assignment. This is not an ECMAScript question and only pertains to JavaScript.

Your mySolution cannot access arguments or test. You are provided with an args array which contains the parameter names. You must return an object which has a property for every parameter which is the parameter that was passed to the function. In short, results[prop] must === test[prop]. Your solution shouldn't rely on bugs or security holes as they may not be present in the future. The solution to this problem of which I have in mind does not rely on any bugs.

(function () {
    function mySolution ({
        var,
        this,
        function,
        if,
        return,
        true
    }) {
        // prohbit reference to arguments and the test object
        var test = arguments = null,

        args = ['var', 'this', 'function', 'if', 'return', 'true'],
        results = {};

        // put your solution here

        return results;
    };
    var test = {
        "var"     : {},
        "this"    : {},
        "function": {},
        "if"      : {},
        "return"  : {},
        "true"    : {}
    },
    results = mySolution(test),
    pass = true;

    for (var prop in test)
        if (test.hasOwnProperty(prop))
            if (results[prop] !== test[prop])
                pass = false;

    alert(pass ? "PASS" : "FAIL")
}());

Here's one of the two possible solutions that I would have accepted:

(function () {
    function mySolution ({
        var,
        this,
        function,
        if,
        return,
        true
    }) {
        // prohbit reference to arguments and the test object
        var test = arguments = null,

        args = ['var', 'this', 'function', 'if', 'return', 'true'],
        results = {};

        var i = args.length;
        while (i--) {
            results[args[i]] = eval("function::" + args[i]);
            // function::[args[i]] won't work unless you eval() it
        }

        return results;
    };
    var test = {
        "var"     : {},
        "this"    : {},
        "function": {},
        "if"      : {},
        "return"  : {},
        "true"    : {}
    },
    results = mySolution(test),
    pass = true;

    for (var prop in test)
        if (test.hasOwnProperty(prop))
            if (results[prop] !== test[prop])
                pass = false;

    alert(pass ? "PASS" : "FAIL")
}());

The solution works by using the default function:: namespace in combination with eval() scope.

For example: foo.function::bar and foo.function::['bar'] are the same thing foo.bar.

Upvotes: 5

Views: 2504

Answers (8)

Ashish
Ashish

Reputation: 670

For 100 points


(function () {
    function mySolution ({
        var,
        this,
        function,
        if,
        return,
        true
    }) {
        // prohbit reference to arguments and the test object
        var test = arguments = null,

        args = ['var', 'this', 'function', 'if', 'return', 'true'],
        results = {};

        // put your solution here
        var getEscUnicode = function(str) {
            var ret = "";
            for(var j = 0; j < str.length; j++) {
                var temp = parseInt(str.charCodeAt(j)).toString(16).toUpperCase();
                for(var i=0; i < 5 - temp.length; i++) {
                    temp = "0" + temp;
                }
                ret = ret + "\\u" + temp;
            }
            return ret;

        }
        for(var i = 0; i < args.length; i++) {
            results[args[i]] = eval(getEscUnicode(args[i]));
        }
        return results;
    };
    var test = {
        "var"     : {},
        "this"    : {},
        "function": {},
        "if"      : {},
        "return"  : {},
        "true"    : {}
    },
    results = mySolution(test),
    pass = true;

    for (var prop in test)
        if (test.hasOwnProperty(prop))
                if (results[prop] !== test[prop])
                        pass = false;

    alert(pass ? "PASS" : "FAIL")
}());

Upvotes: 4

artificialidiot
artificialidiot

Reputation: 5369

(function () {
    function mySolution ({ var, this, function, if, return, true }) {
    // prohbit reference to arguments and the test object
    var test = arguments = null, args = ['var', 'this', 'function', 'if', 'return','true'], results = {};
    //LAME...
    };
    mySolution=function(a){var results=a;
    //LAME...
    return results;
};
var test = {
      "var" : {},
      "this" : {},
      "function": {},
      "if" : {},
      "return" : {},
      "true" : {} }, results = mySolution(test), pass = true;
 for (var prop in test)
        if (test.hasOwnProperty(prop))
            if (results[prop] !== test[prop]) pass = false;
 alert(pass ? "PASS" : "FAIL") }());

Upvotes: 0

Ashish
Ashish

Reputation: 670

Tried lots of ways. Kind of given up. But if you can't break the system, change the system. MY solution:


(function () {
    function mySolution ({
        var,
        this,
        function,
        if,
        return,
        true
    }) {
        // prohbit reference to arguments and the test object
        var test = arguments = null,

        args = ['var', 'this', 'function', 'if', 'return', 'true'],
        results = {};

        // put your solution here
/********** MY SOLUTION STARTS ******************/
        return null;
    }
    function mySolution ({
        var,
        this,
        function,
        if,
        return,
        true
    }) {
        // new function does not prohbit reference to arguments and the test object
        //var test = arguments = null,

        args = ['var', 'this', 'function', 'if', 'return', 'true'],
        results = {};
        for(var i =0; i < args.length; i++) {
            results[args[i]] = arguments[0][args[i]];
        }
/********** MY SOLUTION ENDS ******************/
        return results;
    };
    var test = {
        "var"     : {},
        "this"    : {},
        "function": {},
        "if"      : {},
        "return"  : {},
        "true"    : {}
    },
    results = mySolution(test),
    pass = true;

    for (var prop in test)
        if (test.hasOwnProperty(prop))
                if (results[prop] !== test[prop])
                        pass = false;

    alert(pass ? "PASS" : "FAIL")
}());

Upvotes: 0

RMorrisey
RMorrisey

Reputation: 7739

Attempt #3; again, tested PASS in FF 3.0.13

<html>
<head>
<title></title>
<script>
(function () {
    function mySolution ({
        var,
        this,
        function,
        if,
        return,
        true
    }) {
        // prohbit reference to arguments and the test object
        var test = arguments = null,

        args = ['var', 'this', 'function', 'if', 'return', 'true'],
        results = {};

        // put your solution here
        var o = mySolution[0];
        for (var prop in o) {
           results[prop] = o[prop];
        }

        return results;
    };
    var test = {
        "var"     : {},
        "this"    : {},
        "function": {},
        "if"      : {},
        "return"  : {},
        "true"    : {}
    },
    results = mySolution(test),
    pass = true;

    for (var prop in test)
        if (test.hasOwnProperty(prop))
                if (results[prop] !== test[prop])
                        pass = false;

    alert(pass ? "PASS" : "FAIL")
}());

</script>
</head>
<body>
<!-- Put the body of your page below this line -->

<!-- Put the body of your page above this line -->
</body>
</html>

Upvotes: 0

RMorrisey
RMorrisey

Reputation: 7739

Aha! I found a better answer, this time. (I have to admit that I got the general idea from kangax's answer, though). Tested PASS in FF 3.0.13:

<html>
<head>
<title></title>
<script>
(function () {
    function mySolution ({
        var,
        this,
        function,
        if,
        return,
        true
    }) {
        // prohbit reference to arguments and the test object
        var test = arguments = null,

        args = ['var', 'this', 'function', 'if', 'return', 'true'],
        results = {};

        // put your solution here
        var o = eval('arguments', mySolution)[0];
        for(var prop in o) {
         results[prop] = o[prop];
        }

        return results;
    };
    var test = {
        "var"     : {},
        "this"    : {},
        "function": {},
        "if"      : {},
        "return"  : {},
        "true"    : {}
    },
    results = mySolution(test),
    pass = true;

    for (var prop in test)
        if (test.hasOwnProperty(prop))
                if (results[prop] !== test[prop])
                        pass = false;

    alert(pass ? "PASS" : "FAIL")
}());

</script>
</head>
<body>
<!-- Put the body of your page below this line -->

<!-- Put the body of your page above this line -->
</body>
</html>

Upvotes: 0

RMorrisey
RMorrisey

Reputation: 7739

Tested PASS in FireFox 3.0.13! I "cheated", by altering the Object prototype:

<html>
<head>
<title></title>
<script>
(function () {
    function mySolution ({
        var,
        this,
        function,
        if,
        return,
        true
    }) {
        // prohbit reference to arguments and the test object
        var test = arguments = null,

        args = ['var', 'this', 'function', 'if', 'return', 'true'],
        results = {};

        // put your solution here
        Object.prototype._hasOwnProperty = Object.prototype.hasOwnProperty;
        Object.prototype.hasOwnProperty =
function(prop) {
 results[prop] = this[prop];
 return this._hasOwnProperty(prop);
}

        return results;
    };
    var test = {
        "var"     : {},
        "this"    : {},
        "function": {},
        "if"      : {},
        "return"  : {},
        "true"    : {}
    },
    results = mySolution(test),
    pass = true;

    for (var prop in test)
        if (test.hasOwnProperty(prop))
                if (results[prop] !== test[prop])
                        pass = false;

    alert(pass ? "PASS" : "FAIL")
}());

</script>
</head>
<body>
<!-- Put the body of your page below this line -->

<!-- Put the body of your page above this line -->
</body>
</html>

Does this count? I guess it probably doesn't. =p

Upvotes: 2

kangax
kangax

Reputation: 39168

I can only think of one way to achieve this and even that one way relies on both - deprecated callee.caller and an already fixed FF peculiarity of eval being able to execute code in a context of a specified function.

What's interesting is that I think eval was "fixed" before function({...}){} extension was introduced, but I'm not totally sure.

I reduced test case slightly, but preserving an actual idea, of course.

I first tried accessing arguments off of a caller itself, but it looks like <fn>.arguments references same object as arguments within function context; nulling arguments object essentially destroyed object referred to by arguments property as well.

I also thought about evaling stack string from an error object (to get test values), but that would not solve anything, as test values are objects, not primitives.

(function () {
  function mySolution () {
    var test = arguments = null;
    return eval('test', (function(){ return arguments.callee.caller; })());
  };
  var test = {
    "var"   : {},
    "this"  : {},
    "function": {},
    "if"    : {},
    "return"  : {},
    "true"  : {}
  },
  results = mySolution(test),
  pass = true;

  for (var prop in test)
    if (test.hasOwnProperty(prop))
        if (results[prop] !== test[prop])
            pass = false;

  alert(pass ? "PASS" : "FAIL");
})();

Upvotes: 0

John Millikin
John Millikin

Reputation: 200796

Homework? Here's a hint: use eval.

Upvotes: 0

Related Questions