# JS Tip of the Day: A Function's Home Object

**URL:** <https://forum.kirupa.com/t/js-tip-of-the-day-a-functions-home-object/643187>\
**Category:** web dev\
**Created:** [June 5, 2020, 1:12pm UTC](https://forum.kirupa.com/t/js-tip-of-the-day-a-functions-home-object/643187 "2020-06-05T13:12:55Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![senocular](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/senocular/32/7217_2.png) [@senocular](https://forum.kirupa.com/u/senocular)\
**Post date:** [June 5, 2020, 1:12pm UTC](https://forum.kirupa.com/t/js-tip-of-the-day-a-functions-home-object/643187/1 "2020-06-05T13:12:55Z")

</div>

**A Function’s Home Object**  
Version: ES2015  
Level: Advanced

All JavaScript functions have a internal slot called `[[HomeObject]]`. This is used to store a function’s “home object” which is the object in which the function was originally defined. This doesn’t get set for all functions, though, only method-style functions defined in classes or object literals. All other functions have a `[[HomeObject]]` value of undefined.

```javascript
let obj = {
    method () {}
};
// obj.method.[[HomeObject]] = obj;

class Obj {
    method () {}
}
// Obj.prototype.method.[[HomeObject]] = Obj.prototype;

function func () {}
// func.[[HomeObject]] = undefined;

```

Home objects are used by `super` to know how to make super method calls. When a super method is called, the runtime looks at the `[[HomeObject]]` of the current function, gets the prototype of that object, then calls the super method from there. This ensures the method getting called is inherited and not from the current object or its immediate prototype.

```javascript
class Sup {
    method () {
        console.log('Sup method called');
    }
}

class Sub extends Sup {
    method () {
        console.log('Sub method called');
        super.method();
        // called as:
        // Object.getPrototypeOf(this.method.[[HomeObject]])
        // .method.call(this);
    }
}

```

```javascript
new Sub().method();
/* logs:
Sub method called
Sup method called
*/

```

For the most part, all of this works transparently and `super` method calls magically work as they should. However, the way they’re called through the home object could cause problems, especially if you’re trying to use methods relying on `super` in, for example, non-class-based mixins.

Consider what would happen if you created a class of only methods, each of which that you wanted to copy into another object or class prototype by direct copy. If any of those methods used `super`, you may not get the behavior you expected.

```javascript
// class containing methods to mix in
class SharedMethods {
    method () {
        console.log('Shared-to-be-Sub method called');
        super.method();
    }
}

// class hierarchy receiving the mixin
class Sup {
    method () {
        console.log('Sup method called');
    }
}
class Sub extends Sup {}

```

```javascript
Reflect.ownKeys(SharedMethods.prototype) // mix in
    .filter(key => key !== 'constructor')
    .forEach(key => {
        Object.defineProperty(
            Sub.prototype,
            key,
            Object.getOwnPropertyDescriptor(
                SharedMethods.prototype,
                key
            )
        )
    });

new Sub().method(); // Shared-to-be-Sub method called
// TypeError: method is not a function

```

While one might expect `super.method()` from the mixin - now part of `Sub.prototype` - to reach up and call into `Sup.prototype.method()`, this is not the case. In order to find `super.method()`, the called function uses its home object, a value created when it was originally defined and one that will not change when the function is reassigned by the mixin. The home object of that mixed in `method()` function, because it was originally created in the `SharedMethods` class, is `SharedMethods.prototype`. When `super.method()` is attempted from within it, it will always look for the “method” function in the prototype of `SharedMethods.prototype`, which here is `Object.prototype`. And since `method()` doesn’t exist there, an error is thrown.

There is no way for `super` to work in these kinds of mixins. Class-based mixins do work, however, because each mixin class get its own copy of the method, each with their own home object that can correctly target the appropriate superclass.

```javascript
function shared (Base) {
    return class extends Base {
        method () {
            console.log('shared-to-be-Sub method called');
            super.method(); // finds through Base
        }
    }
}

class Sup {
    method () {
        console.log('Sup method called');
    }
}

class Sub extends shared(Sup) {} // mix in

```

```javascript
new Sub().method();
/* logs:
shared-to-be-Sub method called
Sup method called
*/

```

More info:

- [[[HomeObject]] in ECMAScript spec](http://www.ecma-international.org/ecma-262/10.0/index.html#table-16)

* * *

More tips: [JavaScript Tips of the Day](http://forum.kirupa.com/t/javascript-tips-of-the-day/641803/1)
