| OLD | NEW |
| 1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 11 matching lines...) Expand all Loading... |
| 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 | 27 |
| 28 // Tests the Function.prototype.bind (ES 15.3.4.5) method. | 28 // Tests the Function.prototype.bind (ES 15.3.4.5) method. |
| 29 | 29 |
| 30 // Simple tests. | 30 // Simple tests. |
| 31 function foo(x, y, z) { | 31 function foo(x, y, z) { |
| 32 return x + y + z; | 32 return [this, arguments.length, x]; |
| 33 } | 33 } |
| 34 | 34 |
| 35 assertEquals(3, foo.length); |
| 36 |
| 35 var f = foo.bind(foo); | 37 var f = foo.bind(foo); |
| 36 assertEquals(3, f(1, 1, 1)); | 38 assertEquals([foo, 3, 1], f(1, 2, 3)); |
| 37 assertEquals(3, f.length); | 39 assertEquals(3, f.length); |
| 38 | 40 |
| 39 f = foo.bind(foo, 2); | 41 f = foo.bind(foo, 1); |
| 40 assertEquals(4, f(1, 1)); | 42 assertEquals([foo, 3, 1], f(2, 3)); |
| 41 assertEquals(2, f.length); | 43 assertEquals(2, f.length); |
| 42 | 44 |
| 43 f = foo.bind(foo, 2, 2); | 45 f = foo.bind(foo, 1, 2); |
| 44 assertEquals(5, f(1)); | 46 assertEquals([foo, 3, 1], f(3)); |
| 45 assertEquals(1, f.length); | 47 assertEquals(1, f.length); |
| 46 | 48 |
| 47 f = foo.bind(foo, 2, 2, 2); | 49 f = foo.bind(foo, 1, 2, 3); |
| 48 assertEquals(6, f()); | 50 assertEquals([foo, 3, 1], f()); |
| 49 assertEquals(0, f.length); | 51 assertEquals(0, f.length); |
| 50 | 52 |
| 51 // Test that length works correctly even if more than the actual number | 53 // Test that length works correctly even if more than the actual number |
| 52 // of arguments are given when binding. | 54 // of arguments are given when binding. |
| 53 f = foo.bind(foo, 1, 2, 3, 4, 5, 6, 7, 8, 9); | 55 f = foo.bind(foo, 1, 2, 3, 4, 5, 6, 7, 8, 9); |
| 54 assertEquals(6, f()); | 56 assertEquals([foo, 9, 1], f()); |
| 55 assertEquals(0, f.length); | 57 assertEquals(0, f.length); |
| 56 | 58 |
| 57 // Use a different bound object. | 59 // Use a different bound object. |
| 58 var obj = {x: 42, y: 43}; | 60 var obj = {x: 42, y: 43}; |
| 59 // Values that would normally be in "this" when calling f_bound_this. | 61 // Values that would normally be in "this" when calling f_bound_this. |
| 60 var x = 42; | 62 var x = 42; |
| 61 var y = 44; | 63 var y = 44; |
| 62 | 64 |
| 63 function f_bound_this(z) { | 65 function f_bound_this(z) { |
| 64 return z + this.y - this.x; | 66 return z + this.y - this.x; |
| 65 } | 67 } |
| 66 | 68 |
| 67 assertEquals(3, f_bound_this(1)) | 69 assertEquals(3, f_bound_this(1)) |
| 68 f = f_bound_this.bind(obj); | 70 f = f_bound_this.bind(obj); |
| 69 assertEquals(2, f(1)); | 71 assertEquals(2, f(1)); |
| 70 assertEquals(1, f.length); | 72 assertEquals(1, f.length); |
| 71 | 73 |
| 72 f = f_bound_this.bind(obj, 2); | 74 f = f_bound_this.bind(obj, 2); |
| 73 assertEquals(3, f()); | 75 assertEquals(3, f()); |
| 74 assertEquals(0, f.length); | 76 assertEquals(0, f.length); |
| 75 | 77 |
| 76 // Test chained binds. | 78 // Test chained binds. |
| 77 | 79 |
| 78 // When only giving the thisArg, any number of binds should have | 80 // When only giving the thisArg, any number of binds should have |
| 79 // the same effect. | 81 // the same effect. |
| 80 f = foo.bind(foo); | 82 f = foo.bind(foo); |
| 81 assertEquals(3, f(1, 1, 1)); | 83 assertEquals([foo, 3, 1], f(1, 2, 3)); |
| 82 f = foo.bind(foo).bind(foo).bind(foo).bind(foo); | 84 |
| 83 assertEquals(3, f(1, 1, 1)); | 85 var not_foo = {}; |
| 86 f = foo.bind(foo).bind(not_foo).bind(not_foo).bind(not_foo); |
| 87 assertEquals([foo, 3, 1], f(1, 2, 3)); |
| 84 assertEquals(3, f.length); | 88 assertEquals(3, f.length); |
| 85 | 89 |
| 86 // Giving bound parameters should work at any place in the chain. | 90 // Giving bound parameters should work at any place in the chain. |
| 87 f = foo.bind(foo, 1).bind(foo).bind(foo).bind(foo); | 91 f = foo.bind(foo, 1).bind(not_foo).bind(not_foo).bind(not_foo); |
| 88 assertEquals(3, f(1, 1)); | 92 assertEquals([foo, 3, 1], f(2, 3)); |
| 89 assertEquals(2, f.length); | 93 assertEquals(2, f.length); |
| 90 | 94 |
| 91 f = foo.bind(foo).bind(foo, 1).bind(foo).bind(foo); | 95 f = foo.bind(foo).bind(not_foo, 1).bind(not_foo).bind(not_foo); |
| 92 assertEquals(3, f(1, 1)); | 96 assertEquals([foo, 3, 1], f(2, 3)); |
| 93 assertEquals(2, f.length); | 97 assertEquals(2, f.length); |
| 94 | 98 |
| 95 f = foo.bind(foo).bind(foo).bind(foo,1 ).bind(foo); | 99 f = foo.bind(foo).bind(not_foo).bind(not_foo,1 ).bind(not_foo); |
| 96 assertEquals(3, f(1, 1)); | 100 assertEquals([foo, 3, 1], f(2, 3)); |
| 97 assertEquals(2, f.length); | 101 assertEquals(2, f.length); |
| 98 | 102 |
| 99 f = foo.bind(foo).bind(foo).bind(foo).bind(foo, 1); | 103 f = foo.bind(foo).bind(not_foo).bind(not_foo).bind(not_foo, 1); |
| 100 assertEquals(3, f(1, 1)); | 104 assertEquals([foo, 3, 1], f(2, 3)); |
| 101 assertEquals(2, f.length); | 105 assertEquals(2, f.length); |
| 102 | 106 |
| 103 // Several parameters can be given, and given in different bind invokations. | 107 // Several parameters can be given, and given in different bind invocations. |
| 104 f = foo.bind(foo, 1, 1).bind(foo).bind(foo).bind(foo); | 108 f = foo.bind(foo, 1, 2).bind(not_foo).bind(not_foo).bind(not_foo); |
| 105 assertEquals(3, f(1)); | 109 assertEquals([foo, 3, 1], f(3)); |
| 106 assertEquals(1, f.length); | 110 assertEquals(1, f.length); |
| 107 | 111 |
| 108 f = foo.bind(foo).bind(foo, 1, 1).bind(foo).bind(foo); | 112 f = foo.bind(foo).bind(not_foo, 1, 2).bind(not_foo).bind(not_foo); |
| 109 assertEquals(3, f(1)); | 113 assertEquals([foo, 3, 1], f(1)); |
| 110 assertEquals(1, f.length); | 114 assertEquals(1, f.length); |
| 111 | 115 |
| 112 f = foo.bind(foo).bind(foo, 1, 1).bind(foo).bind(foo); | 116 f = foo.bind(foo).bind(not_foo, 1, 2).bind(not_foo).bind(not_foo); |
| 113 assertEquals(3, f(1)); | 117 assertEquals([foo, 3, 1], f(3)); |
| 114 assertEquals(1, f.length); | 118 assertEquals(1, f.length); |
| 115 | 119 |
| 116 f = foo.bind(foo).bind(foo).bind(foo, 1, 1).bind(foo); | 120 f = foo.bind(foo).bind(not_foo).bind(not_foo, 1, 2).bind(not_foo); |
| 117 assertEquals(3, f(1)); | 121 assertEquals([foo, 3, 1], f(1)); |
| 118 assertEquals(1, f.length); | 122 assertEquals(1, f.length); |
| 119 | 123 |
| 120 f = foo.bind(foo).bind(foo).bind(foo).bind(foo, 1, 1); | 124 f = foo.bind(foo).bind(not_foo).bind(not_foo).bind(not_foo, 1, 2); |
| 121 assertEquals(3, f(1)); | 125 assertEquals([foo, 3, 1], f(3)); |
| 122 assertEquals(1, f.length); | 126 assertEquals(1, f.length); |
| 123 | 127 |
| 124 f = foo.bind(foo, 1).bind(foo, 1).bind(foo).bind(foo); | 128 f = foo.bind(foo, 1).bind(not_foo, 2).bind(not_foo).bind(not_foo); |
| 125 assertEquals(3, f(1)); | 129 assertEquals([foo, 3, 1], f(3)); |
| 126 assertEquals(1, f.length); | 130 assertEquals(1, f.length); |
| 127 | 131 |
| 128 f = foo.bind(foo, 1).bind(foo).bind(foo, 1).bind(foo); | 132 f = foo.bind(foo, 1).bind(not_foo).bind(not_foo, 2).bind(not_foo); |
| 129 assertEquals(3, f(1)); | 133 assertEquals([foo, 3, 1], f(3)); |
| 130 assertEquals(1, f.length); | 134 assertEquals(1, f.length); |
| 131 | 135 |
| 132 f = foo.bind(foo, 1).bind(foo).bind(foo).bind(foo, 1); | 136 f = foo.bind(foo, 1).bind(not_foo).bind(not_foo).bind(not_foo, 2); |
| 133 assertEquals(3, f(1)); | 137 assertEquals([foo, 3, 1], f(3)); |
| 134 assertEquals(1, f.length); | 138 assertEquals(1, f.length); |
| 135 | 139 |
| 136 f = foo.bind(foo).bind(foo, 1).bind(foo).bind(foo, 1); | 140 f = foo.bind(foo).bind(not_foo, 1).bind(not_foo).bind(not_foo, 2); |
| 137 assertEquals(3, f(1)); | 141 assertEquals([foo, 3, 1], f(3)); |
| 138 assertEquals(1, f.length); | 142 assertEquals(1, f.length); |
| 139 | 143 |
| 144 // The wrong number of arguments can be given to bound functions too. |
| 145 f = foo.bind(foo); |
| 146 assertEquals(3, f.length); |
| 147 assertEquals([foo, 0, undefined], f()); |
| 148 assertEquals([foo, 1, 1], f(1)); |
| 149 assertEquals([foo, 2, 1], f(1, 2)); |
| 150 assertEquals([foo, 3, 1], f(1, 2, 3)); |
| 151 assertEquals([foo, 4, 1], f(1, 2, 3, 4)); |
| 152 |
| 153 f = foo.bind(foo, 1); |
| 154 assertEquals(2, f.length); |
| 155 assertEquals([foo, 1, 1], f()); |
| 156 assertEquals([foo, 2, 1], f(2)); |
| 157 assertEquals([foo, 3, 1], f(2, 3)); |
| 158 assertEquals([foo, 4, 1], f(2, 3, 4)); |
| 159 |
| 160 f = foo.bind(foo, 1, 2); |
| 161 assertEquals(1, f.length); |
| 162 assertEquals([foo, 2, 1], f()); |
| 163 assertEquals([foo, 3, 1], f(3)); |
| 164 assertEquals([foo, 4, 1], f(3, 4)); |
| 165 |
| 166 f = foo.bind(foo, 1, 2, 3); |
| 167 assertEquals(0, f.length); |
| 168 assertEquals([foo, 3, 1], f()); |
| 169 assertEquals([foo, 4, 1], f(4)); |
| 170 |
| 171 f = foo.bind(foo, 1, 2, 3, 4); |
| 172 assertEquals(0, f.length); |
| 173 assertEquals([foo, 4, 1], f()); |
| 174 |
| 140 // Test constructor calls. | 175 // Test constructor calls. |
| 141 | 176 |
| 142 function bar(x, y, z) { | 177 function bar(x, y, z) { |
| 143 this.x = x; | 178 this.x = x; |
| 144 this.y = y; | 179 this.y = y; |
| 145 this.z = z; | 180 this.z = z; |
| 146 } | 181 } |
| 147 | 182 |
| 148 f = bar.bind(bar); | 183 f = bar.bind(bar); |
| 149 var obj2 = new f(1,2,3); | 184 var obj2 = new f(1,2,3); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 164 assertEquals(3, obj2.z); | 199 assertEquals(3, obj2.z); |
| 165 | 200 |
| 166 f = bar.bind(bar, 1, 2, 3); | 201 f = bar.bind(bar, 1, 2, 3); |
| 167 obj2 = new f(); | 202 obj2 = new f(); |
| 168 assertEquals(1, obj2.x); | 203 assertEquals(1, obj2.x); |
| 169 assertEquals(2, obj2.y); | 204 assertEquals(2, obj2.y); |
| 170 assertEquals(3, obj2.z); | 205 assertEquals(3, obj2.z); |
| 171 | 206 |
| 172 | 207 |
| 173 // Test bind chains when used as a constructor. | 208 // Test bind chains when used as a constructor. |
| 174 | |
| 175 f = bar.bind(bar, 1).bind(bar, 2).bind(bar, 3); | 209 f = bar.bind(bar, 1).bind(bar, 2).bind(bar, 3); |
| 176 obj2 = new f(); | 210 obj2 = new f(); |
| 177 assertEquals(1, obj2.x); | 211 assertEquals(1, obj2.x); |
| 178 assertEquals(2, obj2.y); | 212 assertEquals(2, obj2.y); |
| 179 assertEquals(3, obj2.z); | 213 assertEquals(3, obj2.z); |
| 180 | 214 |
| 181 // Test instanceof obj2 is bar, not f. | 215 // Test obj2 is instanceof both bar and f. |
| 182 assertTrue(obj2 instanceof bar); | 216 assertTrue(obj2 instanceof bar); |
| 183 assertFalse(obj2 instanceof f); | 217 assertTrue(obj2 instanceof f); |
| 218 |
| 219 // This-args are not relevant to instanceof. |
| 220 f = bar.bind(foo.prototype, 1). |
| 221 bind(String.prototype, 2). |
| 222 bind(Function.prototype, 3); |
| 223 var obj3 = new f(); |
| 224 assertTrue(obj3 instanceof bar); |
| 225 assertTrue(obj3 instanceof f); |
| 226 assertFalse(obj3 instanceof foo); |
| 227 assertFalse(obj3 instanceof Function); |
| 228 assertFalse(obj3 instanceof String); |
| 229 |
| 230 // thisArg is converted to object. |
| 231 f = foo.bind(undefined); |
| 232 assertEquals([this, 0, undefined], f()); |
| 233 |
| 234 f = foo.bind(null); |
| 235 assertEquals([this, 0, undefined], f()); |
| 236 |
| 237 f = foo.bind(42); |
| 238 assertEquals([Object(42), 0, undefined], f()); |
| 239 |
| 240 f = foo.bind("foo"); |
| 241 assertEquals([Object("foo"), 0, undefined], f()); |
| 242 |
| 243 f = foo.bind(true); |
| 244 assertEquals([Object(true), 0, undefined], f()); |
| 245 |
| 246 // Strict functions don't convert thisArg. |
| 247 function soo(x, y, z) { |
| 248 "use strict"; |
| 249 return [this, arguments.length, x]; |
| 250 } |
| 251 |
| 252 var s = soo.bind(undefined); |
| 253 assertEquals([undefined, 0, undefined], s()); |
| 254 |
| 255 s = soo.bind(null); |
| 256 assertEquals([null, 0, undefined], s()); |
| 257 |
| 258 s = soo.bind(42); |
| 259 assertEquals([42, 0, undefined], s()); |
| 260 |
| 261 s = soo.bind("foo"); |
| 262 assertEquals(["foo", 0, undefined], s()); |
| 263 |
| 264 s = soo.bind(true); |
| 265 assertEquals([true, 0, undefined], s()); |
| 266 |
| 267 // Test that .arguments and .caller are poisoned according to the ES5 spec. |
| 268 |
| 269 // Check that property descriptors are correct (unconfigurable, unenumerable, |
| 270 // and both get and set is the ThrowTypeError function). |
| 271 var cdesc = Object.getOwnPropertyDescriptor(f, "caller"); |
| 272 var adesc = Object.getOwnPropertyDescriptor(f, "arguments"); |
| 273 |
| 274 assertFalse(cdesc.enumerable); |
| 275 assertFalse(cdesc.configurable); |
| 276 |
| 277 assertFalse(adesc.enumerable); |
| 278 assertFalse(adesc.configurable); |
| 279 |
| 280 assertSame(cdesc.get, cdesc.set); |
| 281 assertSame(cdesc.get, adesc.get); |
| 282 assertSame(cdesc.get, adesc.set); |
| 283 |
| 284 assertTrue(cdesc.get instanceof Function); |
| 285 assertEquals(0, cdesc.get.length); |
| 286 assertThrows(cdesc.get, TypeError); |
| 287 |
| 288 assertThrows(function() { return f.caller; }, TypeError); |
| 289 assertThrows(function() { f.caller = 42; }, TypeError); |
| 290 assertThrows(function() { return f.arguments; }, TypeError); |
| 291 assertThrows(function() { f.arguments = 42; }, TypeError); |
| 292 |
| 293 // Shouldn't throw. Accessing the functions caller must throw if |
| 294 // the caller is strict and the callee isn't. A bound function is built-in, |
| 295 // but not considered strict. |
| 296 (function foo() { return foo.caller; }).bind()(); |
| OLD | NEW |