| var BUGNUMBER = 924688; |
| var summary = 'Computed Property Names'; |
| |
| print(BUGNUMBER + ": " + summary); |
| |
| // Function definitions. |
| function syntaxError (script) { |
| try { |
| Function(script); |
| } catch (e) { |
| if (e instanceof SyntaxError) { |
| return; |
| } |
| } |
| throw new Error('Expected syntax error: ' + script); |
| } |
| |
| |
| // Tests begin. |
| |
| assertThrowsInstanceOf(function() { var a = {[field1]: "a", [field2]: "b"}; }, ReferenceError); |
| |
| assertThrowsInstanceOf(function() { |
| field1 = 1; |
| var a = {[field1]: "a", [field2]: "b"}; |
| }, ReferenceError); |
| |
| var f1 = 1; |
| var f2 = 2; |
| var a = {[f1]: "a", [f2]: "b"}; |
| assertEq(a[1], "a"); |
| assertEq(a[2], "b"); |
| |
| var a = {[f1]: "a", f2: "b"}; |
| assertEq(a[1], "a"); |
| assertEq(a.f2, "b"); |
| |
| var a = {["f1"]: "a", [++f2]: "b"}; |
| assertEq(a.f1, "a"); |
| assertEq(a[3], "b"); |
| |
| var a = {["f1"]: "a", f2: "b"}; |
| assertEq(a.f1, "a"); |
| assertEq(a.f2, "b"); |
| |
| |
| var i = 0; |
| var a = { |
| ["foo" + ++i]: i, |
| ["foo" + ++i]: i, |
| ["foo" + ++i]: i |
| }; |
| assertEq(a.foo1, 1); |
| assertEq(a.foo2, 2); |
| assertEq(a.foo3, 3); |
| |
| var expr = "abc"; |
| syntaxError("({["); |
| syntaxError("({[expr"); |
| syntaxError("({[expr]"); |
| syntaxError("({[expr]})"); |
| syntaxError("({[expr] 0})"); |
| syntaxError("({[expr], 0})"); |
| syntaxError("[[expr]: 0]"); |
| syntaxError("({[expr]: name: 0})"); |
| syntaxError("({[1, 2]: 3})"); // because '1,2' is an Expression but not an AssignmentExpression |
| syntaxError("({[1;]: 1})"); // and not an ExpressionStatement |
| syntaxError("({[if (0) 0;]})"); // much less a Statement |
| syntaxError("function f() { {[x]: 1} }"); // that's not even an ObjectLiteral |
| syntaxError("function f() { [x]: 1 }"); // or that |
| syntaxError('a = {[f1@]: "a", [f2]: "b"}'); // unexpected symbol at end of AssignmentExpression |
| try { JSON.parse('{["a"]:4}'); } catch(e) { |
| if (!(e instanceof SyntaxError)) throw new Error('Expected syntax error'); |
| } |
| |
| // Property characteristics. |
| a = { ["b"] : 4 }; |
| b = Object.getOwnPropertyDescriptor(a, "b"); |
| assertEq(b.configurable, true); |
| assertEq(b.enumerable, true); |
| assertEq(b.writable, true); |
| assertEq(b.value, 4); |
| |
| // Setter and getter are not hit. |
| Object.defineProperty(Object.prototype, "x", { set: function (x) { throw "FAIL"; }, |
| get: function (x) { throw "FAIL"; } }); |
| var a = {["x"]: 0}; |
| assertEq(a.x, 0); |
| |
| a = {["x"]: 1, ["x"]: 2}; |
| assertEq(a.x, 2); |
| a = {x: 1, ["x"]: 2}; |
| assertEq(a.x, 2); |
| a = {["x"]: 1, x: 2}; |
| assertEq(a.x, 2); |
| |
| // Symbols |
| var unique_sym = Symbol("1"), registered_sym = Symbol.for("2"); |
| a = { [unique_sym] : 2, [registered_sym] : 3 }; |
| assertEq(a[unique_sym], 2); |
| assertEq(a[registered_sym], 3); |
| |
| // Same expression can be run several times to build objects with different property names. |
| a = []; |
| for (var i = 0; i < 3; i++) { |
| a[i] = {["foo" + i]: i}; |
| } |
| assertEq(a[0].foo0, 0); |
| assertEq(a[1].foo1, 1); |
| assertEq(a[2].foo2, 2); |
| |
| // Following are stored in object's elements rather than slots. |
| var i = 0; |
| a = { [++i] : i, |
| [++i] : i, |
| [++i] : i, |
| [++i] : i, |
| [++i] : i, |
| [++i] : i, |
| [++i] : i, |
| [++i] : i |
| } |
| for (var i = 1; i < 9; i++) |
| assertEq(a[i], i); |
| syntaxError("a.1"); |
| syntaxError("a.2"); |
| syntaxError("a.3"); |
| syntaxError("a.4"); |
| syntaxError("a.5"); |
| syntaxError("a.6"); |
| syntaxError("a.7"); |
| syntaxError("a.8"); |
| |
| // Adding a single large index. |
| var i = 0; |
| a = { [++i] : i, |
| [++i] : i, |
| [++i] : i, |
| [++i] : i, |
| [++i] : i, |
| [++i] : i, |
| [++i] : i, |
| [++i] : i, |
| [3000] : 2999 |
| } |
| for (var i = 1; i < 9; i++) |
| assertEq(a[i], i); |
| assertEq(a[3000], 2999); |
| |
| // Defining several properties using eval. |
| var code = "({"; |
| for (i = 0; i < 1000; i++) |
| code += "['foo' + " + i + "]: 'ok', " |
| code += "['bar']: 'ok'});"; |
| var obj = eval(code); |
| for (i = 0; i < 1000; i++) |
| assertEq(obj["foo" + i], "ok"); |
| assertEq(obj["bar"], "ok"); |
| |
| // Can yield in a computed property name which is in a generator. |
| function* g() { |
| var a = { [yield 1]: 2, [yield 2]: 3}; |
| return a; |
| } |
| |
| var it = g(); |
| var next = it.next(); |
| assertEq(next.done, false); |
| assertEq(next.value, 1); |
| next = it.next("hello"); |
| assertEq(next.done, false); |
| assertEq(next.value, 2); |
| next = it.next("world"); |
| assertEq(next.done, true); |
| assertEq(next.value.hello, 2); |
| assertEq(next.value.world, 3); |
| |
| // get and set. |
| expr = "abc"; |
| syntaxError("({get ["); |
| syntaxError("({get [expr()"); |
| syntaxError("({get [expr]()"); |
| syntaxError("({get [expr]()})"); |
| syntaxError("({get [expr] 0 ()})"); |
| syntaxError("({get [expr], 0(})"); |
| syntaxError("[get [expr]: 0()]"); |
| syntaxError("({get [expr](: name: 0})"); |
| syntaxError("({get [1, 2](): 3})"); |
| syntaxError("({get [1;](): 1})"); |
| syntaxError("({get [if (0) 0;](){}})"); |
| syntaxError("({set [(a)"); |
| syntaxError("({set [expr(a)"); |
| syntaxError("({set [expr](a){}"); |
| syntaxError("({set [expr]}(a)"); |
| syntaxError("({set [expr](a), 0})"); |
| syntaxError("[set [expr](a): 0]"); |
| syntaxError("({set [expr](a): name: 0})"); |
| syntaxError("({set [1, 2](a) {return 3;}})"); |
| syntaxError("({set [1;](a) {return 1}})"); |
| syntaxError("({set [if (0) 0;](a){}})"); |
| syntaxError("function f() { {get [x](): 1} }"); |
| syntaxError("function f() { get [x](): 1 }"); |
| syntaxError("function f() { {set [x](a): 1} }"); |
| syntaxError("function f() { set [x](a): 1 }"); |
| f1 = "abc"; |
| syntaxError('a = {get [f1@](){}, set [f1](a){}}'); // unexpected symbol at end of AssignmentExpression |
| syntaxError('a = {get@ [f1](){}, set [f1](a){}}'); // unexpected symbol after get |
| syntaxError('a = {get [f1](){}, set@ [f1](a){}}'); // unexpected symbol after set |
| |
| expr = "hey"; |
| a = {get [expr]() { return 3; }, set[expr](v) { throw 2; }}; |
| assertEq(a.hey, 3); |
| assertThrowsValue(() => { a.hey = 5; }, 2); |
| |
| // Symbols with duplicate get and set. |
| expr = Symbol("hey"); |
| a = {get [expr]() { return 3; }, set[expr](v) { throw 2; }, |
| set [expr] (w) { throw 4; }, get[expr](){return 5; }}; |
| assertEq(a[expr], 5); |
| assertThrowsValue(() => { a[expr] = 7; }, 4); |
| |
| // expressions with side effects are called in the right order |
| log = ""; |
| obj = { |
| "a": log += 'a', |
| get [log += 'b']() {}, |
| [log += 'c']: log += 'd', |
| set [log += 'e'](a) {} |
| }; |
| assertEq(log, "abcde"); |
| |
| // assignment expressions, objects and regex in computed names |
| obj = { |
| get [a = "hey"]() { return 1; }, |
| get [a = {b : 4}.b]() { return 2; }, |
| set [/x/.source](a) { throw 3; } |
| } |
| assertEq(obj.hey, 1); |
| assertEq(obj[4], 2); |
| assertThrowsValue(() => { obj.x = 7; }, 3); |
| |
| if (typeof reportCompare === 'function') |
| reportCompare(0, 0, "ok"); |