eslint object-shorthand
labelled safe
Analysis Nemotron 3 Super
Flags non-shorthand object literal properties/methods where a shorter equivalent exists.
Fix: Replaces longhand property assignments with shorthand when key and variable name match ({x: x} → {x}), and replaces function expressions with method shorthand when the key is a simple identifier or computed expression matching a variable/function name ({m: function(){}} → {m()}, {[n]: function(){}} → {[n]()}).
12 hazards
- Rewriting {a: a} to {a} changes behavior if 'a' is not in scope, causing ReferenceError.
- Rewriting {b: function(){}} to {b()} alters the function's name property from 'b' to empty string, breaking reliance on func.name.
- Rewriting [c]: function(){} to [c](){} may fail if 'c' evaluates to a non-string/symbol key (e.g., number), though unlikely due to rule constraints.
- If the function expression contains 'use strict' directive, rewriting to method syntax may change strictness scope if surrounding context differs.
- Comments attached to the function expression (e.g., {b: /* comment */ function(){}}) are lost in the fix as they are not preserved.
- Rewriting getters/setters like {get x(){}} to shorthand is invalid syntax and never attempted by the fix, but if misapplied would break.
- If the object literal is used in a context relying on property order (e.g., for...in), the fix preserves order so no hazard, but reordering elsewhere could.
- In sloppy mode, if the property creates an implicit global via assignment, shorthand does not change this behavior, so no hazard.
- If the variable 'a' in {a: a} is declared with var and used before declaration, both forms reference the same hoisted variable, so no behavioral change.
- If the function expression is a generator (*), rewriting to *x(){} preserves generator nature, so no hazard.
- If the key is an escaped identifier (e.g., {\u0061: a}), the fix may produce invalid syntax if not handled correctly, though ESLint avoids this.
- If the object literal is nested within a with statement, property resolution changes could theoretically occur, but this is extremely rare and not specific to the fix.
Programs
| id | result | title | hazard |
|---|---|---|---|
| r1-p001 | fix ok | this binding: arrow vs function | Rewriting function shorthand changes `this` binding; extracting method as const loses original `this` context. |
| r1-p002 | fix ok | strict vs sloppy mode semantics | In strict mode, `this` in function shorthand is undefined when called standalone; in sloppy mode it coerces to global, changing outcome after extraction. |
| r1-p003 | fix ok prediction off | implicit global in sloppy mode | Assignment to undeclared variable creates global in sloppy mode; shorthand rewrite doesn’t affect this since RHS reference unchanged. |
| r1-p004 | fix ok | property order reliance | for...in iteration order matters; rule preserves definition order, but if manually reordered post-fix, behavior diverges. |
| r1-p005 | fix ok prediction off | computed key with non-string/symbol | [c]: function(){} rewritten to [c]{} fails if c evaluates to number (coerced to string key), though rule avoids non-simple keys. |
| r1-p006 | fix ok | generator function preservation | Generator function shorthand rewrite {g: function*(){}} → {g*()} preserves generator nature; next() yields correctly. |
| r1-p007 | silent | getter/setter invalid shorthand | Rule never attempts to rewrite getters/setters; misapplication would break syntax, but here we show they remain intact. |
| r1-p008 | fix ok | null/undefined distinction | Optional chaining on rewritten shorthand method preserves nullish short-circuit behavior identically to longhand. |
| r2-p001 | fix ok | ReferenceError due to out-of-scope variable | Rewriting {a: a} to {a} changes behavior if 'a' is not in scope, causing ReferenceError. |
| r2-p002 | fix ok | Var hoisting and redeclaration inside loop | var hoisting and re-declaration inside loops or after use |
| r2-p003 | fix ok | Name collision across scopes after shadowing | name collisions across scopes after a move (shadowing) |
| r2-p004 | fix ok prediction off | Var used before declaration - no behavioral change | If the variable 'a' in {a: a} is declared with var and used before declaration, both forms reference the same hoisted variable, so no behavioral change. |
| r2-p005 | silent prediction off | Class fields and private names interaction | class fields, static blocks, private names, super calls |
| r2-p006 | fix ok | Async/await ordering and generator yield position | async/await ordering, generators and yield position |
| r2-p007 | fix ok | Null/undefined distinction with optional chaining | null/undefined distinction, optional chaining short-circuit, nullish vs falsy |
| r2-p008 | fix ok | Arguments object, function.length, default parameters | arguments object, function.length, default parameters, rest parameters |
Sources
r1-p001 · this binding: arrow vs function
1const obj = {
2 m: function() { return this.val; }
3};
4obj.val = 42;
5console.log(obj.m());
6const fn = obj.m;
7try { console.log(fn()); } catch (e) { console.log(e.name + ': ' + e.message); }
--- orig.js 2026-10-22 14:23:31.295384620 -0400 +++ fixed.js 2026-10-22 14:23:34.529525338 -0400 @@ -1,5 +1,5 @@ const obj = { - m: function() { return this.val; } + m() { return this.val; } }; obj.val = 42; console.log(obj.m());
42 undefined
r1-p002 · strict vs sloppy mode semantics
1"use strict";
2const obj = {
3 m: function() { return this === undefined ? 'strict' : typeof this; }
4};
5obj.val = 1;
6console.log(obj.m());
7const fn = obj.m;
8console.log(fn());
--- orig.js 2026-10-22 14:23:31.296384664 -0400 +++ fixed.js 2026-10-22 14:23:34.519524903 -0400 @@ -1,6 +1,6 @@ "use strict"; const obj = { - m: function() { return this === undefined ? 'strict' : typeof this; } + m() { return this === undefined ? 'strict' : typeof this; } }; obj.val = 1; console.log(obj.m());
object strict
r1-p003 · implicit global in sloppy mode
1"use sloppy";
2(function() {
3 const obj = { p: p };
4 try { console.log(p); } catch (e) { console.log(e.name); }
5})();
--- orig.js 2026-10-22 14:23:31.296384664 -0400 +++ fixed.js 2026-10-22 14:23:34.558526601 -0400 @@ -1,5 +1,5 @@ "use sloppy"; (function() { - const obj = { p: p }; + const obj = { p }; try { console.log(p); } catch (e) { console.log(e.name); } })();
r1-p004 · property order reliance
1const obj = { a: a, b: b };
2let a = 1, b = 2;
3let s = '';
4for (const k in obj) s += k + obj[k];
5console.log(s);
--- orig.js 2026-10-22 14:23:31.297384707 -0400 +++ fixed.js 2026-10-22 14:23:34.506524337 -0400 @@ -1,4 +1,4 @@ -const obj = { a: a, b: b }; +const obj = { a, b }; let a = 1, b = 2; let s = ''; for (const k in obj) s += k + obj[k];
r1-p005 · computed key with non-string/symbol
1const c = 42;
2const obj = { [c]: function() { return 'num'; } };
3console.log(obj['42'](), Object.keys(obj)[0]);
--- orig.js 2026-10-22 14:23:31.298384751 -0400 +++ fixed.js 2026-10-22 14:23:34.510524512 -0400 @@ -1,3 +1,3 @@ const c = 42; -const obj = { [c]: function() { return 'num'; } }; +const obj = { [c]() { return 'num'; } }; console.log(obj['42'](), Object.keys(obj)[0]);
num 42
r1-p006 · generator function preservation
1const obj = {
2 g: function*() {
3 yield 1;
4 yield 2;
5 }
6};
7const it = obj.g();
8console.log(it.next().value, it.next().value, it.next().done);
--- orig.js 2026-10-22 14:23:31.298384751 -0400 +++ fixed.js 2026-10-22 14:23:34.502524163 -0400 @@ -1,5 +1,5 @@ const obj = { - g: function*() { + *g() { yield 1; yield 2; }
1 2 true
r1-p007 · getter/setter invalid shorthand
1const obj = {
2 get x() { return this._x || 0; },
3 set x(v) { this._x = v; }
4};
5obj.x = 5;
6console.log(obj.x);
5
r1-p008 · null/undefined distinction
1let obj = null;
2console.log(obj?.m?.());
3obj = { m: function() { return 'hit'; } };
4console.log(obj?.m?.());
5obj = { m: undefined };
6console.log(obj?.m?.());
--- orig.js 2026-10-22 14:23:35.559570181 -0400 +++ fixed.js 2026-10-22 14:23:37.625660161 -0400 @@ -1,6 +1,6 @@ let obj = null; console.log(obj?.m?.()); -obj = { m: function() { return 'hit'; } }; +obj = { m() { return 'hit'; } }; console.log(obj?.m?.()); obj = { m: undefined }; console.log(obj?.m?.());
undefined hit undefined
r2-p001 · ReferenceError due to out-of-scope variable
1function f() {
2 try {
3 return {a: a}; // triggers rule
4 } catch (e) {
5 return e.name + ': ' + e.message;
6 }
7}
8console.log(f());
--- orig.js 2026-10-22 14:23:45.208990820 -0400 +++ fixed.js 2026-10-22 14:23:47.863106694 -0400 @@ -1,6 +1,6 @@ function f() { try { - return {a: a}; // triggers rule + return {a}; // triggers rule } catch (e) { return e.name + ': ' + e.message; }
ReferenceError: a is not defined
r2-p002 · Var hoisting and redeclaration inside loop
1let result = '';
2for (let i = 0; i < 2; i++) {
3 var x = i;
4 let obj = {x: x}; // triggers rule
5 result += obj.x;
6}
7console.log(result);
8// After first iteration: x=0, obj={x:0} -> result='0'
9// After second: x=1 (same var), obj={x:1} -> result='01'
--- orig.js 2026-10-22 14:23:45.209990864 -0400 +++ fixed.js 2026-10-22 14:23:48.965154829 -0400 @@ -1,7 +1,7 @@ let result = ''; for (let i = 0; i < 2; i++) { var x = i; - let obj = {x: x}; // triggers rule + let obj = {x}; // triggers rule result += obj.x; } console.log(result);
01
r2-p003 · Name collision across scopes after shadowing
1let a = 1;
2{
3 let a = 2;
4 let o = {a: a}; // triggers rule, inner a=2
5 console.log(o.a); // prints 2
6}
7console.log(a); // prints 1 (outer)
--- orig.js 2026-10-22 14:23:45.210990907 -0400 +++ fixed.js 2026-10-22 14:23:48.979155440 -0400 @@ -1,7 +1,7 @@ let a = 1; { let a = 2; - let o = {a: a}; // triggers rule, inner a=2 + let o = {a}; // triggers rule, inner a=2 console.log(o.a); // prints 2 } console.log(a); // prints 1 (outer)
2 1
r2-p004 · Var used before declaration - no behavioral change
1console.log(typeof a); // 'undefined'
2var a = 5;
3let o = {a: a}; // rule would trigger but no semantic change
4console.log(o.a); // 5
--- orig.js 2026-10-22 14:23:45.211990951 -0400 +++ fixed.js 2026-10-22 14:23:47.345084073 -0400 @@ -1,4 +1,4 @@ console.log(typeof a); // 'undefined' var a = 5; -let o = {a: a}; // rule would trigger but no semantic change +let o = {a}; // rule would trigger but no semantic change console.log(o.a); // 5
undefined 5
r2-p005 · Class fields and private names interaction
1class Base {
2 constructor() {
3 this.pub = 1;
4 }
5}
6class Derived extends Base {
7 #priv = 2;
8 static staticVal = 3;
9 get obj() {
10 return {
11 pub: this.pub, // triggers rule
12 priv: this.#priv,
13 static: Derived.staticVal
14 };
15 }
16}
17const d = new Derived();
18console.log(d.obj.pub, d.obj.priv, d.obj.static);
1 2 3
r2-p006 · Async/await ordering and generator yield position
1async function* gen() {
2 yield 1;
3 let x = await Promise.resolve(2);
4 yield {x: x}; // triggers rule
5 yield 3;
6}
7gen().next().value.then(v1 => {
8 gen().next().value.then(v2 => {
9 console.log(v1.value, v2.value); // 1, {x:2}
10 });
11});
--- orig.js 2026-10-22 14:23:45.212990995 -0400 +++ fixed.js 2026-10-22 14:23:48.994156096 -0400 @@ -1,7 +1,7 @@ async function* gen() { yield 1; let x = await Promise.resolve(2); - yield {x: x}; // triggers rule + yield {x}; // triggers rule yield 3; } gen().next().value.then(v1 => {
r2-p007 · Null/undefined distinction with optional chaining
1let obj = null;
2let a = undefined;
3try {
4 console.log({a: a}.a?.()); // triggers rule, prints undefined
5} catch (e) {
6 console.log(e.name);
7}
8try {
9 console.log({a: a}.a()); // would throw if not guarded
10} catch (e) {
11 console.log(e.name);
12}
--- orig.js 2026-10-22 14:23:47.763102327 -0400 +++ fixed.js 2026-10-22 14:23:51.535267137 -0400 @@ -1,12 +1,12 @@ let obj = null; let a = undefined; try { - console.log({a: a}.a?.()); // triggers rule, prints undefined + console.log({a}.a?.()); // triggers rule, prints undefined } catch (e) { console.log(e.name); } try { - console.log({a: a}.a()); // would throw if not guarded + console.log({a}.a()); // would throw if not guarded } catch (e) { console.log(e.name); }
undefined TypeError
r2-p008 · Arguments object, function.length, default parameters
1function f(a, b = 1) {
2 let o = {a: a}; // triggers rule
3 console.log(o.a === arguments[0], f.length);
4 return o;
5}
6f(5); // logs: true 1
--- orig.js 2026-10-22 14:23:48.987155790 -0400 +++ fixed.js 2026-10-22 14:23:51.578269017 -0400 @@ -1,5 +1,5 @@ function f(a, b = 1) { - let o = {a: a}; // triggers rule + let o = {a}; // triggers rule console.log(o.a === arguments[0], f.length); return o; }
true 1