eslint no-extra-bind
labelled safe
Analysis Nemotron 3 Super
Flags unnecessary .bind() calls where the function does not reference 'this' and no arguments are pre-bound.
Fix: Removes the trailing .bind(callExpr) when the function body contains no 'this' references and no arguments are bound beyond the thisArg.
8 hazards
- Removing .bind() changes the function's identity, breaking equality checks (e.g., ===) against the original bound function.
- If the bound function is used as a constructor, removing .bind() alters instance creation behavior since bound functions cannot be constructors.
- The rewrite may expose the function to accidental 'this' binding from surrounding context if used as a method.
- If the function relies on lexical scoping via bind() to capture outer variables (unrelated to this), removal breaks closure semantics—though rare, this is possible if bind() was misused for closure-like behavior.
- Comments attached to the .bind() call (e.g., // ignore this) are discarded during autofix, potentially removing developer intent.
- In strict mode, removing .bind() may alter 'this' value from undefined to the global object if the function is called indirectly.
- If the bound function is passed to higher-order functions that depend on its specific length or name (e.g., for debugging), removal may break those dependencies.
- When bind() is chained (e.g., .bind().bind()), removing only the outer bind() may leave an inner unnecessary bind(), requiring multiple passes; the autofix does not handle nested cases.
Programs
| id | result | title | hazard |
|---|---|---|---|
| r1-p001 | silent prediction off | Comments attached to .bind() are lost | 1. Comments attached to the .bind() call are discarded during autofix |
| r1-p002 | silent prediction off | Class field captures broken bind | 2. Class fields, static blocks, private names, super calls |
| r1-p003 | silent prediction off | Method context hijack after fix | 3. Rewrite exposes function to accidental this binding from surrounding context |
| r1-p004 | silent prediction off | Arguments object and length exposed | 4. Arguments object, function.length, default parameters, rest parameters |
| r1-p005 | fix ok | Var hoisting interferes with rebind | 5. Var hoisting and re-declaration inside loops or after use |
| r1-p006 | silent prediction off | Coercion via + vs template literal | 6. Numeric/string coercion: + vs template literal, objects with toString/valueOf, Symbol, BigInt |
| r1-p007 | silent prediction off | Getter side effect broken by fix | 7. Getters, setters and Object.defineProperty side effects |
| r1-p008 | invalid | ASI hazard with leading paren | 8. ASI and semicolon-less code, leading ( or [ on the next line |
| r2-p001 | invalid | Control Flow Hazard: break/continue/finally | label/break/continue control flow, finally blocks, early returns in nested blocks |
| r2-p002 | silent prediction off | Strict Mode Indirect Call 'this' Shift | In strict mode, removing .bind() may alter 'this' value from undefined to the global object if the function is called indirectly. |
| r2-p003 | fix ok | Bind Comment Discarded During Autofix | Comments attached to the .bind() call (e.g., // ignore this) are discarded during autofix, potentially removing developer intent. |
| r2-p004 | silent | ASI Hazard: Leading Paren After Semicolon-less Line | ASI and semicolon-less code, leading ( or [ on the next line |
| r2-p005 | silent prediction off | Constructor Use: Bound Function Cannot Construct | If the bound function is used as a constructor, removing .bind() alters instance creation behavior since bound functions cannot be constructors. |
| r2-p006 | invalid | RegExp lastIndex and Unicode Flag Interaction | regular expressions: escapes, unicode flag, lastIndex with the g flag |
| r2-p007 | fix ok | Class Fields and Private Names Capture Broken by Fix | class fields, static blocks, private names, super calls |
| r2-p008 | fix ok | Order of Evaluation: Side Effects Duplicated or Lost | order of evaluation when expressions are merged, duplicated or deleted (side effects run twice or never) |
Sources
r1-p001 · Comments attached to .bind() are lost
1let f = function () {
2 console.log(this === undefined ? 'strict' : this);
3}.bind(null) /* preserve this comment */;
4f();
<ref *1> Object [global] {
global: [Circular *1],
clearImmediate: [Function: clearImmediate],
setImmediate: [Function: setImmediate] {
[Symbol(nodejs.util.promisify.custom)]: [Getter]
},
clearInterval: [Function: clearInterval],
clearTimeout: [Function: clearTimeout],
setInterval: [Function: setInterval],
setTimeout: [Function: setTimeout] {
[Symbol(nodejs.util.promisify.custom)]: [Getter]
},
queueMicrotask: [Function: queueMicrotask],
structuredClone: [Function: structuredClone],
atob: [Getter/Setter],
btoa: [Getter/Setter],
performance: [Getter/Setter],
fetch: [Function: fetch],
crypto: [Getter]
}r1-p002 · Class field captures broken bind
1class C {
2 prop = function () {
3 return this.x;
4 }.bind({x: 1});
5}
6const c = new C();
7console.log(c.prop());
1
r1-p003 · Method context hijack after fix
1const obj = {
2 m: function () {
3 return this.value;
4 }.bind({value: 42})
5};
6console.log(obj.m());
7console.log(obj.m.call({value: 99}));
42 42
r1-p004 · Arguments object and length exposed
1const f = function (a, b = 1, ...rest) {
2 console.log(arguments.length, this === undefined ? 'und' : 'def', f.length);
3}.bind(null, 10);
4f(20, 30);
3 def 0
r1-p005 · Var hoisting interferes with rebind
1for (var i = 0; i < 2; i++) {
2 var g = function () {
3 return i;
4 }.bind(null);
5}
6console.log(g());
--- orig.js 2026-10-22 14:16:22.999714841 -0400 +++ fixed.js 2026-10-22 14:16:25.267785352 -0400 @@ -1,6 +1,6 @@ for (var i = 0; i < 2; i++) { var g = function () { return i; - }.bind(null); + }; } console.log(g());
2
r1-p006 · Coercion via + vs template literal
1const obj = {
2 toString() { return 'obj'; },
3 valueOf() { return 42; }
4};
5const s = function () {
6 return this;
7}.bind(obj);
8console.log(s() + '');
9console.log(`${s()}`);
42 obj
r1-p007 · Getter side effect broken by fix
1const obj = {};
2Object.defineProperty(obj, 'prop', {
3 get() {
4 this.accessed = true;
5 return 42;
6 }
7});
8const p = function () {
9 return this.prop;
10}.bind(obj);
11p();
12console.log(obj.accessed ? 'yes' : 'no');
yes
r1-p008 · ASI hazard with leading paren (generated program does not parse: /home/sun/dev/diaghunt/runs/2026-10-22T18-16-1)
1let x = function () { return 1 },
2(y = function () { return 2 })
3console.log(x(), y())
r2-p001 · Control Flow Hazard: break/continue/finally (generated program does not parse: /home/sun/dev/diaghunt/runs/2026-10-22T18-16-1)
1LOOP: {
2 try {
3 console.log((function () {
4 for (let i = 0; i < 3; i++) {
5 if (i === 1) continue LOOP;
6 if (i === 2) return;
7 }
8 console.log('reached');
9 }).bind(null));
10 throw new Error('unreachable');
11 } catch (e) {
12 console.log(e.message);
13 } finally {
14 console.log('finally executed');
15 }
16}
r2-p002 · Strict Mode Indirect Call 'this' Shift
1"use strict";
2const f = (function () { return typeof this; }).bind(null);
3const g = f;
4console.log(g());
object
r2-p003 · Bind Comment Discarded During Autofix
1const log = (function () {
2 console.log('no this used');
3}).bind(undefined); // preserve comment
4console.log(typeof log);
--- orig.js 2026-10-22 14:16:37.782179809 -0400 +++ fixed.js 2026-10-22 14:16:40.654271608 -0400 @@ -1,4 +1,4 @@ const log = (function () { console.log('no this used'); -}).bind(undefined); // preserve comment +}); // preserve comment console.log(typeof log);
function
r2-p004 · ASI Hazard: Leading Paren After Semicolon-less Line
1let x = 1
2(function () {
3 console.log('called');
4}).bind(null)
5[x] = [x + 1]
6console.log(x)
r2-p005 · Constructor Use: Bound Function Cannot Construct
1function C() { this.value = 'bound'; }
2const BoundC = C.bind({});
3try {
4 new BoundC();
5 console.log('constructed');
6} catch (e) {
7 console.log(e.name + ': ' + e.message);
8}
9console.log(typeof BoundC.prototype)
constructed undefined
r2-p006 · RegExp lastIndex and Unicode Flag Interaction (generated program does not parse: /home/sun/dev/diaghunt/runs/2026-10-22T18-16-1)
1const regex = /\\u{1f600}/gu;
2const test = (function () {
3 return regex.lastIndex;
4}).bind(null);
5regex.test('😀');
6console.log(test());
r2-p007 · Class Fields and Private Names Capture Broken by Fix
1class Base {
2 #x = 42;
3 getX() { return this.#x; }
4}
5class Derived extends Base {
6 getXBound = (() => this.getX()).bind(this);
7}
8const d = new Derived();
9console.log(d.getXBound());
--- orig.js 2026-10-22 14:16:37.827181243 -0400 +++ fixed.js 2026-10-22 14:16:41.193288886 -0400 @@ -3,7 +3,7 @@ getX() { return this.#x; } } class Derived extends Base { - getXBound = (() => this.getX()).bind(this); + getXBound = (() => this.getX()); } const d = new Derived(); console.log(d.getXBound());
42
r2-p008 · Order of Evaluation: Side Effects Duplicated or Lost
1let counter = 0;
2const inc = (function () {
3 return ++counter;
4}).bind(null);
5console.log(inc() + inc());
--- orig.js 2026-10-22 14:16:37.830181338 -0400 +++ fixed.js 2026-10-22 14:16:41.892311318 -0400 @@ -1,5 +1,5 @@ let counter = 0; const inc = (function () { return ++counter; -}).bind(null); +}); console.log(inc() + inc());
3