1 // Copyright 2010 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 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. 27 28 // Tests the Function.prototype.bind (ES 15.3.4.5) method. 29 30 // Simple tests. 31 function foo(x, y, z) { 32 return [this, arguments.length, x]; 33 } 34 35 assertEquals(3, foo.length); 36 37 var f = foo.bind(foo); 38 assertEquals([foo, 3, 1], f(1, 2, 3)); 39 assertEquals(3, f.length); 40 41 f = foo.bind(foo, 1); 42 assertEquals([foo, 3, 1], f(2, 3)); 43 assertEquals(2, f.length); 44 45 f = foo.bind(foo, 1, 2); 46 assertEquals([foo, 3, 1], f(3)); 47 assertEquals(1, f.length); 48 49 f = foo.bind(foo, 1, 2, 3); 50 assertEquals([foo, 3, 1], f()); 51 assertEquals(0, f.length); 52 53 // Test that length works correctly even if more than the actual number 54 // of arguments are given when binding. 55 f = foo.bind(foo, 1, 2, 3, 4, 5, 6, 7, 8, 9); 56 assertEquals([foo, 9, 1], f()); 57 assertEquals(0, f.length); 58 59 // Use a different bound object. 60 var obj = {x: 42, y: 43}; 61 // Values that would normally be in "this" when calling f_bound_this. 62 var x = 42; 63 var y = 44; 64 65 function f_bound_this(z) { 66 return z + this.y - this.x; 67 } 68 69 assertEquals(3, f_bound_this(1)) 70 f = f_bound_this.bind(obj); 71 assertEquals(2, f(1)); 72 assertEquals(1, f.length); 73 74 f = f_bound_this.bind(obj, 2); 75 assertEquals(3, f()); 76 assertEquals(0, f.length); 77 78 // Test chained binds. 79 80 // When only giving the thisArg, any number of binds should have 81 // the same effect. 82 f = foo.bind(foo); 83 assertEquals([foo, 3, 1], f(1, 2, 3)); 84 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)); 88 assertEquals(3, f.length); 89 90 // Giving bound parameters should work at any place in the chain. 91 f = foo.bind(foo, 1).bind(not_foo).bind(not_foo).bind(not_foo); 92 assertEquals([foo, 3, 1], f(2, 3)); 93 assertEquals(2, f.length); 94 95 f = foo.bind(foo).bind(not_foo, 1).bind(not_foo).bind(not_foo); 96 assertEquals([foo, 3, 1], f(2, 3)); 97 assertEquals(2, f.length); 98 99 f = foo.bind(foo).bind(not_foo).bind(not_foo,1 ).bind(not_foo); 100 assertEquals([foo, 3, 1], f(2, 3)); 101 assertEquals(2, f.length); 102 103 f = foo.bind(foo).bind(not_foo).bind(not_foo).bind(not_foo, 1); 104 assertEquals([foo, 3, 1], f(2, 3)); 105 assertEquals(2, f.length); 106 107 // Several parameters can be given, and given in different bind invocations. 108 f = foo.bind(foo, 1, 2).bind(not_foo).bind(not_foo).bind(not_foo); 109 assertEquals([foo, 3, 1], f(3)); 110 assertEquals(1, f.length); 111 112 f = foo.bind(foo).bind(not_foo, 1, 2).bind(not_foo).bind(not_foo); 113 assertEquals([foo, 3, 1], f(1)); 114 assertEquals(1, f.length); 115 116 f = foo.bind(foo).bind(not_foo, 1, 2).bind(not_foo).bind(not_foo); 117 assertEquals([foo, 3, 1], f(3)); 118 assertEquals(1, f.length); 119 120 f = foo.bind(foo).bind(not_foo).bind(not_foo, 1, 2).bind(not_foo); 121 assertEquals([foo, 3, 1], f(1)); 122 assertEquals(1, f.length); 123 124 f = foo.bind(foo).bind(not_foo).bind(not_foo).bind(not_foo, 1, 2); 125 assertEquals([foo, 3, 1], f(3)); 126 assertEquals(1, f.length); 127 128 f = foo.bind(foo, 1).bind(not_foo, 2).bind(not_foo).bind(not_foo); 129 assertEquals([foo, 3, 1], f(3)); 130 assertEquals(1, f.length); 131 132 f = foo.bind(foo, 1).bind(not_foo).bind(not_foo, 2).bind(not_foo); 133 assertEquals([foo, 3, 1], f(3)); 134 assertEquals(1, f.length); 135 136 f = foo.bind(foo, 1).bind(not_foo).bind(not_foo).bind(not_foo, 2); 137 assertEquals([foo, 3, 1], f(3)); 138 assertEquals(1, f.length); 139 140 f = foo.bind(foo).bind(not_foo, 1).bind(not_foo).bind(not_foo, 2); 141 assertEquals([foo, 3, 1], f(3)); 142 assertEquals(1, f.length); 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 175 // Test constructor calls. 176 177 function bar(x, y, z) { 178 this.x = x; 179 this.y = y; 180 this.z = z; 181 } 182 183 f = bar.bind(bar); 184 var obj2 = new f(1,2,3); 185 assertEquals(1, obj2.x); 186 assertEquals(2, obj2.y); 187 assertEquals(3, obj2.z); 188 189 f = bar.bind(bar, 1); 190 obj2 = new f(2,3); 191 assertEquals(1, obj2.x); 192 assertEquals(2, obj2.y); 193 assertEquals(3, obj2.z); 194 195 f = bar.bind(bar, 1, 2); 196 obj2 = new f(3); 197 assertEquals(1, obj2.x); 198 assertEquals(2, obj2.y); 199 assertEquals(3, obj2.z); 200 201 f = bar.bind(bar, 1, 2, 3); 202 obj2 = new f(); 203 assertEquals(1, obj2.x); 204 assertEquals(2, obj2.y); 205 assertEquals(3, obj2.z); 206 207 208 // Test bind chains when used as a constructor. 209 f = bar.bind(bar, 1).bind(bar, 2).bind(bar, 3); 210 obj2 = new f(); 211 assertEquals(1, obj2.x); 212 assertEquals(2, obj2.y); 213 assertEquals(3, obj2.z); 214 215 // Test obj2 is instanceof both bar and f. 216 assertTrue(obj2 instanceof bar); 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()(); 297