| //------------------------------------------------------------------------------------------------------- | |
| // Copyright (C) Microsoft. All rights reserved. | |
| // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. | |
| //------------------------------------------------------------------------------------------------------- | |
| function echo(msg) { | |
| WScript.Echo(msg); | |
| } | |
| function guarded_call(func) { | |
| try { | |
| func(); | |
| } catch(e) { | |
| echo("Exception: " + e.name + " : " + e.message); | |
| } | |
| } | |
| function dump_args() { | |
| var args = ""; | |
| for (var i = 0; i < arguments.length; i++) { | |
| if (i > 0) { | |
| args += ", "; | |
| } | |
| args += arguments[i]; | |
| } | |
| echo("Called with this: " + typeof this + "[" + this + "], args: [" + args + "]"); | |
| } | |
| // 1. If IsCallable(func) is false, throw TypeError | |
| var noncallable = { | |
| apply: Function.prototype.apply | |
| }; | |
| echo("--- f is not callable ---"); | |
| guarded_call(function() { | |
| noncallable.apply(); | |
| }); | |
| guarded_call(function() { | |
| noncallable.apply({}, [1, 2, 3]); | |
| }); | |
| // 2. If argArray is null or undefined, call func with an empty list of arguments | |
| var o = {}; | |
| echo("\n--- f.apply(x) ---"); | |
| guarded_call(function() { | |
| dump_args.apply(o); | |
| }); | |
| echo("\n--- f.apply(x, null), f.apply(x, undefined) ---"); | |
| guarded_call(function() { | |
| dump_args.apply(o, null); | |
| }); | |
| guarded_call(function() { | |
| dump_args.apply(o, undefined); | |
| }); | |
| // 3. Type(argArray) is invalid | |
| echo("\n--- f.apply(x, 123), f.apply(x, 'string'), f.apply(x, true) ---"); | |
| guarded_call(function() { | |
| dump_args.apply(o, 123); | |
| }); | |
| guarded_call(function() { | |
| dump_args.apply(o, 'string'); | |
| }); | |
| guarded_call(function() { | |
| dump_args.apply(o, true); | |
| }); | |
| // 5, 7 argArray.length is invalid | |
| echo("\n--- f.apply(x, obj), obj.length is null/undefined/NaN/string/OutOfRange ---"); | |
| guarded_call(function() { | |
| dump_args.apply(o, {length: null}); | |
| }); | |
| guarded_call(function() { | |
| dump_args.apply(o, {length: undefined}); | |
| }); | |
| guarded_call(function() { | |
| dump_args.apply(o, {length: NaN}); | |
| }); | |
| guarded_call(function() { | |
| dump_args.apply(o, {length: 'string'}); | |
| }); | |
| guarded_call(function() { | |
| dump_args.apply(o, {length: 4294967295 + 1}); //UINT32_MAX + 1 | |
| }); | |
| guarded_call(function() { | |
| dump_args.apply(o, {length: -1}); | |
| }); | |
| echo("\n--- f.apply(x, arr), arr.length is huge ---"); | |
| var huge_array_length = []; | |
| huge_array_length.length = 2147483647; //INT32_MAX | |
| guarded_call(function() { | |
| dump_args.apply(o, huge_array_length); | |
| }); | |
| echo("\n--- f.apply(x, obj), obj.length is huge ---"); | |
| guarded_call(function() { | |
| dump_args.apply(o, {length: 4294967295}); //UINT32_MAX | |
| }); | |
| // Normal usage -- argArray tests | |
| echo("\n--- f.apply(x, arr) ---"); | |
| dump_args.apply(o, []); | |
| dump_args.apply(o, [1]); | |
| dump_args.apply(o, [2, 3, NaN, null, undefined, false, "hello", o]); | |
| echo("\n--- f.apply(x, arr) arr.length increased ---"); | |
| var arr = [1, 2]; | |
| arr.length = 5; | |
| dump_args.apply(o, arr); | |
| echo("\n--- f.apply(x, arguments) ---"); | |
| function apply_arguments() { | |
| dump_args.apply(o, arguments); | |
| } | |
| apply_arguments(); | |
| apply_arguments(1); | |
| apply_arguments(2, 3, NaN, null, undefined, false, "hello", o); | |
| echo("\n--- f.apply(x, obj) ---"); | |
| guarded_call(function() { | |
| dump_args.apply(o, { | |
| length: 0 | |
| }); | |
| }); | |
| guarded_call(function() { | |
| dump_args.apply(o, { | |
| length: 1, | |
| "0": 1 | |
| }); | |
| }); | |
| guarded_call(function() { | |
| dump_args.apply(o, { | |
| length: 8, | |
| "0": 2, | |
| "1": 3, | |
| "2": NaN, | |
| "3": null, | |
| "4": undefined, | |
| "5": false, | |
| "6": "hello", | |
| "7": o | |
| }); | |
| }); | |
| // Normal usage -- thisArg tests | |
| function f1() { | |
| this.x1 = "hello"; | |
| } | |
| echo("\n--- f.apply(), f.apply(null), f.apply(undefined), global x1 should be changed ---"); | |
| f1.apply(); | |
| echo("global x1 : " + x1); | |
| x1 = 0; | |
| f1.apply(null); | |
| echo("global x1 : " + x1); | |
| x1 = 0; | |
| f1.apply(undefined); | |
| echo("global x1 : " + x1); | |
| echo("\n--- f.apply(x), global x1 should NOT be changed ---"); | |
| var o = {}; | |
| x1 = 0; | |
| f1.apply(o); | |
| echo("global x1 : " + x1); | |
| echo("o.x1 : " + o.x1); | |
| // apply on non-objects -- test thisArg | |
| function apply_non_object(func, doEcho) { | |
| var echo_if = function(msg) { | |
| if (doEcho) { | |
| echo(msg); | |
| } | |
| }; | |
| guarded_call(function() { | |
| echo_if(func.apply()); | |
| }); | |
| guarded_call(function() { | |
| echo_if(func.apply(null)); | |
| }); | |
| guarded_call(function() { | |
| echo_if(func.apply(undefined)); | |
| }); | |
| guarded_call(function() { | |
| echo_if(func.apply(123)); | |
| }); | |
| guarded_call(function() { | |
| echo_if(func.apply(true)); | |
| }); | |
| guarded_call(function() { | |
| echo_if(func.apply("string")); | |
| }); | |
| } | |
| echo("\n--- f.apply(v), v is missing/null/undefined/123/true/'string' ---"); | |
| apply_non_object(dump_args); | |
| // | |
| // ES5: String.prototype.charCodeAt calls CheckObjectCoercible(thisArg). It should throw | |
| // when thisArg is missing/null/undefined. | |
| // | |
| echo("\n--- f.apply(v), v is missing/null/undefined/123/true/'string', f: string.charCodeAt ---"); | |
| apply_non_object(String.prototype.charCodeAt, true); | |
| echo("\n--- f.apply(v), v is missing/null/undefined/123/true/'string', f: string.charAt ---"); | |
| apply_non_object(String.prototype.charAt, true); | |
| // | |
| // Similarly, test thisArg behavior in Function.prototype.call | |
| // | |
| // call on non-objects -- test thisArg | |
| function call_non_object(func, doEcho) { | |
| var echo_if = function(msg) { | |
| if (doEcho) { | |
| echo(msg); | |
| } | |
| }; | |
| guarded_call(function() { | |
| echo_if(func.call()); | |
| }); | |
| guarded_call(function() { | |
| echo_if(func.call(null)); | |
| }); | |
| guarded_call(function() { | |
| echo_if(func.call(undefined)); | |
| }); | |
| guarded_call(function() { | |
| echo_if(func.call(123)); | |
| }); | |
| guarded_call(function() { | |
| echo_if(func.call(true)); | |
| }); | |
| guarded_call(function() { | |
| echo_if(func.call("string")); | |
| }); | |
| } | |
| echo("\n--- f.call(v), v is missing/null/undefined/123/true/'string' ---"); | |
| call_non_object(dump_args); | |
| echo("\n--- f.call(v), v is missing/null/undefined/123/true/'string', f: string.charCodeAt ---"); | |
| call_non_object(String.prototype.charCodeAt, true); | |
| echo("\n--- f.call(v), v is missing/null/undefined/123/true/'string', f: string.charAt ---"); | |
| call_non_object(String.prototype.charAt, true); |